feat: 新增引导式新手指引 (OnboardingTour) 组件,全站页面接入

This commit is contained in:
OmniAI Developer
2026-06-08 21:30:48 +08:00
parent 1e756808c1
commit 6ed65ca3ee
24 changed files with 1414 additions and 164 deletions
@@ -6,7 +6,7 @@ import {
PictureOutlined,
UploadOutlined,
} from "@ant-design/icons";
import { useEffect, useMemo, useRef, useState, type ChangeEvent } from "react";
import { useEffect, useMemo, useRef, useState, type ChangeEvent, type DragEvent } from "react";
import { aiGenerationClient } from "../../api/aiGenerationClient";
import { communityClient } from "../../api/communityClient";
import WorkspacePageShell from "../../components/WorkspacePageShell";
@@ -73,6 +73,29 @@ export default function CommunityCaseAddPage({ session, onOpenLogin, onOpenRevie
const allowed = canManageCommunityCases(session);
const imageInputRef = useRef<HTMLInputElement | null>(null);
const workflowInputRef = useRef<HTMLInputElement | null>(null);
const [isImageDragging, setIsImageDragging] = useState(false);
const [isWorkflowDragging, setIsWorkflowDragging] = useState(false);
const handleImageDragOver = (e: DragEvent) => { e.preventDefault(); if (e.dataTransfer.types.includes("Files")) setIsImageDragging(true); };
const handleImageDragLeave = (e: DragEvent) => { e.preventDefault(); if (!e.currentTarget.contains(e.relatedTarget as Node)) setIsImageDragging(false); };
const handleImageDrop = (e: DragEvent) => {
e.preventDefault();
setIsImageDragging(false);
if (e.dataTransfer.files.length) {
void handleImageChange({ target: { files: e.dataTransfer.files } } as ChangeEvent<HTMLInputElement>);
}
};
const handleWorkflowDragOver = (e: DragEvent) => { e.preventDefault(); if (e.dataTransfer.types.includes("Files")) setIsWorkflowDragging(true); };
const handleWorkflowDragLeave = (e: DragEvent) => { e.preventDefault(); if (!e.currentTarget.contains(e.relatedTarget as Node)) setIsWorkflowDragging(false); };
const handleWorkflowDrop = (e: DragEvent) => {
e.preventDefault();
setIsWorkflowDragging(false);
if (e.dataTransfer.files.length) {
void handleWorkflowChange({ target: { files: e.dataTransfer.files } } as ChangeEvent<HTMLInputElement>);
}
};
const [target, setTarget] = useState<CaseTarget>("generation");
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
@@ -331,7 +354,14 @@ export default function CommunityCaseAddPage({ session, onOpenLogin, onOpenRevie
</label>
<div className="community-case-add-upload-row">
<input ref={imageInputRef} type="file" accept="image/*" hidden onChange={handleImageChange} />
<button type="button" onClick={() => imageInputRef.current?.click()}>
<button
type="button"
className={isImageDragging ? "is-dragging" : ""}
onClick={() => imageInputRef.current?.click()}
onDragOver={handleImageDragOver}
onDragLeave={handleImageDragLeave}
onDrop={handleImageDrop}
>
<UploadOutlined />
</button>
@@ -345,7 +375,14 @@ export default function CommunityCaseAddPage({ session, onOpenLogin, onOpenRevie
<>
<div className="community-case-add-upload-row">
<input ref={workflowInputRef} type="file" accept="application/json,.json" hidden onChange={handleWorkflowChange} />
<button type="button" onClick={() => workflowInputRef.current?.click()}>
<button
type="button"
className={isWorkflowDragging ? "is-dragging" : ""}
onClick={() => workflowInputRef.current?.click()}
onDragOver={handleWorkflowDragOver}
onDragLeave={handleWorkflowDragLeave}
onDrop={handleWorkflowDrop}
>
<UploadOutlined />
JSON
</button>