diff --git a/src/features/canvas/CanvasPage.tsx b/src/features/canvas/CanvasPage.tsx
index 28b3089..9306ec3 100644
--- a/src/features/canvas/CanvasPage.tsx
+++ b/src/features/canvas/CanvasPage.tsx
@@ -26,7 +26,6 @@
VideoCameraOutlined,
} from "@ant-design/icons";
import {
- Background,
ReactFlow,
} from "@xyflow/react";
import { useCallback, useEffect, useMemo, useRef, useState, type ChangeEvent, type CSSProperties, type MouseEvent, type WheelEvent } from "react";
@@ -3560,7 +3559,8 @@ function CanvasPage({
onMouseMove={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handleCanvasMouseMove}
onWheel={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handleCanvasWheel}
style={{
- "--canvas-bg-size": `${24 * canvasViewport.zoom}px`,
+ "--canvas-bg-size": `${34 * canvasViewport.zoom}px`,
+ "--canvas-bg-dot": `${1.35 * canvasViewport.zoom}px`,
"--canvas-bg-x": `${canvasViewport.x}px`,
"--canvas-bg-y": `${canvasViewport.y}px`,
cursor: canvasPanDrag ? "grabbing" : spacePanning ? "grab" : undefined,
@@ -3748,9 +3748,7 @@ function CanvasPage({
proOptions={{ hideAttribution: true }}
onPaneClick={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handlePaneClick}
onPaneContextMenu={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handlePaneContextMenu}
- >
-
-
+ />
e.stopPropagation()}>
);
+ const renderCardPreview = (
+ url: string | null | undefined,
+ type: "image" | "video" | "project" | "asset",
+ label: string,
+ ) => {
+ const mediaUrl = typeof url === "string" ? url.trim() : "";
+ const isVideoPreview = type === "video" || /\.(mp4|webm|mov)(\?|#|$)/i.test(mediaUrl);
+ const placeholderIcon =
+ type === "video" ? : type === "project" ? : ;
+
+ return (
+
+ {mediaUrl ? (
+ isVideoPreview ? (
+
+ ) : (
+

+ )
+ ) : (
+
{placeholderIcon}
+ )}
+
{label}
+
+ );
+ };
+
const renderActivePanel = () => {
if (activePanel === "works") {
return visibleWorks.length ? (
{visibleWorks.map((task) => (
-
-
- {task.title}
- {formatTaskType(task.type)}
-
- {task.prompt}
-
-
{formatTaskStatus(task.status)}
-
{formatProfileDate(task.createdAt)}
+
+ {renderCardPreview(task.outputUrl, task.type === "video" ? "video" : "image", formatTaskType(task.type))}
+
+
+ {task.title}
+
+
{task.prompt}
+
+ {formatTaskStatus(task.status)}
+ {formatProfileDate(task.createdAt)}
+
))}
@@ -637,25 +681,27 @@ function ProfilePage({
return projects.length ? (
{projects.map((project) => (
-
-
- {project.name}
- {formatProfileDate(project.updatedAt)}
- {onDeleteProject ? (
-
- ) : null}
-
- {project.description || "最近更新的项目"}
-
-
{project.storyboardCount} 节点
-
{project.imageCount} 图 / {project.videoCount} 视频
+
+ {renderCardPreview(project.thumbnailUrl, "project", "项目")}
+
+
+ {project.name}
+ {onDeleteProject ? (
+
+ ) : null}
+
+
{project.description || "最近更新的项目"}
+
+ {project.storyboardCount} 节点
+ {formatProfileDate(project.updatedAt)}
+
))}
@@ -669,15 +715,18 @@ function ProfilePage({
return savedAssets.length ? (
{savedAssets.map((asset) => (
-
-
- {asset.name}
- {formatAssetStatus(asset.status)}
-
- {asset.description}
-
-
{asset.type}
-
{formatProfileDate(asset.updatedAt)}
+
+ {renderCardPreview(asset.imageUrl || asset.url, asset.type === "video" ? "video" : "asset", formatAssetType(asset.type))}
+
+
+ {asset.name}
+ {formatAssetStatus(asset.status)}
+
+
{asset.description}
+
+ {formatAssetType(asset.type)}
+ {formatProfileDate(asset.updatedAt)}
+
))}
@@ -791,6 +840,50 @@ function ProfilePage({
+
+
+
+
+
+
+ {accountPanel === "credits" ? (
+ <>
+
+ 当前账号
+ {displayName}
+
+
+ 积分剩余
+ {(usage.balanceCents / 100).toFixed(2)}
+
+ >
+ ) : (
+ <>
+
+ 任务总数
+ {tasks.length}
+
+
+ 已完成
+ {completedTasks.length}
+
+ >
+ )}
+
+
+
-
-
-
-
-
-
-
-
-
- {accountPanel === "credits" ? (
- <>
-
- 当前账号
- {displayName}
-
-
- 积分剩余
- {(usage.balanceCents / 100).toFixed(2)}
-
- >
- ) : (
- <>
-
- 任务总数
- {tasks.length}
-
-
- 已完成
- {completedTasks.length}
-
- >
- )}
-
-
diff --git a/src/features/script-tokens/ScriptTokensPage.tsx b/src/features/script-tokens/ScriptTokensPage.tsx
index 10e4e6b..c59cbb0 100644
--- a/src/features/script-tokens/ScriptTokensPage.tsx
+++ b/src/features/script-tokens/ScriptTokensPage.tsx
@@ -405,111 +405,113 @@ function ScriptTokensPage() {
{/* Left Panel */}