feat: 拖拽上传、图片缩放预览及新功能脚手架
- EcommercePage/WorkbenchPage 增加页面级拖拽文件上传支持 - 上传图片悬停缩放预览效果 - Workbench 参考素材增加图片/视频缩放预览 - CanvasPage 连接菜单位置微调 (-40) - script-tokens-v5 文本溢出省略号修复 - 新增: CookieConsentBanner, CompliancePage, 电商面板组件, generation store/hooks/service
This commit is contained in:
@@ -251,6 +251,8 @@ function WorkbenchPage({
|
||||
const [toolbarMenuId, setToolbarMenuId] = useState<ToolbarMenuId>(null);
|
||||
const [referenceItems, setReferenceItems] = useState<ReferenceItem[]>([]);
|
||||
const [referencePreviewOpen, setReferencePreviewOpen] = useState(false);
|
||||
const [isComposerDragging, setIsComposerDragging] = useState(false);
|
||||
const composerDragCounterRef = useRef(0);
|
||||
const [messagePreviewAttachment, setMessagePreviewAttachment] = useState<ChatAttachment | null>(null);
|
||||
const [selectedPromptCase, setSelectedPromptCase] = useState<PromptCaseViewModel | null>(null);
|
||||
const [serverPromptCases, setServerPromptCases] = useState<PromptCaseViewModel[]>([]);
|
||||
@@ -1493,9 +1495,22 @@ function WorkbenchPage({
|
||||
setReferenceItems(nextItems);
|
||||
};
|
||||
|
||||
const handleReferenceUpload = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const files = Array.from(event.target.files || []);
|
||||
event.target.value = "";
|
||||
const handleReferenceUploadClick = () => {
|
||||
if (referenceItems.length > 0) {
|
||||
setToolbarMenuId(null);
|
||||
setReferencePreviewOpen((current) => !current);
|
||||
return;
|
||||
}
|
||||
referenceInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleReferenceAddMore = () => {
|
||||
setToolbarMenuId(null);
|
||||
setReferencePreviewOpen(true);
|
||||
referenceInputRef.current?.click();
|
||||
};
|
||||
|
||||
const processReferenceFiles = async (files: File[]) => {
|
||||
if (files.length === 0) return;
|
||||
|
||||
const existingFingerprints = new Set(
|
||||
@@ -1582,20 +1597,46 @@ function WorkbenchPage({
|
||||
window.requestAnimationFrame(() => textareaRef.current?.focus());
|
||||
};
|
||||
|
||||
const handleReferenceUploadClick = () => {
|
||||
if (referenceItems.length > 0) {
|
||||
setToolbarMenuId(null);
|
||||
setReferencePreviewOpen((current) => !current);
|
||||
return;
|
||||
}
|
||||
referenceInputRef.current?.click();
|
||||
const handleReferenceUpload = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const files = Array.from(event.target.files || []);
|
||||
event.target.value = "";
|
||||
await processReferenceFiles(files);
|
||||
};
|
||||
|
||||
const handleReferenceAddMore = () => {
|
||||
setToolbarMenuId(null);
|
||||
setReferencePreviewOpen(true);
|
||||
referenceInputRef.current?.click();
|
||||
};
|
||||
const handleComposerDragEnter = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
composerDragCounterRef.current += 1;
|
||||
if (composerDragCounterRef.current === 1) {
|
||||
setIsComposerDragging(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleComposerDragLeave = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
composerDragCounterRef.current -= 1;
|
||||
if (composerDragCounterRef.current <= 0) {
|
||||
composerDragCounterRef.current = 0;
|
||||
setIsComposerDragging(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleComposerDragOver = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}, []);
|
||||
|
||||
const handleComposerDrop = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
composerDragCounterRef.current = 0;
|
||||
setIsComposerDragging(false);
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
if (files.length > 0) {
|
||||
void processReferenceFiles(files);
|
||||
}
|
||||
}, [activeMode]);
|
||||
|
||||
const insertPromptMention = (token: string) => {
|
||||
const rawBefore = inputValue.slice(0, cursorIndex);
|
||||
@@ -2595,6 +2636,11 @@ function WorkbenchPage({
|
||||
>
|
||||
<ReferencePreview item={item} label={getReferenceKindLabel(item.kind)} />
|
||||
</button>
|
||||
{(item.kind === "image" || item.kind === "video") && item.previewUrl ? (
|
||||
<span className="wb-composer__ref-zoom" aria-hidden="true">
|
||||
{item.kind === "video" ? <video src={item.previewUrl} muted playsInline /> : <img src={item.previewUrl} alt="" />}
|
||||
</span>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
className="wb-composer__ref-remove"
|
||||
@@ -2852,7 +2898,14 @@ function WorkbenchPage({
|
||||
<h1 className="wb-home__title">今天想生成什么?</h1>
|
||||
</div>
|
||||
|
||||
<div className="wb-home__composer" ref={toolbarRef}>
|
||||
<div
|
||||
className={`wb-home__composer${isComposerDragging ? " wb-composer--drag-active" : ""}`}
|
||||
ref={toolbarRef}
|
||||
onDragEnter={handleComposerDragEnter}
|
||||
onDragLeave={handleComposerDragLeave}
|
||||
onDragOver={handleComposerDragOver}
|
||||
onDrop={handleComposerDrop}
|
||||
>
|
||||
<div className="wb-composer__content">
|
||||
<div className="wb-composer__input-row">
|
||||
{renderComposerReferences(false)}
|
||||
@@ -3027,7 +3080,14 @@ function WorkbenchPage({
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={`wb-composer${composerHidden ? " is-hidden" : ""}`} ref={toolbarRef}>
|
||||
<section
|
||||
className={`wb-composer${composerHidden ? " is-hidden" : ""}${isComposerDragging ? " wb-composer--drag-active" : ""}`}
|
||||
ref={toolbarRef}
|
||||
onDragEnter={handleComposerDragEnter}
|
||||
onDragLeave={handleComposerDragLeave}
|
||||
onDragOver={handleComposerDragOver}
|
||||
onDrop={handleComposerDrop}
|
||||
>
|
||||
<div className="wb-composer__content">
|
||||
<div className="wb-composer__input-row">
|
||||
{renderComposerReferences(false)}
|
||||
|
||||
Reference in New Issue
Block a user