diff --git a/web/src/components/canvas/canvas-folder-preview.tsx b/web/src/components/canvas/canvas-folder-preview.tsx index ab1630e14..ac411ef4b 100644 --- a/web/src/components/canvas/canvas-folder-preview.tsx +++ b/web/src/components/canvas/canvas-folder-preview.tsx @@ -125,12 +125,11 @@ export const CanvasFolderPreview = React.memo(function CanvasFolderPreview({ if (!readOnly) setEditing(true); }} > - {data.title}{!readOnly ? : null} + {data.title} + {!readOnly ? : null} )} - - {style === "midnight" ? formatFolderDate(data.metadata?.folder?.createdAt) : `${childNodes.length} 项内容`} - + {style === "midnight" ? formatFolderDate(data.metadata?.folder?.createdAt) : `${childNodes.length} 项内容`} {!readOnly ? ( @@ -149,10 +148,7 @@ export const CanvasFolderPreview = React.memo(function CanvasFolderPreview({ ) : ( - + diff --git a/web/src/lib/canvas/canvas-folder-theme.ts b/web/src/lib/canvas/canvas-folder-theme.ts index b42b56a77..9bc13da54 100644 --- a/web/src/lib/canvas/canvas-folder-theme.ts +++ b/web/src/lib/canvas/canvas-folder-theme.ts @@ -12,7 +12,7 @@ export const CANVAS_FOLDER_THEME_OPTIONS: ReadonlyArray<{ ]; export function resolveCanvasFolderTheme(value?: string): CanvasFolderTheme { - return CANVAS_FOLDER_THEME_OPTIONS.some((theme) => theme.key === value) ? value as CanvasFolderTheme : "aurora"; + return CANVAS_FOLDER_THEME_OPTIONS.some((theme) => theme.key === value) ? (value as CanvasFolderTheme) : "aurora"; } export function resolveCanvasFolderThemeCover(theme?: string, customCover?: string) { diff --git a/web/src/pages/dev/folder-preview-lab.css b/web/src/pages/dev/folder-preview-lab.css index 265471e08..b28581824 100644 --- a/web/src/pages/dev/folder-preview-lab.css +++ b/web/src/pages/dev/folder-preview-lab.css @@ -22,14 +22,14 @@ color: var(--muted-foreground); font-size: var(--fs-label); font-weight: 650; - letter-spacing: .12em; + letter-spacing: 0.12em; } .folder-preview-lab-header h1 { margin: var(--space-2) 0 0; font-size: var(--fs-display); font-weight: 620; - letter-spacing: -.04em; + letter-spacing: -0.04em; } .folder-preview-lab-header p { @@ -151,7 +151,7 @@ margin: 0; font-size: var(--fs-title); font-weight: 620; - letter-spacing: -.02em; + letter-spacing: -0.02em; } .folder-preview-lab-section-heading p { @@ -215,7 +215,9 @@ padding: var(--space-2) var(--space-4); color: var(--fg); font-size: var(--fs-body); - transition: transform var(--motion-state) var(--motion-ease-out), background-color var(--motion-state) var(--motion-ease-out); + transition: + transform var(--motion-state) var(--motion-ease-out), + background-color var(--motion-state) var(--motion-ease-out); } .folder-preview-lab-open { @@ -282,7 +284,9 @@ overflow: hidden; border-radius: var(--r-3xl); background: var(--library-surface); - transition: transform var(--motion-state) var(--motion-ease-out), background-color var(--motion-state) var(--motion-ease-out); + transition: + transform var(--motion-state) var(--motion-ease-out), + background-color var(--motion-state) var(--motion-ease-out); } .folder-preview-lab-asset:hover { @@ -315,16 +319,37 @@ } @media (max-width: 760px) { - .folder-preview-lab { padding: var(--space-6) var(--space-4) var(--space-12); } + .folder-preview-lab { + padding: var(--space-6) var(--space-4) var(--space-12); + } .folder-preview-lab-header, .folder-preview-lab-controls, - .folder-preview-lab-section-heading { align-items: flex-start; flex-direction: column; } - .folder-preview-lab-grid { grid-template-columns: minmax(0, 1fr); } - .folder-preview-lab-theme-catalog { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .folder-preview-lab-folder { transform: scale(.86); transform-origin: top center; margin-bottom: -40px; } - .folder-preview-lab-drawer { inset: var(--space-2); padding: var(--space-4); } - .folder-preview-lab-drawer-header { grid-template-columns: 1fr 1fr; } - .folder-preview-lab-drawer-header > div { grid-column: 1 / -1; grid-row: 1; } + .folder-preview-lab-section-heading { + align-items: flex-start; + flex-direction: column; + } + .folder-preview-lab-grid { + grid-template-columns: minmax(0, 1fr); + } + .folder-preview-lab-theme-catalog { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .folder-preview-lab-folder { + transform: scale(0.86); + transform-origin: top center; + margin-bottom: -40px; + } + .folder-preview-lab-drawer { + inset: var(--space-2); + padding: var(--space-4); + } + .folder-preview-lab-drawer-header { + grid-template-columns: 1fr 1fr; + } + .folder-preview-lab-drawer-header > div { + grid-column: 1 / -1; + grid-row: 1; + } } @media (prefers-reduced-motion: reduce) { @@ -332,6 +357,6 @@ .folder-preview-lab-open, .folder-preview-lab-asset, .folder-preview-lab-drawer-header button { - transition-duration: .01ms !important; + transition-duration: 0.01ms !important; } } diff --git a/web/src/pages/dev/folder-preview-lab.tsx b/web/src/pages/dev/folder-preview-lab.tsx index 2412acef4..60445f4d2 100644 --- a/web/src/pages/dev/folder-preview-lab.tsx +++ b/web/src/pages/dev/folder-preview-lab.tsx @@ -35,13 +35,7 @@ const PRESET_GROUPS = [ const THEME_SEQUENCE: CanvasFolderTheme[] = ["aurora", "pearl", "ember", "obsidian", "aurora", "pearl"]; -const SAMPLE_MEDIA = [ - "/short-drama-styles/fantasy-3d.jpg", - "/short-drama-styles/suspense-noir.jpg", - "/short-drama-styles/cyberpunk-neon.jpg", - "/short-drama-styles/ink-narrative.jpg", - "/short-drama-styles/space-opera.jpg", -]; +const SAMPLE_MEDIA = ["/short-drama-styles/fantasy-3d.jpg", "/short-drama-styles/suspense-noir.jpg", "/short-drama-styles/cyberpunk-neon.jpg", "/short-drama-styles/ink-narrative.jpg", "/short-drama-styles/space-opera.jpg"]; function makeMediaNode(id: string, title: string, content: string, index: number): CanvasNodeData { return { @@ -75,9 +69,7 @@ const INITIAL_FOLDERS = STYLE_PRESETS.map((preset, index) => makeFolderNode(pres const INITIAL_CHILDREN = Object.fromEntries( INITIAL_FOLDERS.map((folder, folderIndex) => [ folder.id, - SAMPLE_MEDIA.slice(0, 3 + (folderIndex % 3)).map((source, childIndex) => - makeMediaNode(`${folder.id}-asset-${childIndex}`, ["主视觉", "氛围参考", "场景草图", "色彩方案", "镜头灵感"][childIndex], source, childIndex), - ), + SAMPLE_MEDIA.slice(0, 3 + (folderIndex % 3)).map((source, childIndex) => makeMediaNode(`${folder.id}-asset-${childIndex}`, ["主视觉", "氛围参考", "场景草图", "色彩方案", "镜头灵感"][childIndex], source, childIndex)), ]), ) as Record; @@ -100,12 +92,7 @@ export default function FolderPreviewLab() { setChildrenByFolder((current) => { const previous = current[openedId] || []; const index = previous.length; - const next = makeMediaNode( - `${openedId}-asset-${Date.now()}`, - `新素材 ${index + 1}`, - SAMPLE_MEDIA[index % SAMPLE_MEDIA.length], - index, - ); + const next = makeMediaNode(`${openedId}-asset-${Date.now()}`, `新素材 ${index + 1}`, SAMPLE_MEDIA[index % SAMPLE_MEDIA.length], index); return { ...current, [openedId]: [...previous, next] }; }); }; diff --git a/web/test/canvas-folder.test.ts b/web/test/canvas-folder.test.ts index 28ca1c985..af84e38ad 100644 --- a/web/test/canvas-folder.test.ts +++ b/web/test/canvas-folder.test.ts @@ -1,12 +1,6 @@ import { describe, expect, test } from "bun:test"; -import { - applyFrameDrop, - canFolderContain, - canLinkedFolderArchive, - findFrameDropTarget, - isCanvasFolderNode, -} from "@/lib/canvas/canvas-frame"; +import { applyFrameDrop, canFolderContain, canLinkedFolderArchive, findFrameDropTarget, isCanvasFolderNode } from "@/lib/canvas/canvas-frame"; import { resolveCanvasFolderTheme, resolveCanvasFolderThemeCover } from "@/lib/canvas/canvas-folder-theme"; import { CanvasNodeType, type CanvasNodeData } from "@/types/canvas";