fix(canvas): 文件夹主题 - 对齐参考材质并分离内容预览
This commit is contained in:
@@ -39,7 +39,7 @@ export const CanvasFolderPreview = React.memo(function CanvasFolderPreview({
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [title, setTitle] = useState(data.title);
|
||||
const previewNodes = useMemo(() => childNodes.filter(canPreviewFolderNode).slice(0, 3), [childNodes]);
|
||||
const primaryNode = previewNodes[0];
|
||||
const themeCover = data.metadata?.folder?.themeCover || DEFAULT_FOLDER_COVER;
|
||||
const showAdd = style === "glass" || childNodes.length === 0;
|
||||
|
||||
useEffect(() => setTitle(data.title), [data.title]);
|
||||
@@ -54,20 +54,22 @@ export const CanvasFolderPreview = React.memo(function CanvasFolderPreview({
|
||||
return (
|
||||
<div className={`canvas-folder-preview canvas-folder-preview-${style}${active ? " is-active" : ""}${isDropTarget ? " is-drop-target" : ""}`}>
|
||||
<div className="canvas-folder-back" aria-hidden>
|
||||
<FolderNodeMedia node={primaryNode} fallback />
|
||||
<FolderThemeMedia source={themeCover} />
|
||||
</div>
|
||||
|
||||
<div className="canvas-folder-paper-sheet" aria-hidden />
|
||||
|
||||
<div className="canvas-folder-preview-stack" aria-hidden>
|
||||
{(previewNodes.length ? previewNodes : [undefined, undefined]).map((node, index) => (
|
||||
<div key={node?.id || `folder-placeholder-${index}`} className={`canvas-folder-preview-card canvas-folder-preview-card-${index + 1}`}>
|
||||
<FolderNodeMedia node={node} fallback={index === 0} />
|
||||
<FolderNodeMedia node={node} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="canvas-folder-front">
|
||||
<div className="canvas-folder-front-media" aria-hidden>
|
||||
<FolderNodeMedia node={primaryNode} fallback />
|
||||
<FolderThemeMedia source={themeCover} />
|
||||
</div>
|
||||
<div className="canvas-folder-front-tint" aria-hidden />
|
||||
|
||||
@@ -180,7 +182,11 @@ function canPreviewFolderNode(node: CanvasNodeData) {
|
||||
return node.type !== CanvasNodeType.Frame;
|
||||
}
|
||||
|
||||
function FolderNodeMedia({ node, fallback = false }: { node?: CanvasNodeData; fallback?: boolean }) {
|
||||
function FolderThemeMedia({ source }: { source: string }) {
|
||||
return <img src={source} alt="" loading="eager" decoding="async" draggable={false} />;
|
||||
}
|
||||
|
||||
function FolderNodeMedia({ node }: { node?: CanvasNodeData }) {
|
||||
if (node?.type === CanvasNodeType.Image && node.metadata?.content) {
|
||||
return <img src={node.metadata.content} alt="" loading="lazy" decoding="async" draggable={false} />;
|
||||
}
|
||||
@@ -198,7 +204,7 @@ function FolderNodeMedia({ node, fallback = false }: { node?: CanvasNodeData; fa
|
||||
return <span className="canvas-folder-text-preview">{node.metadata?.content || node.title}</span>;
|
||||
}
|
||||
if (node) return <FileText className="canvas-folder-file-icon" />;
|
||||
return fallback ? <img src={DEFAULT_FOLDER_COVER} alt="" loading="lazy" decoding="async" draggable={false} /> : <span className="canvas-folder-file-sheet" />;
|
||||
return <span className="canvas-folder-file-sheet" />;
|
||||
}
|
||||
|
||||
function formatFolderDate(value?: string) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
.folder-preview-lab {
|
||||
min-height: 100dvh;
|
||||
overflow: auto;
|
||||
background: var(--workspace-canvas);
|
||||
background-color: var(--workspace-canvas);
|
||||
background-image: radial-gradient(circle, var(--border-semantic) 1.15px, transparent 1.35px);
|
||||
background-position: center top;
|
||||
background-size: 24px 24px;
|
||||
color: var(--fg);
|
||||
padding: var(--space-10) var(--space-12) var(--space-20);
|
||||
}
|
||||
@@ -49,6 +52,43 @@
|
||||
font-size: var(--fs-caption);
|
||||
}
|
||||
|
||||
.folder-preview-lab-controls {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.folder-preview-lab-theme {
|
||||
display: inline-flex;
|
||||
border-radius: var(--r-full);
|
||||
background: var(--library-surface);
|
||||
padding: var(--space-1);
|
||||
}
|
||||
|
||||
.folder-preview-lab-theme button {
|
||||
display: inline-flex;
|
||||
min-height: 40px;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
border: 0;
|
||||
border-radius: var(--r-full);
|
||||
background: transparent;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
color: var(--muted-foreground);
|
||||
font-size: var(--fs-caption);
|
||||
}
|
||||
|
||||
.folder-preview-lab-theme button[aria-pressed="true"] {
|
||||
background: var(--control-selected-bg);
|
||||
color: var(--control-selected-fg);
|
||||
}
|
||||
|
||||
.folder-preview-lab-theme svg {
|
||||
width: var(--space-4);
|
||||
height: var(--space-4);
|
||||
}
|
||||
|
||||
.folder-preview-lab-guide svg,
|
||||
.folder-preview-lab-open svg,
|
||||
.folder-preview-lab-drawer-header button svg {
|
||||
@@ -56,10 +96,38 @@
|
||||
height: var(--space-4);
|
||||
}
|
||||
|
||||
.folder-preview-lab-grid {
|
||||
display: grid;
|
||||
.folder-preview-lab-section {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.folder-preview-lab-section + .folder-preview-lab-section {
|
||||
margin-top: var(--space-16);
|
||||
}
|
||||
|
||||
.folder-preview-lab-section-heading {
|
||||
display: flex;
|
||||
margin-bottom: var(--space-6);
|
||||
align-items: end;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
.folder-preview-lab-section-heading h2 {
|
||||
margin: 0;
|
||||
font-size: var(--fs-title);
|
||||
font-weight: 620;
|
||||
letter-spacing: -.02em;
|
||||
}
|
||||
|
||||
.folder-preview-lab-section-heading p {
|
||||
margin: 0;
|
||||
color: var(--muted-foreground);
|
||||
font-size: var(--fs-caption);
|
||||
}
|
||||
|
||||
.folder-preview-lab-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
|
||||
gap: var(--space-10) var(--space-8);
|
||||
}
|
||||
@@ -214,7 +282,9 @@
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.folder-preview-lab { padding: var(--space-6) var(--space-4) var(--space-12); }
|
||||
.folder-preview-lab-header { align-items: flex-start; flex-direction: column; }
|
||||
.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-folder { transform: scale(.86); transform-origin: top center; margin-bottom: -40px; }
|
||||
.folder-preview-lab-drawer { inset: var(--space-2); padding: var(--space-4); }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { ChevronLeft, FolderOpen, ImagePlus, MousePointer2 } from "lucide-react";
|
||||
import { ChevronLeft, FolderOpen, ImagePlus, Moon, MousePointer2, Sun } from "lucide-react";
|
||||
|
||||
import { CanvasFolderPreview } from "@/components/canvas/canvas-folder-preview";
|
||||
import { useThemeStore } from "@/stores/use-theme-store";
|
||||
import type { CanvasFolderStyle, CanvasNodeData } from "@/types/canvas";
|
||||
import { CanvasNodeType } from "@/types/canvas";
|
||||
|
||||
@@ -16,6 +17,23 @@ const STYLE_PRESETS: Array<{ style: CanvasFolderStyle; name: string; hint: strin
|
||||
{ style: "compact", name: "紧凑资料", hint: "衍生 · 高频调用" },
|
||||
];
|
||||
|
||||
const PRESET_GROUPS = [
|
||||
{
|
||||
key: "reference",
|
||||
title: "原图复刻",
|
||||
description: "三种参考结构:玻璃加号、内容陈列、午夜封面。",
|
||||
presets: STYLE_PRESETS.slice(0, 3),
|
||||
},
|
||||
{
|
||||
key: "derived",
|
||||
title: "风格衍生",
|
||||
description: "沿用同一主题皮肤与交互合同的工作流变体。",
|
||||
presets: STYLE_PRESETS.slice(3),
|
||||
},
|
||||
];
|
||||
|
||||
const FOLDER_THEME_COVER = "/images/canvas/folder-default-cover.png";
|
||||
|
||||
const SAMPLE_MEDIA = [
|
||||
"/short-drama-styles/fantasy-3d.jpg",
|
||||
"/short-drama-styles/suspense-noir.jpg",
|
||||
@@ -40,12 +58,12 @@ function makeFolderNode(style: CanvasFolderStyle, index: number): CanvasNodeData
|
||||
return {
|
||||
id: `folder-${style}`,
|
||||
type: CanvasNodeType.Frame,
|
||||
title: ["我的素材", "项目资料", "视觉档案", "灵感收藏", "影像资产", "快速调用"][index],
|
||||
title: ["My Files", "Archives", "My Files", "灵感收藏", "影像资产", "快速调用"][index],
|
||||
position: { x: 0, y: 0 },
|
||||
width: 360,
|
||||
height: 280,
|
||||
metadata: {
|
||||
folder: { style, createdAt: new Date(2026, 7, 19 + index).toISOString() },
|
||||
folder: { style, createdAt: new Date(2026, 7, 19 + index).toISOString(), themeCover: FOLDER_THEME_COVER },
|
||||
frame: { collapsed: true, expandedWidth: 760, expandedHeight: 520 },
|
||||
},
|
||||
};
|
||||
@@ -63,9 +81,11 @@ const INITIAL_CHILDREN = Object.fromEntries(
|
||||
) as Record<string, CanvasNodeData[]>;
|
||||
|
||||
export default function FolderPreviewLab() {
|
||||
const theme = useThemeStore((state) => state.theme);
|
||||
const setTheme = useThemeStore((state) => state.setTheme);
|
||||
const [folders, setFolders] = useState(INITIAL_FOLDERS);
|
||||
const [childrenByFolder, setChildrenByFolder] = useState(INITIAL_CHILDREN);
|
||||
const [selectedId, setSelectedId] = useState(INITIAL_FOLDERS[0].id);
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
const [openedId, setOpenedId] = useState<string | null>(null);
|
||||
const openedFolder = useMemo(() => folders.find((folder) => folder.id === openedId), [folders, openedId]);
|
||||
const openedChildren = openedId ? childrenByFolder[openedId] || [] : [];
|
||||
@@ -95,64 +115,82 @@ export default function FolderPreviewLab() {
|
||||
<div>
|
||||
<span className="folder-preview-lab-kicker">DEV · INTERACTIVE FOLDER LAB</span>
|
||||
<h1>通用素材文件夹</h1>
|
||||
<p>悬停查看动效,单击选中,双击打开;标题和右上角菜单都可以直接操作。</p>
|
||||
<p>红蓝抽象图只作为文件夹主题皮肤;打开文件夹后,内部素材以独立内容卡片展示。悬停、单击和双击都有对应反馈。</p>
|
||||
</div>
|
||||
<div className="folder-preview-lab-guide">
|
||||
<MousePointer2 aria-hidden />
|
||||
<span>试试 hover、双击与样式切换</span>
|
||||
<div className="folder-preview-lab-controls">
|
||||
<div className="folder-preview-lab-theme" aria-label="预览主题">
|
||||
<button type="button" aria-pressed={theme === "light"} onClick={() => setTheme("light")}>
|
||||
<Sun aria-hidden /> 浅色
|
||||
</button>
|
||||
<button type="button" aria-pressed={theme === "dark"} onClick={() => setTheme("dark")}>
|
||||
<Moon aria-hidden /> 深色
|
||||
</button>
|
||||
</div>
|
||||
<div className="folder-preview-lab-guide">
|
||||
<MousePointer2 aria-hidden />
|
||||
<span>试试 hover、双击与样式切换</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section className="folder-preview-lab-grid" aria-label="文件夹样式预览">
|
||||
{folders.map((folder, index) => {
|
||||
const preset = STYLE_PRESETS[index];
|
||||
const childNodes = childrenByFolder[folder.id] || [];
|
||||
return (
|
||||
<article key={folder.id} className="folder-preview-lab-item">
|
||||
<div className="folder-preview-lab-item-copy">
|
||||
<strong>{preset.name}</strong>
|
||||
<span>{preset.hint}</span>
|
||||
</div>
|
||||
<div
|
||||
className="folder-preview-lab-folder"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`打开 ${folder.title}`}
|
||||
onClick={() => setSelectedId(folder.id)}
|
||||
onDoubleClick={() => setOpenedId(folder.id)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
setOpenedId(folder.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CanvasFolderPreview
|
||||
data={folder}
|
||||
childNodes={childNodes}
|
||||
active={selectedId === folder.id}
|
||||
isDropTarget={false}
|
||||
readOnly={false}
|
||||
onToggleCollapsed={setOpenedId}
|
||||
onTitleChange={(nodeId, title) => updateFolder(nodeId, (current) => ({ ...current, title }))}
|
||||
onStyleChange={(nodeId, style) =>
|
||||
updateFolder(nodeId, (current) => ({
|
||||
...current,
|
||||
metadata: {
|
||||
...current.metadata,
|
||||
folder: { ...current.metadata!.folder!, style },
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<button type="button" className="folder-preview-lab-open" onClick={() => setOpenedId(folder.id)}>
|
||||
<FolderOpen aria-hidden /> 打开文件夹
|
||||
</button>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</section>
|
||||
{PRESET_GROUPS.map((group) => (
|
||||
<section key={group.key} className="folder-preview-lab-section" aria-labelledby={`folder-preview-${group.key}`}>
|
||||
<div className="folder-preview-lab-section-heading">
|
||||
<h2 id={`folder-preview-${group.key}`}>{group.title}</h2>
|
||||
<p>{group.description}</p>
|
||||
</div>
|
||||
<div className="folder-preview-lab-grid">
|
||||
{group.presets.map((preset) => {
|
||||
const folder = folders.find((item) => item.id === `folder-${preset.style}`)!;
|
||||
const childNodes = childrenByFolder[folder.id] || [];
|
||||
return (
|
||||
<article key={folder.id} className="folder-preview-lab-item">
|
||||
<div className="folder-preview-lab-item-copy">
|
||||
<strong>{preset.name}</strong>
|
||||
<span>{preset.hint}</span>
|
||||
</div>
|
||||
<div
|
||||
className="folder-preview-lab-folder"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`打开 ${folder.title}`}
|
||||
onClick={() => setSelectedId(folder.id)}
|
||||
onDoubleClick={() => setOpenedId(folder.id)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
setOpenedId(folder.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CanvasFolderPreview
|
||||
data={folder}
|
||||
childNodes={childNodes}
|
||||
active={selectedId === folder.id}
|
||||
isDropTarget={false}
|
||||
readOnly={false}
|
||||
onToggleCollapsed={setOpenedId}
|
||||
onTitleChange={(nodeId, title) => updateFolder(nodeId, (current) => ({ ...current, title }))}
|
||||
onStyleChange={(nodeId, style) =>
|
||||
updateFolder(nodeId, (current) => ({
|
||||
...current,
|
||||
metadata: {
|
||||
...current.metadata,
|
||||
folder: { ...current.metadata!.folder!, style },
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<button type="button" className="folder-preview-lab-open" onClick={() => setOpenedId(folder.id)}>
|
||||
<FolderOpen aria-hidden /> 打开文件夹
|
||||
</button>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
|
||||
{openedFolder ? (
|
||||
<section className="folder-preview-lab-drawer" aria-label={`${openedFolder.title} 内容`}>
|
||||
|
||||
@@ -6021,6 +6021,7 @@
|
||||
}
|
||||
|
||||
.canvas-folder-preview {
|
||||
--canvas-folder-front-shape: path("M 28 58 H 112 C 126 58 135 62 144 70 L 174 96 C 182 104 191 108 204 108 H 332 C 348 108 360 120 360 136 V 252 C 360 268 348 280 332 280 H 28 C 12 280 0 268 0 252 V 86 C 0 70 12 58 28 58 Z");
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -6062,11 +6063,14 @@
|
||||
|
||||
.canvas-folder-back,
|
||||
.canvas-folder-front,
|
||||
.canvas-folder-preview-card {
|
||||
.canvas-folder-preview-card,
|
||||
.canvas-folder-paper-sheet {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.canvas-folder-paper-sheet { display: none; }
|
||||
|
||||
.canvas-folder-back {
|
||||
z-index: 1;
|
||||
inset: 0;
|
||||
@@ -6125,7 +6129,7 @@
|
||||
inset: 0;
|
||||
border-radius: var(--r-5xl);
|
||||
box-shadow: inset 0 0 0 2px var(--canvas-folder-edge);
|
||||
clip-path: path("M 28 58 H 112 C 126 58 135 62 144 70 L 174 96 C 182 104 191 108 204 108 H 332 C 348 108 360 120 360 136 V 252 C 360 268 348 280 332 280 H 28 C 12 280 0 268 0 252 V 86 C 0 70 12 58 28 58 Z");
|
||||
clip-path: var(--canvas-folder-front-shape);
|
||||
backdrop-filter: blur(24px) saturate(118%);
|
||||
transition: transform var(--motion-state) var(--motion-ease-out);
|
||||
}
|
||||
@@ -6232,7 +6236,7 @@
|
||||
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--canvas-folder-action-fg) 22%, transparent), 0 12px 26px color-mix(in srgb, var(--cn-spatial-shadow) 52%, transparent);
|
||||
}
|
||||
|
||||
.canvas-folder-add > svg { width: 34px; height: 34px; stroke-width: 1.5; }
|
||||
.canvas-folder-add > svg { width: 34px; height: 34px; color: var(--canvas-folder-action-fg); stroke: currentColor; stroke-width: 1.5; }
|
||||
|
||||
.canvas-folder-options {
|
||||
width: 66px;
|
||||
@@ -6292,30 +6296,158 @@
|
||||
.canvas-folder-file-icon { position: absolute; inset: 0; width: 36px; height: 36px; margin: auto; opacity: .42; }
|
||||
.canvas-folder-file-sheet { display: block; width: 100%; height: 100%; background: var(--canvas-folder-surface-strong); }
|
||||
|
||||
/* 三个参考态。stacked 露出内容卡;midnight 把标题压进深色封面标签。 */
|
||||
/* 三个参考态严格保留各自材质:玻璃磨砂、白纸层叠、红黑夜间封面。 */
|
||||
.canvas-folder-preview-glass {
|
||||
--canvas-folder-front-shape: path("M 28 70 H 112 C 126 70 136 74 146 82 L 174 104 C 183 112 192 116 205 116 H 332 C 348 116 360 128 360 144 V 252 C 360 268 348 280 332 280 H 28 C 12 280 0 268 0 252 V 98 C 0 82 12 70 28 70 Z");
|
||||
--canvas-folder-surface: rgba(248, 249, 251, .62);
|
||||
--canvas-folder-surface-strong: rgba(251, 252, 253, .9);
|
||||
--canvas-folder-edge: rgba(255, 255, 255, .78);
|
||||
--canvas-folder-ink: #17181b;
|
||||
--canvas-folder-muted: rgba(23, 24, 27, .54);
|
||||
--canvas-folder-action-bg: rgba(8, 9, 11, .94);
|
||||
--canvas-folder-action-fg: #fff;
|
||||
}
|
||||
|
||||
.canvas-folder-preview-glass .canvas-folder-front-media { opacity: .66; }
|
||||
.canvas-folder-preview-glass .canvas-folder-front-tint { background: rgba(249, 250, 252, .56); }
|
||||
.canvas-folder-preview-glass .canvas-folder-front {
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .74), 0 18px 34px rgba(12, 18, 28, .12);
|
||||
backdrop-filter: blur(28px) saturate(124%);
|
||||
}
|
||||
|
||||
.dark .canvas-folder-preview-glass {
|
||||
--canvas-folder-surface: rgba(10, 12, 16, .54);
|
||||
--canvas-folder-surface-strong: rgba(13, 15, 20, .82);
|
||||
--canvas-folder-edge: rgba(255, 255, 255, .2);
|
||||
--canvas-folder-ink: rgba(255, 255, 255, .96);
|
||||
--canvas-folder-muted: rgba(255, 255, 255, .58);
|
||||
--canvas-folder-action-bg: rgba(246, 247, 249, .94);
|
||||
--canvas-folder-action-fg: #111318;
|
||||
}
|
||||
|
||||
.dark .canvas-folder-preview-glass .canvas-folder-front-media { opacity: .78; }
|
||||
.dark .canvas-folder-preview-glass .canvas-folder-front-tint { background: rgba(7, 9, 13, .5); }
|
||||
.dark .canvas-folder-preview-glass .canvas-folder-front {
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .18), 0 22px 42px rgba(0, 0, 0, .42);
|
||||
}
|
||||
|
||||
.canvas-folder-preview-glass .canvas-folder-preview-stack,
|
||||
.canvas-folder-preview-midnight .canvas-folder-preview-stack,
|
||||
.canvas-folder-preview-cinema .canvas-folder-preview-stack { opacity: 0; }
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-back,
|
||||
.canvas-folder-preview-stacked {
|
||||
--canvas-folder-front-shape: path("M 28 116 H 100 C 116 116 126 120 138 130 L 164 150 C 173 158 183 162 196 162 H 332 C 348 162 360 174 360 190 V 252 C 360 268 348 280 332 280 H 28 C 12 280 0 268 0 252 V 144 C 0 128 12 116 28 116 Z");
|
||||
--canvas-folder-surface: rgba(248, 249, 250, .72);
|
||||
--canvas-folder-surface-strong: rgba(255, 255, 255, .94);
|
||||
--canvas-folder-edge: rgba(255, 255, 255, .84);
|
||||
--canvas-folder-ink: #17181b;
|
||||
--canvas-folder-muted: rgba(23, 24, 27, .5);
|
||||
--canvas-folder-action-bg: rgba(235, 237, 240, .78);
|
||||
--canvas-folder-action-fg: #16181b;
|
||||
}
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-back { opacity: 0; }
|
||||
.canvas-folder-preview-stacked .canvas-folder-paper-sheet {
|
||||
z-index: 3;
|
||||
top: 4px;
|
||||
left: 80px;
|
||||
display: block;
|
||||
width: 238px;
|
||||
height: 214px;
|
||||
border-radius: var(--r-4xl);
|
||||
background: rgba(255, 255, 255, .96);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .82), 0 18px 34px rgba(21, 24, 30, .12);
|
||||
}
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-preview-card-1 {
|
||||
top: 52px;
|
||||
left: 16px;
|
||||
width: 178px;
|
||||
height: 154px;
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-preview-card-2 {
|
||||
top: 46px;
|
||||
right: 8px;
|
||||
width: 176px;
|
||||
height: 154px;
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-preview-card-3 { opacity: 0; }
|
||||
.canvas-folder-preview-stacked .canvas-folder-front-media { opacity: .18; }
|
||||
.canvas-folder-preview-stacked .canvas-folder-front-tint { background: rgba(232, 234, 238, .72); }
|
||||
.canvas-folder-preview-stacked .canvas-folder-front {
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .82), 0 20px 38px rgba(21, 24, 30, .14);
|
||||
backdrop-filter: blur(30px) saturate(112%);
|
||||
}
|
||||
|
||||
.dark .canvas-folder-preview-stacked {
|
||||
--canvas-folder-surface: rgba(19, 21, 26, .7);
|
||||
--canvas-folder-surface-strong: rgba(29, 32, 38, .94);
|
||||
--canvas-folder-edge: rgba(255, 255, 255, .18);
|
||||
--canvas-folder-ink: rgba(255, 255, 255, .96);
|
||||
--canvas-folder-muted: rgba(255, 255, 255, .56);
|
||||
--canvas-folder-action-bg: rgba(45, 48, 55, .82);
|
||||
--canvas-folder-action-fg: rgba(255, 255, 255, .94);
|
||||
}
|
||||
|
||||
.dark .canvas-folder-preview-stacked .canvas-folder-paper-sheet {
|
||||
background: rgba(38, 41, 48, .98);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .1), 0 20px 42px rgba(0, 0, 0, .42);
|
||||
}
|
||||
|
||||
.dark .canvas-folder-preview-stacked .canvas-folder-front-tint { background: rgba(17, 19, 24, .72); }
|
||||
.dark .canvas-folder-preview-stacked .canvas-folder-front {
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .14), 0 22px 42px rgba(0, 0, 0, .46);
|
||||
}
|
||||
|
||||
.canvas-folder-preview-paper .canvas-folder-back,
|
||||
.canvas-folder-preview-compact .canvas-folder-back { background: var(--canvas-folder-surface-strong); }
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-front-media,
|
||||
.canvas-folder-preview-paper .canvas-folder-front-media,
|
||||
.canvas-folder-preview-compact .canvas-folder-front-media { opacity: .24; }
|
||||
|
||||
.canvas-folder-preview-stacked .canvas-folder-copy,
|
||||
.canvas-folder-preview-stacked .canvas-folder-copy { top: 142px; bottom: auto; }
|
||||
.canvas-folder-preview-paper .canvas-folder-copy { top: 132px; bottom: auto; }
|
||||
|
||||
.canvas-folder-preview-midnight,
|
||||
.canvas-folder-preview-cinema { --canvas-folder-ink: rgba(255, 255, 255, .96); --canvas-folder-muted: rgba(255, 255, 255, .58); --canvas-folder-edge: rgba(255, 255, 255, .19); --canvas-folder-surface: rgba(4, 5, 7, .78); --canvas-folder-surface-strong: rgba(8, 9, 12, .9); }
|
||||
.canvas-folder-preview-cinema {
|
||||
--canvas-folder-ink: rgba(255, 255, 255, .96);
|
||||
--canvas-folder-muted: rgba(255, 255, 255, .58);
|
||||
--canvas-folder-edge: rgba(255, 255, 255, .19);
|
||||
--canvas-folder-surface: rgba(4, 5, 8, .7);
|
||||
--canvas-folder-surface-strong: rgba(7, 8, 12, .9);
|
||||
--canvas-folder-action-bg: rgba(5, 6, 9, .88);
|
||||
--canvas-folder-action-fg: rgba(255, 255, 255, .96);
|
||||
}
|
||||
.canvas-folder-preview-midnight {
|
||||
--canvas-folder-front-shape: path("M 28 116 H 118 C 134 116 145 121 157 132 L 180 151 C 189 159 198 162 211 162 H 332 C 348 162 360 174 360 190 V 252 C 360 268 348 280 332 280 H 28 C 12 280 0 268 0 252 V 144 C 0 128 12 116 28 116 Z");
|
||||
}
|
||||
.canvas-folder-preview-midnight .canvas-folder-back,
|
||||
.canvas-folder-preview-cinema .canvas-folder-back {
|
||||
inset: 0 0 34px;
|
||||
border-radius: var(--r-5xl);
|
||||
clip-path: none;
|
||||
}
|
||||
.canvas-folder-preview-midnight .canvas-folder-copy,
|
||||
.canvas-folder-preview-cinema .canvas-folder-copy { top: 142px; right: 34px; bottom: auto; left: auto; max-width: 170px; }
|
||||
.canvas-folder-preview-midnight .canvas-folder-front-media,
|
||||
.canvas-folder-preview-cinema .canvas-folder-front-media { opacity: .78; }
|
||||
.canvas-folder-preview-cinema .canvas-folder-front-media { opacity: .72; }
|
||||
.canvas-folder-preview-midnight .canvas-folder-front-tint,
|
||||
.canvas-folder-preview-cinema .canvas-folder-front-tint { background: color-mix(in srgb, var(--canvas-folder-surface) 88%, transparent); }
|
||||
.canvas-folder-preview-cinema .canvas-folder-front-tint { background: rgba(4, 5, 8, .7); }
|
||||
.canvas-folder-preview-midnight .canvas-folder-front,
|
||||
.canvas-folder-preview-cinema .canvas-folder-front {
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .15), 0 24px 48px rgba(0, 0, 0, .44);
|
||||
backdrop-filter: blur(30px) saturate(118%);
|
||||
}
|
||||
|
||||
.dark .canvas-folder-preview-midnight .canvas-folder-front-tint { background: rgba(2, 3, 6, .78); }
|
||||
.dark .canvas-folder-preview-midnight .canvas-folder-front-media { opacity: .82; }
|
||||
|
||||
.canvas-folder-preview-glass .canvas-folder-meta,
|
||||
.canvas-folder-preview-stacked .canvas-folder-meta { display: none; }
|
||||
|
||||
.canvas-folder-preview-paper { --canvas-folder-surface: color-mix(in srgb, var(--background) 88%, transparent); }
|
||||
.canvas-folder-preview-cinema { filter: drop-shadow(0 28px 32px color-mix(in srgb, var(--cn-spatial-shadow) 72%, transparent)); }
|
||||
|
||||
@@ -287,6 +287,7 @@ export type CanvasNodeMetadata = {
|
||||
folder?: {
|
||||
style: CanvasFolderStyle;
|
||||
createdAt: string;
|
||||
themeCover?: string;
|
||||
assetFolderId?: string;
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user