feat(canvas): 自由画布 - 增强空白起点、外观设置与节点连接体验 (#356)

This commit is contained in:
vv-get-ti
2026-08-31 06:49:43 +08:00
committed by GitHub
parent cc4aa736ff
commit 151e99f8d9
22 changed files with 925 additions and 113 deletions

View File

@@ -2,10 +2,12 @@ import { create } from "zustand";
import { persist, type PersistStorage, type StorageValue } from "zustand/middleware";
import { nanoid } from "nanoid";
import { normalizeCanvasAppearance, readCanvasAppearanceDefault, type CanvasAppearance } from "@/lib/canvas/canvas-appearance";
import { parseCanvasStorageDocument, rebaseCanvasProjects, serializeCanvasStorageDocument, type CanvasStorageDocument } from "@/lib/canvas/canvas-storage-revision";
import { localForageStorageForScope } from "@/lib/localforage-storage";
import { getActiveUserScope } from "@/lib/user-scope";
import type { CanvasBackgroundMode } from "@/lib/canvas-theme";
import type { CanvasStarterMode } from "@/lib/canvas/canvas-starter";
import type { CanvasAssistantSession, CanvasConnection, CanvasNodeData, ViewportTransform } from "@/types/canvas";
import type { DirectorScene } from "@/types/director";
import type { TimelineProject } from "@/types/timeline";
@@ -20,6 +22,8 @@ export type CanvasProject = {
connections: CanvasConnection[];
chatSessions: CanvasAssistantSession[];
activeChatId: string | null;
starterMode?: CanvasStarterMode;
appearance?: CanvasAppearance;
backgroundMode: CanvasBackgroundMode;
showImageInfo: boolean;
viewport: ViewportTransform;
@@ -36,7 +40,7 @@ type CanvasStore = {
renameProject: (id: string, title: string) => void;
deleteProjects: (ids: string[]) => void;
replaceProjects: (projects: CanvasProject[]) => void;
updateProject: (id: string, patch: Partial<Pick<CanvasProject, "projectId" | "nodes" | "connections" | "chatSessions" | "activeChatId" | "backgroundMode" | "showImageInfo" | "viewport" | "directorScenes" | "timeline">>) => void;
updateProject: (id: string, patch: Partial<Pick<CanvasProject, "projectId" | "nodes" | "connections" | "chatSessions" | "activeChatId" | "starterMode" | "appearance" | "backgroundMode" | "showImageInfo" | "viewport" | "directorScenes" | "timeline">>) => void;
};
const initialViewport: ViewportTransform = { x: 0, y: 0, k: 1 };
@@ -418,6 +422,7 @@ export const useCanvasStore = create<CanvasStore>()(
createProject: (title = "未命名画布", projectId) => {
const now = new Date().toISOString();
const id = nanoid();
const appearanceDefault = readCanvasAppearanceDefault();
const project: CanvasProject = {
id,
projectId,
@@ -428,7 +433,8 @@ export const useCanvasStore = create<CanvasStore>()(
connections: [],
chatSessions: [],
activeChatId: null,
backgroundMode: "lines",
appearance: appearanceDefault?.appearance,
backgroundMode: appearanceDefault?.backgroundMode || "lines",
showImageInfo: false,
viewport: initialViewport,
directorScenes: [],
@@ -448,6 +454,8 @@ export const useCanvasStore = create<CanvasStore>()(
connections: source.connections || [],
chatSessions: source.chatSessions || [],
activeChatId: source.activeChatId || null,
starterMode: source.starterMode,
appearance: source.appearance ? normalizeCanvasAppearance(source.appearance, "dark") : undefined,
backgroundMode: source.backgroundMode || "lines",
showImageInfo: source.showImageInfo || false,
viewport: source.viewport || initialViewport,