refactor: remove "use client" directive from multiple files and update project structure to align with Vite and React Router

This commit is contained in:
HouYunFei
2026-06-26 17:24:48 +08:00
parent e635ec6908
commit 443afab7bd
88 changed files with 94 additions and 230 deletions
+4 -3
View File
@@ -32,15 +32,16 @@
## 前端规范 ## 前端规范
- 前端使用 Next.js App Router、React、TypeScript、Ant Design、Tailwind、Zustand。 - 前端使用 Vite、React、React Router、TypeScript、Ant Design、Tailwind、Zustand。
- 编写 Ant Design 相关代码时,参考 https://ant.design/llms-full.txt 理解组件 API、示例和设计规范,并优先结合项目当前 antd 版本与既有写法。 - 编写 Ant Design 相关代码时,参考 https://ant.design/llms-full.txt 理解组件 API、示例和设计规范,并优先结合项目当前 antd 版本与既有写法。
- API 请求统一放在 `web/src/services/api/` - API 请求统一放在 `web/src/services/api/`
- 全局或跨页面状态优先放在 `web/src/stores/` - 全局或跨页面状态优先放在 `web/src/stores/`
- 已经放在全局 store 或全局 hook 中的状态/动作,组件需要时直接使用对应 store/hook,不要为了“纯组件”层层透传 props;避免一个组件传递过多参数。 - 已经放在全局 store 或全局 hook 中的状态/动作,组件需要时直接使用对应 store/hook,不要为了“纯组件”层层透传 props;避免一个组件传递过多参数。
- 全局组件、全局常量、全局配置等全局性质的内容不要作为 props 或参数层层传递;哪里需要就在哪里直接从对应全局入口获取。 - 全局组件、全局常量、全局配置等全局性质的内容不要作为 props 或参数层层传递;哪里需要就在哪里直接从对应全局入口获取。
- 多个页面重复出现的 UI 副作用动作,例如复制文本并提示、下载并提示、统一确认弹窗,优先抽成 `web/src/hooks/` 下的全局 hook;不要放进 store,除非它确实是需要共享/订阅的状态。 - 多个页面重复出现的 UI 副作用动作,例如复制文本并提示、下载并提示、统一确认弹窗,优先抽成 `web/src/hooks/` 下的全局 hook;不要放进 store,除非它确实是需要共享/订阅的状态。
- 画布相关状态和组件放在 `web/src/app/(user)/canvas/` 内部 - 路由页面放在 `web/src/pages/`,页面布局放在 `web/src/layouts/`,路由配置放在 `web/src/router.tsx`
- 页面里只有一个主业务组件时直接写在 `page.tsx`,不要单独拆 `Manager` 组件再传一堆 props - 画布页面放在 `web/src/pages/canvas/`,画布组件放在 `web/src/components/canvas/`,画布状态放在 `web/src/stores/canvas/`,画布工具函数放在 `web/src/lib/canvas/`
- 页面按目录组织,例如 `web/src/pages/image/index.tsx`;页面里只有一个主业务组件时直接写在对应页面入口中,不要单独拆 `Manager` 组件再传一堆 props。
- 不要新增只做简单转发的组件,例如只 `return <X>{children}</X>` 或只换个名字透传 props;直接在使用处使用真实组件或把逻辑写进当前文件。 - 不要新增只做简单转发的组件,例如只 `return <X>{children}</X>` 或只换个名字透传 props;直接在使用处使用真实组件或把逻辑写进当前文件。
- 页面私有 hook 放在对应页面目录下,例如 `admin/assets/use-admin-assets.ts`;只有多个页面真实复用的 hook 才放到外层 `hooks/` - 页面私有 hook 放在对应页面目录下,例如 `admin/assets/use-admin-assets.ts`;只有多个页面真实复用的 hook 才放到外层 `hooks/`
- 管理后台页面私有组件放到各自页面目录的 `components/` 下,例如 `admin/assets/components/``admin/prompts/components/`;不要为了单页面使用放到 `admin/components/` 共享目录。 - 管理后台页面私有组件放到各自页面目录的 `components/` 下,例如 `admin/assets/components/``admin/prompts/components/`;不要为了单页面使用放到 `admin/components/` 共享目录。
+1 -1
View File
@@ -11,4 +11,4 @@ description: 当前版本已实现但仍需人工验证的变更项
- 音频和视频生成:选择 Gemini 调用格式时先给出不支持提示,仍需使用 OpenAI 兼容渠道。 - 音频和视频生成:选择 Gemini 调用格式时先给出不支持提示,仍需使用 OpenAI 兼容渠道。
- WebDAV 同步:移除 Next.js 转发代理和连接方式选择,改为浏览器前端直接连接 WebDAV 服务。 - WebDAV 同步:移除 Next.js 转发代理和连接方式选择,改为浏览器前端直接连接 WebDAV 服务。
- 提示词库:移除 Next.js route 抓取和服务端内存缓存,改为浏览器前端直连 GitHub 原始文件并缓存到 IndexedDB。 - 提示词库:移除 Next.js route 抓取和服务端内存缓存,改为浏览器前端直连 GitHub 原始文件并缓存到 IndexedDB。
- 前端构建:移除 Next.js,改为 Vite + React Router,需验证首页、图片/视频工作台、素材、提示词库和画布路由跳转。 - 前端构建:移除 Next.js,改为 Vite + React Router并将前端目录调整为 `pages` / `components` / `stores` / `lib` / `layouts` / `styles`需验证首页、图片/视频工作台、素材、提示词库和画布路由跳转。
-5
View File
@@ -1,5 +0,0 @@
import CanvasClientPage from "./canvas-client-page";
export default function CanvasPage() {
return <CanvasClientPage />;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

@@ -1,5 +1,3 @@
"use client";
import { type ReactNode } from "react"; import { type ReactNode } from "react";
import { ImageSettingsTheme } from "@/components/image-settings-panel"; import { ImageSettingsTheme } from "@/components/image-settings-panel";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { Empty, Input, Modal, Pagination, Tag } from "antd"; import { Empty, Input, Modal, Pagination, Tag } from "antd";
import { Search } from "lucide-react"; import { Search } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState, type ReactNode } from "react"; import { useEffect, useRef, useState, type ReactNode } from "react";
import { Button, Tooltip } from "antd"; import { Button, Tooltip } from "antd";
import { ArrowUp, CheckCircle2, CircleAlert, ImagePlus, LoaderCircle, UserRound, Wrench, X, XCircle } from "lucide-react"; import { ArrowUp, CheckCircle2, CircleAlert, ImagePlus, LoaderCircle, UserRound, Wrench, X, XCircle } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import copyToClipboard from "copy-to-clipboard"; import copyToClipboard from "copy-to-clipboard";
import { Bot, Copy, Cpu, History, PanelRightClose, Plus, Settings2, Trash2, X } from "lucide-react"; import { Bot, Copy, Cpu, History, PanelRightClose, Plus, Settings2, Trash2, X } from "lucide-react";
@@ -20,10 +18,10 @@ import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/u
import { CanvasPromptLibrary } from "./canvas-prompt-library"; import { CanvasPromptLibrary } from "./canvas-prompt-library";
import { AgentChatComposer, AgentChatMessage, AgentModeSwitch, AgentPanelTabs, AgentWorkingMessage, type CanvasAgentChatMessage, type CanvasAgentMode } from "./canvas-agent-chat-ui"; import { AgentChatComposer, AgentChatMessage, AgentModeSwitch, AgentPanelTabs, AgentWorkingMessage, type CanvasAgentChatMessage, type CanvasAgentMode } from "./canvas-agent-chat-ui";
import { CanvasLocalAgentPanel } from "./canvas-local-agent-panel"; import { CanvasLocalAgentPanel } from "./canvas-local-agent-panel";
import { NODE_DEFAULT_SIZE } from "../constants"; import { NODE_DEFAULT_SIZE } from "@/constant/canvas";
import { CanvasNodeType, type CanvasAssistantMessage, type CanvasAssistantReference, type CanvasAssistantSession, type CanvasNodeData } from "../types"; import { CanvasNodeType, type CanvasAssistantMessage, type CanvasAssistantReference, type CanvasAssistantSession, type CanvasNodeData } from "@/types/canvas";
import { useCanvasAgentStore } from "../stores/use-canvas-agent-store"; import { useCanvasAgentStore } from "@/stores/canvas/use-canvas-agent-store";
import { summarizeCanvasAgentOps, type CanvasAgentOp, type CanvasAgentSnapshot } from "../utils/canvas-agent-ops"; import { summarizeCanvasAgentOps, type CanvasAgentOp, type CanvasAgentSnapshot } from "@/lib/canvas/canvas-agent-ops";
export const CANVAS_AGENT_PANEL_MOTION_MS = 500; export const CANVAS_AGENT_PANEL_MOTION_MS = 500;
const PANEL_MOTION_SECONDS = CANVAS_AGENT_PANEL_MOTION_MS / 1000; const PANEL_MOTION_SECONDS = CANVAS_AGENT_PANEL_MOTION_MS / 1000;
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState, type RefObject } from "react"; import { useEffect, useRef, useState, type RefObject } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { Settings2 } from "lucide-react"; import { Settings2 } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import type { CSSProperties, KeyboardEvent, MouseEvent, PointerEvent } from "react"; import type { CSSProperties, KeyboardEvent, MouseEvent, PointerEvent } from "react";
import { Button, Image } from "antd"; import { Button, Image } from "antd";
@@ -1,5 +1,3 @@
"use client";
import type { CSSProperties } from "react"; import type { CSSProperties } from "react";
import { Image as ImageIcon, LoaderCircle, MessageSquare, Music2, Play, Settings2, Square, Video } from "lucide-react"; import { Image as ImageIcon, LoaderCircle, MessageSquare, Music2, Play, Settings2, Square, Video } from "lucide-react";
import { Button, Segmented } from "antd"; import { Button, Segmented } from "antd";
@@ -12,7 +10,7 @@ import { useThemeStore } from "@/stores/use-theme-store";
import { CanvasImageSettingsPopover } from "./canvas-image-settings-popover"; import { CanvasImageSettingsPopover } from "./canvas-image-settings-popover";
import { CanvasAudioSettingsPopover, type CanvasAudioSettingKey } from "./canvas-audio-settings-popover"; import { CanvasAudioSettingsPopover, type CanvasAudioSettingKey } from "./canvas-audio-settings-popover";
import { CanvasVideoSettingsPopover } from "./canvas-video-settings-popover"; import { CanvasVideoSettingsPopover } from "./canvas-video-settings-popover";
import type { CanvasGenerationMode, CanvasNodeData, CanvasNodeMetadata } from "../types"; import type { CanvasGenerationMode, CanvasNodeData, CanvasNodeMetadata } from "@/types/canvas";
type CanvasConfigNodePanelProps = { type CanvasConfigNodePanelProps = {
node: CanvasNodeData; node: CanvasNodeData;
@@ -2,7 +2,7 @@ import type { MouseEvent as ReactMouseEvent } from "react";
import { canvasThemes } from "@/lib/canvas-theme"; import { canvasThemes } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import type { CanvasConnection, CanvasNodeData, ConnectionHandle, Position } from "../types"; import type { CanvasConnection, CanvasNodeData, ConnectionHandle, Position } from "@/types/canvas";
export function ConnectionPath({ export function ConnectionPath({
connection, connection,
@@ -1,12 +1,10 @@
"use client";
import { useEffect } from "react"; import { useEffect } from "react";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { Plus, Trash2 } from "lucide-react"; import { Plus, Trash2 } from "lucide-react";
import { canvasThemes } from "@/lib/canvas-theme"; import { canvasThemes } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import type { ContextMenuState } from "../types"; import type { ContextMenuState } from "@/types/canvas";
export function CanvasNodeContextMenu({ menu, onClose, onDuplicate, onDelete }: { menu: ContextMenuState; onClose: () => void; onDuplicate: () => void; onDelete: () => void }) { export function CanvasNodeContextMenu({ menu, onClose, onDuplicate, onDelete }: { menu: ContextMenuState; onClose: () => void; onDuplicate: () => void; onDelete: () => void }) {
const theme = canvasThemes[useThemeStore((state) => state.theme)]; const theme = canvasThemes[useThemeStore((state) => state.theme)];
@@ -1,10 +1,8 @@
"use client";
import { Button, Modal } from "antd"; import { Button, Modal } from "antd";
import { useAssetStore } from "@/stores/use-asset-store"; import { useAssetStore } from "@/stores/use-asset-store";
import { useCanvasStore } from "../stores/use-canvas-store"; import { useCanvasStore } from "@/stores/canvas/use-canvas-store";
import { useCanvasUiStore } from "../stores/use-canvas-ui-store"; import { useCanvasUiStore } from "@/stores/canvas/use-canvas-ui-store";
export function CanvasDeleteProjectsDialog() { export function CanvasDeleteProjectsDialog() {
const ids = useCanvasUiStore((state) => state.deleteProjectIds); const ids = useCanvasUiStore((state) => state.deleteProjectIds);
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState, type RefObject } from "react"; import { useEffect, useRef, useState, type RefObject } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { Settings2 } from "lucide-react"; import { Settings2 } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from "react"; import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from "react";
import { Button, Card, Checkbox, Form, Modal, Space, Switch, Tag, Tooltip, Typography, theme as antdTheme } from "antd"; import { Button, Card, Checkbox, Form, Modal, Space, Switch, Tag, Tooltip, Typography, theme as antdTheme } from "antd";
import { Ellipsis, Image as ImageIcon, Settings2 } from "lucide-react"; import { Ellipsis, Image as ImageIcon, Settings2 } from "lucide-react";
@@ -1,9 +1,7 @@
"use client";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { Brush, Camera, Copy, FileText, Grid2x2, Lock, LockOpen, Maximize2, Scissors, Sparkles, Upload, ZoomIn } from "lucide-react"; import { Brush, Camera, Copy, FileText, Grid2x2, Lock, LockOpen, Maximize2, Scissors, Sparkles, Upload, ZoomIn } from "lucide-react";
import type { CanvasNodeData } from "../types"; import type { CanvasNodeData } from "@/types/canvas";
export type ImageNodeActionToolId = "copyPrompt" | "reversePrompt" | "replace" | "resize" | "maskEdit" | "crop" | "split" | "upscale" | "superResolve" | "angle" | "view"; export type ImageNodeActionToolId = "copyPrompt" | "reversePrompt" | "replace" | "resize" | "maskEdit" | "crop" | "split" | "upscale" | "superResolve" | "angle" | "view";
export type ImageQuickToolId = "info" | "delete" | "saveAsset" | "download" | "edit" | ImageNodeActionToolId; export type ImageQuickToolId = "info" | "delete" | "saveAsset" | "download" | "edit" | ImageNodeActionToolId;
@@ -1,5 +1,3 @@
"use client";
import { useCallback, useEffect, useMemo, useRef, useState, type PointerEvent as ReactPointerEvent } from "react"; import { useCallback, useEffect, useMemo, useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { App, Button, Input, Segmented, Tooltip } from "antd"; import { App, Button, Input, Segmented, Tooltip } from "antd";
@@ -10,8 +8,8 @@ import { motion } from "motion/react";
import { canvasThemes } from "@/lib/canvas-theme"; import { canvasThemes } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import { useUserStore } from "@/stores/use-user-store"; import { useUserStore } from "@/stores/use-user-store";
import { useCanvasAgentStore, type AgentAttachment, type AgentChatItem, type AgentEventLog, type AgentPanelTab, type AgentPendingToolCall, type AgentThreadSummary } from "../stores/use-canvas-agent-store"; import { useCanvasAgentStore, type AgentAttachment, type AgentChatItem, type AgentEventLog, type AgentPanelTab, type AgentPendingToolCall, type AgentThreadSummary } from "@/stores/canvas/use-canvas-agent-store";
import { summarizeCanvasAgentOps, type CanvasAgentOp, type CanvasAgentSnapshot } from "../utils/canvas-agent-ops"; import { summarizeCanvasAgentOps, type CanvasAgentOp, type CanvasAgentSnapshot } from "@/lib/canvas/canvas-agent-ops";
import { AgentChatComposer, AgentChatMessage, AgentPanelTabs, AgentPendingToolCard, AgentWorkingMessage, type CanvasAgentChatAttachment } from "./canvas-agent-chat-ui"; import { AgentChatComposer, AgentChatMessage, AgentPanelTabs, AgentPendingToolCard, AgentWorkingMessage, type CanvasAgentChatAttachment } from "./canvas-agent-chat-ui";
const PANEL_MOTION_SECONDS = 0.5; const PANEL_MOTION_SECONDS = 0.5;
@@ -1,10 +1,8 @@
"use client";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useMemo, useRef, useState } from "react";
import { canvasThemes } from "@/lib/canvas-theme"; import { canvasThemes } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import { CanvasNodeType, type CanvasNodeData, type ViewportTransform } from "../types"; import { CanvasNodeType, type CanvasNodeData, type ViewportTransform } from "@/types/canvas";
export function Minimap({ nodes, viewport, viewportSize, onViewportChange }: { nodes: CanvasNodeData[]; viewport: ViewportTransform; viewportSize: { width: number; height: number }; onViewportChange: (viewport: ViewportTransform) => void }) { export function Minimap({ nodes, viewport, viewportSize, onViewportChange }: { nodes: CanvasNodeData[]; viewport: ViewportTransform; viewportSize: { width: number; height: number }; onViewportChange: (viewport: ViewportTransform) => void }) {
const theme = canvasThemes[useThemeStore((state) => state.theme)]; const theme = canvasThemes[useThemeStore((state) => state.theme)];
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Button, Modal, Segmented, Slider } from "antd"; import { Button, Modal, Segmented, Slider } from "antd";
import { RotateCcw, WandSparkles } from "lucide-react"; import { RotateCcw, WandSparkles } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState, type PointerEvent as ReactPointerEvent } from "react"; import { useEffect, useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
import { Button, Modal } from "antd"; import { Button, Modal } from "antd";
import { Check, Lock, LockOpen, X } from "lucide-react"; import { Check, Lock, LockOpen, X } from "lucide-react";
@@ -3,8 +3,8 @@ import { imageReferenceLabel } from "@/lib/image-reference-prompt";
import { seedanceReferenceLabel } from "@/lib/seedance-video"; import { seedanceReferenceLabel } from "@/lib/seedance-video";
import type { ReferenceImage } from "@/types/image"; import type { ReferenceImage } from "@/types/image";
import type { ReferenceAudio, ReferenceVideo } from "@/types/media"; import type { ReferenceAudio, ReferenceVideo } from "@/types/media";
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "../types"; import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "@/types/canvas";
import { getGenerationResourceNodes } from "../utils/canvas-resource-references"; import { getGenerationResourceNodes } from "@/lib/canvas/canvas-resource-references";
export type NodeGenerationContext = { export type NodeGenerationContext = {
prompt: string; prompt: string;
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useMemo, useState, type ReactNode } from "react"; import { useEffect, useMemo, useState, type ReactNode } from "react";
import { App, Modal, Segmented, Tooltip } from "antd"; import { App, Modal, Segmented, Tooltip } from "antd";
import { Download, Ellipsis, FolderPlus, Image as ImageIcon, Info, MessageSquare, Minus, Music2, Pencil, Plus, RefreshCw, Settings2, Trash2, Upload, Video } from "lucide-react"; import { Download, Ellipsis, FolderPlus, Image as ImageIcon, Info, MessageSquare, Minus, Music2, Pencil, Plus, RefreshCw, Settings2, Trash2, Upload, Video } from "lucide-react";
@@ -8,7 +6,7 @@ import { canvasThemes } from "@/lib/canvas-theme";
import { formatBytes, getDataUrlByteSize } from "@/lib/image-utils"; import { formatBytes, getDataUrlByteSize } from "@/lib/image-utils";
import { useCopyText } from "@/hooks/use-copy-text"; import { useCopyText } from "@/hooks/use-copy-text";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import { CanvasNodeType, type CanvasNodeData, type ViewportTransform } from "../types"; import { CanvasNodeType, type CanvasNodeData, type ViewportTransform } from "@/types/canvas";
import { ImageToolSettingsModal, type ImageToolbarSettingsTool } from "./canvas-image-toolbar-settings-modal"; import { ImageToolSettingsModal, type ImageToolbarSettingsTool } from "./canvas-image-toolbar-settings-modal";
import { IMAGE_QUICK_TOOLS_STORAGE_KEY, buildImageToolbarTools, defaultImageQuickToolIds, readImageQuickToolsConfig, type ImageQuickToolId } from "./canvas-image-toolbar-tools"; import { IMAGE_QUICK_TOOLS_STORAGE_KEY, buildImageToolbarTools, defaultImageQuickToolIds, readImageQuickToolsConfig, type ImageQuickToolId } from "./canvas-image-toolbar-tools";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState, type PointerEvent as ReactPointerEvent } from "react"; import { useEffect, useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
import { Button, Input, Modal, Slider } from "antd"; import { Button, Input, Modal, Slider } from "antd";
import { Brush, Eraser, RotateCcw, WandSparkles, X } from "lucide-react"; import { Brush, Eraser, RotateCcw, WandSparkles, X } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { ArrowUp, LoaderCircle, Square } from "lucide-react"; import { ArrowUp, LoaderCircle, Square } from "lucide-react";
import { Button } from "antd"; import { Button } from "antd";
@@ -14,8 +12,8 @@ import { CanvasPromptLibrary } from "./canvas-prompt-library";
import { CanvasAudioSettingsPopover, type CanvasAudioSettingKey } from "./canvas-audio-settings-popover"; import { CanvasAudioSettingsPopover, type CanvasAudioSettingKey } from "./canvas-audio-settings-popover";
import { CanvasResourceMentionTextarea } from "./canvas-resource-mention-textarea"; import { CanvasResourceMentionTextarea } from "./canvas-resource-mention-textarea";
import { CanvasVideoSettingsPopover } from "./canvas-video-settings-popover"; import { CanvasVideoSettingsPopover } from "./canvas-video-settings-popover";
import { CanvasNodeType, type CanvasGenerationMode, type CanvasNodeData } from "../types"; import { CanvasNodeType, type CanvasGenerationMode, type CanvasNodeData } from "@/types/canvas";
import type { CanvasResourceReference } from "../utils/canvas-resource-references"; import type { CanvasResourceReference } from "@/lib/canvas/canvas-resource-references";
export type CanvasNodeGenerationMode = CanvasGenerationMode; export type CanvasNodeGenerationMode = CanvasGenerationMode;
@@ -1,11 +1,9 @@
"use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Button, InputNumber, Modal } from "antd"; import { Button, InputNumber, Modal } from "antd";
import { Grid2x2 } from "lucide-react"; import { Grid2x2 } from "lucide-react";
import { readImageMeta } from "@/lib/image-utils"; import { readImageMeta } from "@/lib/image-utils";
import type { ImageSplitParams } from "../utils/canvas-image-data"; import type { ImageSplitParams } from "@/lib/canvas/canvas-image-data";
export type CanvasImageSplitParams = ImageSplitParams; export type CanvasImageSplitParams = ImageSplitParams;
@@ -1,11 +1,9 @@
"use client";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { Button, Modal, Segmented } from "antd"; import { Button, Modal, Segmented } from "antd";
import { ImagePlus } from "lucide-react"; import { ImagePlus } from "lucide-react";
import { readImageMeta } from "@/lib/image-utils"; import { readImageMeta } from "@/lib/image-utils";
import { MAX_UPSCALE_LONG_EDGE, resolveUpscaleSize, type ImageUpscaleAlgorithm, type ImageUpscaleParams } from "../utils/canvas-image-data"; import { MAX_UPSCALE_LONG_EDGE, resolveUpscaleSize, type ImageUpscaleAlgorithm, type ImageUpscaleParams } from "@/lib/canvas/canvas-image-data";
export type CanvasImageUpscaleParams = ImageUpscaleParams; export type CanvasImageUpscaleParams = ImageUpscaleParams;
@@ -1,5 +1,3 @@
"use client";
import React, { useCallback, useEffect, useRef, useState } from "react"; import React, { useCallback, useEffect, useRef, useState } from "react";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { ChevronRight, Image as ImageIcon, Music2, RefreshCw, Star, Video } from "lucide-react"; import { ChevronRight, Image as ImageIcon, Music2, RefreshCw, Star, Video } from "lucide-react";
@@ -8,8 +6,8 @@ import { canvasThemes } from "@/lib/canvas-theme";
import { formatBytes } from "@/lib/image-utils"; import { formatBytes } from "@/lib/image-utils";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import { CanvasResourceMentionTextarea } from "./canvas-resource-mention-textarea"; import { CanvasResourceMentionTextarea } from "./canvas-resource-mention-textarea";
import { CanvasNodeType, type CanvasNodeData, type Position } from "../types"; import { CanvasNodeType, type CanvasNodeData, type Position } from "@/types/canvas";
import type { CanvasResourceReference } from "../utils/canvas-resource-references"; import type { CanvasResourceReference } from "@/lib/canvas/canvas-resource-references";
type ResizeCorner = "top-left" | "top-right" | "bottom-left" | "bottom-right"; type ResizeCorner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
const selectionBlue = "#2f80ff"; const selectionBlue = "#2f80ff";
@@ -1,12 +1,10 @@
"use client";
import { Check, Download, Pencil, Trash2, X } from "lucide-react"; import { Check, Download, Pencil, Trash2, X } from "lucide-react";
import { useNavigate, useSearchParams } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { Button, Input } from "antd"; import { Button, Input } from "antd";
import { useCanvasStore, type CanvasProject } from "../stores/use-canvas-store"; import { useCanvasStore, type CanvasProject } from "@/stores/canvas/use-canvas-store";
import { useCanvasUiStore } from "../stores/use-canvas-ui-store"; import { useCanvasUiStore } from "@/stores/canvas/use-canvas-ui-store";
import { exportCanvasProjects } from "../utils/canvas-export"; import { exportCanvasProjects } from "@/lib/canvas/canvas-export";
export function CanvasProjectCard({ project }: { project: CanvasProject }) { export function CanvasProjectCard({ project }: { project: CanvasProject }) {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -1,5 +1,3 @@
"use client";
import { useState } from "react"; import { useState } from "react";
import { Button, Tooltip } from "antd"; import { Button, Tooltip } from "antd";
import { BookOpen } from "lucide-react"; import { BookOpen } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { forwardRef, useMemo, useRef, useState } from "react"; import { forwardRef, useMemo, useRef, useState } from "react";
import type { CSSProperties, MouseEvent, PointerEvent, TextareaHTMLAttributes } from "react"; import type { CSSProperties, MouseEvent, PointerEvent, TextareaHTMLAttributes } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
@@ -7,7 +5,7 @@ import { FileText, Image as ImageIcon, Music2, Video } from "lucide-react";
import { canvasThemes } from "@/lib/canvas-theme"; import { canvasThemes } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import type { CanvasResourceReference } from "../utils/canvas-resource-references"; import type { CanvasResourceReference } from "@/lib/canvas/canvas-resource-references";
type MentionState = { type MentionState = {
start: number; start: number;
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Select } from "antd"; import { Select } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState, type RefObject } from "react"; import { useEffect, useRef, useState, type RefObject } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { Settings2 } from "lucide-react"; import { Settings2 } from "lucide-react";
@@ -1,10 +1,8 @@
"use client";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { canvasThemes, type CanvasBackgroundMode } from "@/lib/canvas-theme"; import { canvasThemes, type CanvasBackgroundMode } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import type { ViewportTransform } from "../types"; import type { ViewportTransform } from "@/types/canvas";
type InfiniteCanvasProps = { type InfiniteCanvasProps = {
containerRef: React.RefObject<HTMLDivElement | null>; containerRef: React.RefObject<HTMLDivElement | null>;
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { LoaderCircle } from "lucide-react"; import { LoaderCircle } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { type ReactNode, useState } from "react"; import { type ReactNode, useState } from "react";
import { ConfigProvider, Switch } from "antd"; import { ConfigProvider, Switch } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { App, Button, Form, Input, Modal, Progress, Select, Tabs } from "antd"; import { App, Button, Form, Input, Modal, Progress, Select, Tabs } from "antd";
import { CircleAlert, Cloud, Plus, RefreshCw, Trash2, Wifi } from "lucide-react"; import { CircleAlert, Cloud, Plus, RefreshCw, Trash2, Wifi } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
@@ -1,5 +1,3 @@
"use client";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { useEffect } from "react"; import { useEffect } from "react";
import { ProConfigProvider } from "@ant-design/pro-components"; import { ProConfigProvider } from "@ant-design/pro-components";
@@ -1,5 +1,3 @@
"use client";
import { Menu } from "lucide-react"; import { Menu } from "lucide-react";
import { Link, useLocation } from "react-router-dom"; import { Link, useLocation } from "react-router-dom";
@@ -1,5 +1,3 @@
"use client";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { App } from "antd"; import { App } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { GithubOutlined } from "@ant-design/icons"; import { GithubOutlined } from "@ant-design/icons";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -1,5 +1,3 @@
"use client";
import { Drawer } from "antd"; import { Drawer } from "antd";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
@@ -1,5 +1,3 @@
"use client";
import type { CSSProperties } from "react"; import type { CSSProperties } from "react";
import { BookOpen, Keyboard, Settings2 } from "lucide-react"; import { BookOpen, Keyboard, Settings2 } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import type { CSSProperties } from "react"; import type { CSSProperties } from "react";
import { Modal, Tag, Timeline } from "antd"; import { Modal, Tag, Timeline } from "antd";
import { useVersionCheck } from "@/hooks/use-version-check"; import { useVersionCheck } from "@/hooks/use-version-check";
-2
View File
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useId, useMemo, useState } from "react"; import { useEffect, useId, useMemo, useState } from "react";
import { Cpu } from "lucide-react"; import { Cpu } from "lucide-react";
@@ -1,5 +1,3 @@
"use client";
import { Copy } from "lucide-react"; import { Copy } from "lucide-react";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { Button, Card, Tag } from "antd"; import { Button, Card, Tag } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { Check, Search } from "lucide-react"; import { Check, Search } from "lucide-react";
import { type UIEvent, useEffect, useState } from "react"; import { type UIEvent, useEffect, useState } from "react";
import { App, Empty, Input, Modal, Spin, Tag } from "antd"; import { App, Empty, Input, Modal, Spin, Tag } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { useMemo } from "react"; import { useMemo } from "react";
import { useInfiniteQuery } from "@tanstack/react-query"; import { useInfiniteQuery } from "@tanstack/react-query";
@@ -1,5 +1,3 @@
"use client";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { Moon, Sun } from "lucide-react"; import { Moon, Sun } from "lucide-react";
import { flushSync } from "react-dom"; import { flushSync } from "react-dom";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { animate, motion, useInView, useMotionValue, useReducedMotion, useTransform, type HTMLMotionProps } from "motion/react"; import { animate, motion, useInView, useMotionValue, useReducedMotion, useTransform, type HTMLMotionProps } from "motion/react";
-2
View File
@@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import { Select as SelectPrimitive } from "radix-ui" import { Select as SelectPrimitive } from "radix-ui"
@@ -1,5 +1,3 @@
"use client";
import { type ReactNode } from "react"; import { type ReactNode } from "react";
import { Switch } from "antd"; import { Switch } from "antd";
@@ -1,5 +1,5 @@
import { CanvasNodeType } from "./types"; import { CanvasNodeType } from "@/types/canvas";
import type { CanvasNodeMetadata } from "./types"; import type { CanvasNodeMetadata } from "@/types/canvas";
type CanvasNodeSpec = { type CanvasNodeSpec = {
width: number; width: number;
-2
View File
@@ -1,5 +1,3 @@
"use client";
import { App } from "antd"; import { App } from "antd";
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
@@ -1,5 +1,3 @@
"use client";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { AppTopNav } from "@/components/layout/app-top-nav"; import { AppTopNav } from "@/components/layout/app-top-nav";
@@ -1,7 +1,7 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { getNodeSpec } from "../constants"; import { getNodeSpec } from "@/constant/canvas";
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type CanvasNodeMetadata, type ViewportTransform } from "../types"; import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type CanvasNodeMetadata, type ViewportTransform } from "@/types/canvas";
export type CanvasAgentOp = export type CanvasAgentOp =
| { type: "add_node"; id?: string; nodeType?: CanvasNodeType; title?: string; position?: { x: number; y: number }; x?: number; y?: number; width?: number; height?: number; metadata?: CanvasNodeMetadata } | { type: "add_node"; id?: string; nodeType?: CanvasNodeType; title?: string; position?: { x: number; y: number }; x?: number; y?: number; width?: number; height?: number; metadata?: CanvasNodeMetadata }
@@ -3,8 +3,8 @@ import { saveAs } from "file-saver";
import { createZip } from "@/lib/zip"; import { createZip } from "@/lib/zip";
import { getMediaBlob } from "@/services/file-storage"; import { getMediaBlob } from "@/services/file-storage";
import { getImageBlob } from "@/services/image-storage"; import { getImageBlob } from "@/services/image-storage";
import type { CanvasExportAsset, CanvasExportFile } from "../export-types"; import type { CanvasExportAsset, CanvasExportFile } from "@/types/canvas-export";
import type { CanvasProject } from "../stores/use-canvas-store"; import type { CanvasProject } from "@/stores/canvas/use-canvas-store";
export async function exportCanvasProjects(projects: CanvasProject[], fileName = "无限画布") { export async function exportCanvasProjects(projects: CanvasProject[], fileName = "无限画布") {
const zipFiles: { name: string; data: BlobPart }[] = []; const zipFiles: { name: string; data: BlobPart }[] = [];
@@ -1,5 +1,3 @@
"use client";
export type ImageCropRect = { export type ImageCropRect = {
x: number; x: number;
y: number; y: number;
@@ -1,5 +1,3 @@
"use client";
export function fitNodeSize(width: number, height: number, maxWidth = 640, maxHeight = 640) { export function fitNodeSize(width: number, height: number, maxWidth = 640, maxHeight = 640) {
const w = Math.max(1, width); const w = Math.max(1, width);
const h = Math.max(1, height); const h = Math.max(1, height);
@@ -1,6 +1,6 @@
import { imageReferenceLabel } from "@/lib/image-reference-prompt"; import { imageReferenceLabel } from "@/lib/image-reference-prompt";
import { seedanceReferenceLabel } from "@/lib/seedance-video"; import { seedanceReferenceLabel } from "@/lib/seedance-video";
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "../types"; import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "@/types/canvas";
export type CanvasResourceKind = "image" | "video" | "audio" | "text"; export type CanvasResourceKind = "image" | "video" | "audio" | "text";
+1 -1
View File
@@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import "antd/dist/reset.css"; import "antd/dist/reset.css";
import "./app/globals.css"; import "./styles/globals.css";
import { RouterProvider } from "react-router-dom"; import { RouterProvider } from "react-router-dom";
import { AppProviders } from "@/components/layout/app-providers"; import { AppProviders } from "@/components/layout/app-providers";
@@ -1,5 +1,3 @@
"use client";
import { Copy, Download, PencilLine, Search, Trash2, Upload } from "lucide-react"; import { Copy, Download, PencilLine, Search, Trash2, Upload } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { App, Button, Card, Drawer, Empty, Form, Image, Input, Modal, Pagination, Select, Space, Tag, Typography } from "antd"; import { App, Button, Card, Drawer, Empty, Form, Image, Input, Modal, Pagination, Select, Space, Tag, Typography } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { useNavigate, useSearchParams } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { App, Button } from "antd"; import { App, Button } from "antd";
@@ -8,12 +6,12 @@ import { Download, FileUp, Plus } from "lucide-react";
import { readZip } from "@/lib/zip"; import { readZip } from "@/lib/zip";
import { setMediaBlob } from "@/services/file-storage"; import { setMediaBlob } from "@/services/file-storage";
import { setImageBlob } from "@/services/image-storage"; import { setImageBlob } from "@/services/image-storage";
import { CanvasDeleteProjectsDialog } from "./components/canvas-delete-projects-dialog"; import { CanvasDeleteProjectsDialog } from "@/components/canvas/canvas-delete-projects-dialog";
import { CanvasProjectCard } from "./components/canvas-project-card"; import { CanvasProjectCard } from "@/components/canvas/canvas-project-card";
import type { CanvasExportFile } from "./export-types"; import type { CanvasExportFile } from "@/types/canvas-export";
import { useCanvasStore } from "./stores/use-canvas-store"; import { useCanvasStore } from "@/stores/canvas/use-canvas-store";
import { useCanvasUiStore } from "./stores/use-canvas-ui-store"; import { useCanvasUiStore } from "@/stores/canvas/use-canvas-ui-store";
import { exportCanvasProjects } from "./utils/canvas-export"; import { exportCanvasProjects } from "@/lib/canvas/canvas-export";
export default function CanvasPage() { export default function CanvasPage() {
const { message } = App.useApp(); const { message } = App.useApp();
@@ -1,5 +1,3 @@
"use client";
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import type { ChangeEvent as ReactChangeEvent, DragEvent as ReactDragEvent, MouseEvent as ReactMouseEvent, PointerEvent as ReactPointerEvent } from "react"; import type { ChangeEvent as ReactChangeEvent, DragEvent as ReactDragEvent, MouseEvent as ReactMouseEvent, PointerEvent as ReactPointerEvent } from "react";
import { useNavigate, useParams, useSearchParams } from "react-router-dom"; import { useNavigate, useParams, useSearchParams } from "react-router-dom";
@@ -19,35 +17,35 @@ import { canvasThemes, type CanvasBackgroundMode } from "@/lib/canvas-theme";
import { UserStatusActions } from "@/components/layout/user-status-actions"; import { UserStatusActions } from "@/components/layout/user-status-actions";
import { useAssetStore } from "@/stores/use-asset-store"; import { useAssetStore } from "@/stores/use-asset-store";
import { useThemeStore } from "@/stores/use-theme-store"; import { useThemeStore } from "@/stores/use-theme-store";
import { cropDataUrl, splitDataUrl, upscaleDataUrl } from "../utils/canvas-image-data"; import { cropDataUrl, splitDataUrl, upscaleDataUrl } from "@/lib/canvas/canvas-image-data";
import { fitNodeSize, nodeSizeFromRatio } from "../utils/canvas-node-size"; import { fitNodeSize, nodeSizeFromRatio } from "@/lib/canvas/canvas-node-size";
import { App, Button, Dropdown, Modal } from "antd"; import { App, Button, Dropdown, Modal } from "antd";
import { NODE_DEFAULT_SIZE, getNodeSpec } from "../constants"; import { NODE_DEFAULT_SIZE, getNodeSpec } from "@/constant/canvas";
import { ActiveConnectionPath, ConnectionPath } from "../components/canvas-connections"; import { ActiveConnectionPath, ConnectionPath } from "@/components/canvas/canvas-connections";
import { CanvasConfigComposer } from "../components/canvas-config-composer"; import { CanvasConfigComposer } from "@/components/canvas/canvas-config-composer";
import { CanvasConfigNodePanel } from "../components/canvas-config-node-panel"; import { CanvasConfigNodePanel } from "@/components/canvas/canvas-config-node-panel";
import { CANVAS_AGENT_PANEL_MOTION_MS, CanvasAssistantPanel } from "../components/canvas-assistant-panel"; import { CANVAS_AGENT_PANEL_MOTION_MS, CanvasAssistantPanel } from "@/components/canvas/canvas-assistant-panel";
import { CanvasNodeContextMenu } from "../components/canvas-context-menu"; import { CanvasNodeContextMenu } from "@/components/canvas/canvas-context-menu";
import { CanvasNodeAngleDialog, type CanvasImageAngleParams } from "../components/canvas-node-angle-dialog"; import { CanvasNodeAngleDialog, type CanvasImageAngleParams } from "@/components/canvas/canvas-node-angle-dialog";
import { CanvasNodeCropDialog, type CanvasImageCropRect } from "../components/canvas-node-crop-dialog"; import { CanvasNodeCropDialog, type CanvasImageCropRect } from "@/components/canvas/canvas-node-crop-dialog";
import { CanvasNodeMaskEditDialog, type CanvasImageMaskEditPayload } from "../components/canvas-node-mask-edit-dialog"; import { CanvasNodeMaskEditDialog, type CanvasImageMaskEditPayload } from "@/components/canvas/canvas-node-mask-edit-dialog";
import { CanvasNodeSplitDialog, type CanvasImageSplitParams } from "../components/canvas-node-split-dialog"; import { CanvasNodeSplitDialog, type CanvasImageSplitParams } from "@/components/canvas/canvas-node-split-dialog";
import { CanvasNodeUpscaleDialog, type CanvasImageUpscaleParams } from "../components/canvas-node-upscale-dialog"; import { CanvasNodeUpscaleDialog, type CanvasImageUpscaleParams } from "@/components/canvas/canvas-node-upscale-dialog";
import { buildNodeGenerationContext, buildNodeGenerationInputs, buildNodeResponseMessages, hydrateNodeGenerationContext, type NodeGenerationInput } from "../components/canvas-node-generation"; import { buildNodeGenerationContext, buildNodeGenerationInputs, buildNodeResponseMessages, hydrateNodeGenerationContext, type NodeGenerationInput } from "@/components/canvas/canvas-node-generation";
import { CanvasNodeHoverToolbar, CanvasNodeInfoModal } from "../components/canvas-node-hover-toolbar"; import { CanvasNodeHoverToolbar, CanvasNodeInfoModal } from "@/components/canvas/canvas-node-hover-toolbar";
import { InfiniteCanvas } from "../components/infinite-canvas"; import { InfiniteCanvas } from "@/components/canvas/infinite-canvas";
import { Minimap } from "../components/canvas-mini-map"; import { Minimap } from "@/components/canvas/canvas-mini-map";
import { CanvasNode } from "../components/canvas-node"; import { CanvasNode } from "@/components/canvas/canvas-node";
import { CanvasNodePromptPanel, type CanvasNodeGenerationMode } from "../components/canvas-node-prompt-panel"; import { CanvasNodePromptPanel, type CanvasNodeGenerationMode } from "@/components/canvas/canvas-node-prompt-panel";
import { CanvasToolbar } from "../components/canvas-toolbar"; import { CanvasToolbar } from "@/components/canvas/canvas-toolbar";
import { AssetPickerModal, type InsertAssetPayload } from "../components/asset-picker-modal"; import { AssetPickerModal, type InsertAssetPayload } from "@/components/canvas/asset-picker-modal";
import { CanvasZoomControls } from "../components/canvas-zoom-controls"; import { CanvasZoomControls } from "@/components/canvas/canvas-zoom-controls";
import { CanvasLocalAgentPanel } from "../components/canvas-local-agent-panel"; import { CanvasLocalAgentPanel } from "@/components/canvas/canvas-local-agent-panel";
import { useCanvasAgentStore } from "../stores/use-canvas-agent-store"; import { useCanvasAgentStore } from "@/stores/canvas/use-canvas-agent-store";
import { useCanvasStore } from "../stores/use-canvas-store"; import { useCanvasStore } from "@/stores/canvas/use-canvas-store";
import { applyCanvasAgentOps, type CanvasAgentOp, type CanvasAgentSnapshot } from "../utils/canvas-agent-ops"; import { applyCanvasAgentOps, type CanvasAgentOp, type CanvasAgentSnapshot } from "@/lib/canvas/canvas-agent-ops";
import { buildCanvasResourceReferences, buildNodeMentionReferences } from "../utils/canvas-resource-references"; import { buildCanvasResourceReferences, buildNodeMentionReferences } from "@/lib/canvas/canvas-resource-references";
import type { CanvasAgentMode } from "../components/canvas-agent-chat-ui"; import type { CanvasAgentMode } from "@/components/canvas/canvas-agent-chat-ui";
import { import {
CanvasNodeType, CanvasNodeType,
type CanvasAssistantImage, type CanvasAssistantImage,
@@ -61,7 +59,7 @@ import {
type Position, type Position,
type SelectionBox, type SelectionBox,
type ViewportTransform, type ViewportTransform,
} from "../types"; } from "@/types/canvas";
import type { ReferenceImage } from "@/types/image"; import type { ReferenceImage } from "@/types/image";
import type { ReferenceAudio } from "@/types/media"; import type { ReferenceAudio } from "@/types/media";
@@ -1,5 +1,3 @@
"use client";
import { ArrowRight } from "lucide-react"; import { ArrowRight } from "lucide-react";
import { type ReactNode, useEffect, useState } from "react"; import { type ReactNode, useEffect, useState } from "react";
import { App, Button, Image, Tag } from "antd"; import { App, Button, Image, Tag } from "antd";
@@ -1,5 +1,3 @@
"use client";
import { ArrowLeft, ArrowRight, BookOpen, CheckSquare, ClipboardPaste, Download, FolderPlus, History, ImagePlus, LoaderCircle, PenLine, Plus, SlidersHorizontal, Sparkles, Trash2, Upload } from "lucide-react"; import { ArrowLeft, ArrowRight, BookOpen, CheckSquare, ClipboardPaste, Download, FolderPlus, History, ImagePlus, LoaderCircle, PenLine, Plus, SlidersHorizontal, Sparkles, Trash2, Upload } from "lucide-react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { App, Button, Checkbox, Drawer, Empty, Image, Input, Modal, Tag, Tooltip, Typography } from "antd"; import { App, Button, Checkbox, Drawer, Empty, Image, Input, Modal, Tag, Tooltip, Typography } from "antd";
@@ -9,7 +7,7 @@ import { saveAs } from "file-saver";
import { ImageSettingsPanel } from "@/components/image-settings-panel"; import { ImageSettingsPanel } from "@/components/image-settings-panel";
import { ModelPicker } from "@/components/model-picker"; import { ModelPicker } from "@/components/model-picker";
import { PromptSelectDialog } from "@/components/prompts/prompt-select-dialog"; import { PromptSelectDialog } from "@/components/prompts/prompt-select-dialog";
import { AssetPickerModal, type InsertAssetPayload } from "@/app/(user)/canvas/components/asset-picker-modal"; import { AssetPickerModal, type InsertAssetPayload } from "@/components/canvas/asset-picker-modal";
import { canvasThemes } from "@/lib/canvas-theme"; import { canvasThemes } from "@/lib/canvas-theme";
import { imageReferenceLabel } from "@/lib/image-reference-prompt"; import { imageReferenceLabel } from "@/lib/image-reference-prompt";
import { modelOptionLabel, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; import { modelOptionLabel, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store";
@@ -1,5 +1,3 @@
"use client";
import { Copy, FolderPlus } from "lucide-react"; import { Copy, FolderPlus } from "lucide-react";
import { Button, Modal, Space, Tag } from "antd"; import { Button, Modal, Space, Tag } from "antd";
@@ -1,12 +1,10 @@
"use client";
import { FolderPlus, Search } from "lucide-react"; import { FolderPlus, Search } from "lucide-react";
import { type UIEvent, useEffect, useState } from "react"; import { type UIEvent, useEffect, useState } from "react";
import { App, Button, Empty, Input, Spin, Tag } from "antd"; import { App, Button, Empty, Input, Spin, Tag } from "antd";
import { PromptCard } from "@/components/prompts/prompt-card"; import { PromptCard } from "@/components/prompts/prompt-card";
import { PromptDetailDialog } from "@/components/prompts/prompt-detail-dialog";
import { usePromptList } from "@/components/prompts/use-prompt-list"; import { usePromptList } from "@/components/prompts/use-prompt-list";
import { PromptDetailDialog } from "./components/prompt-detail-dialog";
import { useCopyText } from "@/hooks/use-copy-text"; import { useCopyText } from "@/hooks/use-copy-text";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useAssetStore } from "@/stores/use-asset-store"; import { useAssetStore } from "@/stores/use-asset-store";
@@ -1,5 +1,3 @@
"use client";
import { ArrowLeft, ArrowRight, BookOpen, CheckSquare, ClipboardPaste, Download, FolderPlus, History, LoaderCircle, Music2, Plus, SlidersHorizontal, Sparkles, Trash2, Upload, VideoIcon } from "lucide-react"; import { ArrowLeft, ArrowRight, BookOpen, CheckSquare, ClipboardPaste, Download, FolderPlus, History, LoaderCircle, Music2, Plus, SlidersHorizontal, Sparkles, Trash2, Upload, VideoIcon } from "lucide-react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { App, Button, Checkbox, Drawer, Empty, Input, Modal, Tag, Typography } from "antd"; import { App, Button, Checkbox, Drawer, Empty, Input, Modal, Tag, Typography } from "antd";
@@ -7,7 +5,7 @@ import localforage from "localforage";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { saveAs } from "file-saver"; import { saveAs } from "file-saver";
import { AssetPickerModal, type InsertAssetPayload } from "@/app/(user)/canvas/components/asset-picker-modal"; import { AssetPickerModal, type InsertAssetPayload } from "@/components/canvas/asset-picker-modal";
import { ModelPicker } from "@/components/model-picker"; import { ModelPicker } from "@/components/model-picker";
import { PromptSelectDialog } from "@/components/prompts/prompt-select-dialog"; import { PromptSelectDialog } from "@/components/prompts/prompt-select-dialog";
import { VideoSettingsPanel, normalizeVideoResolutionValue, normalizeVideoSizeValue, videoSizeLabel } from "@/components/video-settings-panel"; import { VideoSettingsPanel, normalizeVideoResolutionValue, normalizeVideoSizeValue, videoSizeLabel } from "@/components/video-settings-panel";
+10 -10
View File
@@ -1,14 +1,14 @@
import { createBrowserRouter, Outlet } from "react-router-dom"; import { createBrowserRouter, Outlet } from "react-router-dom";
import NotFound from "@/app/not-found"; import UserLayout from "@/layouts/user-layout";
import UserLayout from "@/app/(user)/layout"; import AssetsPage from "@/pages/assets";
import IndexPage from "@/app/(user)/page"; import CanvasPage from "@/pages/canvas";
import ImagePage from "@/app/(user)/image/page"; import CanvasProjectPage from "@/pages/canvas/project";
import VideoPage from "@/app/(user)/video/page"; import HomePage from "@/pages/home";
import AssetsPage from "@/app/(user)/assets/page"; import ImagePage from "@/pages/image";
import PromptsPage from "@/app/(user)/prompts/page"; import NotFound from "@/pages/not-found";
import CanvasPage from "@/app/(user)/canvas/page"; import PromptsPage from "@/pages/prompts";
import CanvasProjectPage from "@/app/(user)/canvas/[id]/page"; import VideoPage from "@/pages/video";
export const router = createBrowserRouter([ export const router = createBrowserRouter([
{ {
@@ -18,7 +18,7 @@ export const router = createBrowserRouter([
</UserLayout> </UserLayout>
), ),
children: [ children: [
{ path: "/", element: <IndexPage /> }, { path: "/", element: <HomePage /> },
{ path: "/image", element: <ImagePage /> }, { path: "/image", element: <ImagePage /> },
{ path: "/video", element: <VideoPage /> }, { path: "/video", element: <VideoPage /> },
{ path: "/assets", element: <AssetsPage /> }, { path: "/assets", element: <AssetsPage /> },
-2
View File
@@ -1,5 +1,3 @@
"use client";
import localforage from "localforage"; import localforage from "localforage";
export type Prompt = { export type Prompt = {
+2 -4
View File
@@ -1,5 +1,3 @@
"use client";
import localforage from "localforage"; import localforage from "localforage";
import { getMediaBlob, resolveMediaUrl, setMediaBlob } from "@/services/file-storage"; import { getMediaBlob, resolveMediaUrl, setMediaBlob } from "@/services/file-storage";
@@ -8,8 +6,8 @@ import { downloadWebdavFile, uploadWebdavFile, WEBDAV_MANIFEST_FILE_NAME } from
import type { Asset } from "@/stores/use-asset-store"; import type { Asset } from "@/stores/use-asset-store";
import { useAssetStore } from "@/stores/use-asset-store"; import { useAssetStore } from "@/stores/use-asset-store";
import type { WebdavSyncConfig } from "@/stores/use-config-store"; import type { WebdavSyncConfig } from "@/stores/use-config-store";
import type { CanvasProject } from "@/app/(user)/canvas/stores/use-canvas-store"; import type { CanvasProject } from "@/stores/canvas/use-canvas-store";
import { useCanvasStore } from "@/app/(user)/canvas/stores/use-canvas-store"; import { useCanvasStore } from "@/stores/canvas/use-canvas-store";
type StoredLog = Record<string, unknown> & { id?: string }; type StoredLog = Record<string, unknown> & { id?: string };
export type AppSyncDomainKey = "canvas" | "assets" | "image-workbench" | "video-workbench"; export type AppSyncDomainKey = "canvas" | "assets" | "image-workbench" | "video-workbench";
-2
View File
@@ -1,5 +1,3 @@
"use client";
import localforage from "localforage"; import localforage from "localforage";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
-2
View File
@@ -1,5 +1,3 @@
"use client";
import localforage from "localforage"; import localforage from "localforage";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
-2
View File
@@ -1,5 +1,3 @@
"use client";
import type { WebdavSyncConfig } from "@/stores/use-config-store"; import type { WebdavSyncConfig } from "@/stores/use-config-store";
export const WEBDAV_MANIFEST_FILE_NAME = "manifest.json"; export const WEBDAV_MANIFEST_FILE_NAME = "manifest.json";
@@ -1,6 +1,6 @@
import { create } from "zustand"; import { create } from "zustand";
import type { CanvasAgentOp } from "../utils/canvas-agent-ops"; import type { CanvasAgentOp } from "@/lib/canvas/canvas-agent-ops";
export type AgentChatRole = "user" | "assistant" | "system" | "tool" | "error"; export type AgentChatRole = "user" | "assistant" | "system" | "tool" | "error";
export type AgentAttachment = { id: string; name: string; type: string; size: number; url: string; dataUrl: string }; export type AgentAttachment = { id: string; name: string; type: string; size: number; url: string; dataUrl: string };
@@ -4,7 +4,7 @@ import { persist, type PersistStorage, type StorageValue } from "zustand/middlew
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { localForageStorage } from "@/lib/localforage-storage"; import { localForageStorage } from "@/lib/localforage-storage";
import type { CanvasBackgroundMode } from "@/lib/canvas-theme"; import type { CanvasBackgroundMode } from "@/lib/canvas-theme";
import type { CanvasAssistantSession, CanvasConnection, CanvasNodeData, ViewportTransform } from "../types"; import type { CanvasAssistantSession, CanvasConnection, CanvasNodeData, ViewportTransform } from "@/types/canvas";
export type CanvasProject = { export type CanvasProject = {
id: string; id: string;
+1 -3
View File
@@ -1,5 +1,3 @@
"use client";
import { create } from "zustand"; import { create } from "zustand";
import { persist, type PersistStorage, type StorageValue } from "zustand/middleware"; import { persist, type PersistStorage, type StorageValue } from "zustand/middleware";
@@ -89,7 +87,7 @@ export const useAssetStore = create<AssetStore>()(
replaceAssets: (assets) => set({ assets }), replaceAssets: (assets) => set({ assets }),
cleanupImages: (extra) => { cleanupImages: (extra) => {
window.setTimeout(async () => { window.setTimeout(async () => {
const { useCanvasStore } = await import("@/app/(user)/canvas/stores/use-canvas-store"); const { useCanvasStore } = await import("@/stores/canvas/use-canvas-store");
await cleanupUnusedImages({ assets: get().assets, projects: useCanvasStore.getState().projects, extra }); await cleanupUnusedImages({ assets: get().assets, projects: useCanvasStore.getState().projects, extra });
await cleanupUnusedMedia({ assets: get().assets, projects: useCanvasStore.getState().projects, extra }); await cleanupUnusedMedia({ assets: get().assets, projects: useCanvasStore.getState().projects, extra });
}, 0); }, 0);
-2
View File
@@ -1,5 +1,3 @@
"use client";
import { useMemo } from "react"; import { useMemo } from "react";
import { create } from "zustand"; import { create } from "zustand";
import { persist } from "zustand/middleware"; import { persist } from "zustand/middleware";
-2
View File
@@ -1,5 +1,3 @@
"use client";
import { create } from "zustand"; import { create } from "zustand";
export type LocalUser = { export type LocalUser = {
@@ -1,4 +1,4 @@
import type { CanvasProject } from "./stores/use-canvas-store"; import type { CanvasProject } from "@/stores/canvas/use-canvas-store";
export type CanvasExportFile = { export type CanvasExportFile = {
app: "infinite-canvas"; app: "infinite-canvas";