2 Commits

Author SHA1 Message Date
c805012adc feat: restyle workbench with glassmorphism shell 2026-05-21 10:37:54 +08:00
536b4d7f59 auto-save 2026-05-21 02:09 (~2) 2026-05-21 02:09:07 +08:00
5 changed files with 2620 additions and 2440 deletions

View File

@@ -1,6 +1,6 @@
# 项目接力
- 生成时间May 20, 2026 at 16:25
- 生成时间May 21, 2026 at 02:06
- 项目SKG Marketing Studio / SKG 营销内容工作台
- 路径:/Users/kangwan/Projects/business/20260512-20260512-skg-tk-二创验证
- 状态active
@@ -9,7 +9,7 @@
## 最近助手会话概览
- Claudea9e0449c-d9cb-4a2a-bb16-16596dfb552a · 时间未知
- Codex019e3db1-012e-7163-bc78-acf7cde326e7 · 时间未知
- Codex019e447d-68c7-7db1-a499-b5eb6a98a7c2 · 时间未知
- Cursor未找到匹配当前项目的最近会话
## Claude 最近会话
@@ -92,27 +92,42 @@
## Codex 最近会话
- Session ID019e3db1-012e-7163-bc78-acf7cde326e7
- Transcript/Users/kangwan/.codex/sessions/2026/05/19/rollout-2026-05-19T08-44-30-019e3db1-012e-7163-bc78-acf7cde326e7.jsonl
- Session ID019e447d-68c7-7db1-a499-b5eb6a98a7c2
- Transcript/Users/kangwan/.codex/sessions/2026/05/20/rollout-2026-05-20T16-25-30-019e447d-68c7-7db1-a499-b5eb6a98a7c2.jsonl
- 工作目录:/Users/kangwan/Projects/business/20260512-20260512-skg-tk-二创验证
- 分支main
- 敏感字段:已对 token / key / password / secret 做脱敏
### 最近用户要求
-之前的案例呢 我更新一次就清空了么
- 怎么避免这样的事情出现,我都快炸了
- 我要开新的窗口 继续这个项目了 你帮我打开
-看的没改变呀 我感觉这个已经彻底调整崩了
- figma mcp是通的么
- 连一些被 我都打开
### Codex 最近回复
> 这个旧路径不存在,我查一下当前机器上工作看板实际装在哪里,然后打开它
> 现在命令行访问本机端口被沙箱拦了一次,`nc` 明确返回 `Operation not permitted`。我用已授权外部执行再测一次这样能区分“Figma 没开”和“Codex 沙箱不让连本地端口”
> 打开工作看板
> 连上本地 Figma Desktop MCP
>
> 新窗口继续这个项目时,项目根目录用
> 我做了这些验证
>
> `/Users/kangwan/Projects/business/20260512-20260512-skg-tk-二创验证`
> - Figma 桌面端已打开 Design 文件,并显示 `MCP server enabled on http://127.0.0.1:3845/mcp`
> - 本机端口确认监听:`Figma ... 127.0.0.1:3845 (LISTEN)`
> - MCP `initialize` 成功返回:`Figma Dev Mode MCP Server 1.0.0`
> - 工具列表可用:`get_design_context`、`get_screenshot`、`get_metadata`、`get_variable_defs`
> - 实际调用 `get_metadata` 成功,返回当前文件页面:`0:1: Page 1`
>
> 注意:官方远程 `figma` 那条还没通,因为当前环境没有 `FIGMA_OAUTH_TOKEN``codex mcp login figma` 也返回了 `invalid_redirect_uri`。但本地 `figma-desktop` 这条已经能用。Figma 官方文档也是这个流程:打开桌面端 Design 文件,启用本地 MCP然后配置 `http://127.0.0.1:3845/mcp`。
>
> 当前仓库没改代码,状态还是:
>
> ```text
> ## main...origin/main
> M .memory/worklog.json
> ```
>
> 来源Figma 官方 Codex MCP 设置文档 https://help.figma.com/hc/en-us/articles/39888629089175-Codex-and-Figma-Set-up-the-MCP-server
## Cursor 最近会话

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -469,29 +469,33 @@ nextjs-portal {
信息流工作台 · 登录页同源质感
============================================================ */
.skg-board-theme {
--skg-gold-1: #d6b36a;
--skg-gold-2: #c89b3c;
--skg-cream: #f5efe3;
--skg-bg-1: #0a0a0a;
--skg-bg-2: #111111;
--skg-bg-3: rgba(255, 255, 255, 0.035);
--skg-border: rgba(255, 255, 255, 0.1);
--skg-gold-1: #c8cd19;
--skg-gold-2: #a2c638;
--skg-cream: #f6f6ee;
--skg-bg-1: #1b1b1b;
--skg-bg-2: #242424;
--skg-bg-3: rgba(255, 255, 255, 0.1);
--skg-border: rgba(255, 255, 255, 0.14);
--skg-text-1: #ffffff;
--skg-text-2: rgba(255, 255, 255, 0.62);
--skg-text-3: rgba(255, 255, 255, 0.34);
--skg-success: #34d399;
--skg-warn: #fcd34d;
--skg-text-2: rgba(255, 255, 255, 0.56);
--skg-text-3: rgba(255, 255, 255, 0.36);
--skg-success: #a2c638;
--skg-warn: #c8cd19;
--skg-danger: #fb7185;
--skg-info: #67e8f9;
--skg-info: #a6d533;
--skg-radius-sm: 6px;
--skg-radius-md: 8px;
--skg-radius-lg: 12px;
--skg-shadow-button: 0 6px 24px -8px rgba(0, 0, 0, 0.45);
--skg-radius-lg: 20px;
--skg-shadow-button: 10px 10px 10px rgba(0, 0, 0, 0.3);
--skg-shadow-card: 10px 10px 10px rgba(0, 0, 0, 0.3);
--skg-glass-bg: rgba(255, 255, 255, 0.1);
--skg-glass-bg-soft: rgba(255, 255, 255, 0.055);
--skg-rail: #383838;
color: var(--skg-text-1);
background:
radial-gradient(circle at 52% 4%, rgba(214, 179, 106, 0.1), transparent 30%),
radial-gradient(circle at 12% 96%, rgba(214, 179, 106, 0.065), transparent 34%),
linear-gradient(120deg, #0a0a0a 0%, #10100f 46%, #050505 100%);
radial-gradient(circle at 20% 18%, rgba(162, 198, 56, 0.11), transparent 28%),
radial-gradient(circle at 86% 78%, rgba(200, 205, 25, 0.12), transparent 28%),
linear-gradient(120deg, #202020 0%, #242424 48%, #171717 100%);
}
.skg-board-theme::before {
@@ -501,10 +505,10 @@ nextjs-portal {
z-index: 0;
pointer-events: none;
background:
linear-gradient(90deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px),
linear-gradient(180deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px);
background-size: 64px 64px;
opacity: 0.44;
linear-gradient(90deg, rgba(255, 255, 255, 0.018) 1px, transparent 1px),
linear-gradient(180deg, rgba(255, 255, 255, 0.016) 1px, transparent 1px);
background-size: 56px 56px;
opacity: 0.34;
}
.skg-board-theme::after {
@@ -514,39 +518,38 @@ nextjs-portal {
z-index: 0;
pointer-events: none;
background:
linear-gradient(180deg, rgba(0, 0, 0, 0.22), transparent 42%, rgba(0, 0, 0, 0.4)),
linear-gradient(90deg, rgba(0, 0, 0, 0.28), transparent 38%, rgba(0, 0, 0, 0.24));
linear-gradient(180deg, rgba(0, 0, 0, 0.18), transparent 45%, rgba(0, 0, 0, 0.38)),
linear-gradient(90deg, rgba(0, 0, 0, 0.34), transparent 36%, rgba(0, 0, 0, 0.2));
}
.skg-board-ambient {
background:
radial-gradient(circle at 78% 0%, rgba(232, 201, 122, 0.08), transparent 30%),
radial-gradient(circle at 8% 100%, rgba(214, 179, 106, 0.06), transparent 34%);
radial-gradient(circle at 72% 12%, rgba(162, 198, 56, 0.13), transparent 28%),
radial-gradient(circle at 18% 92%, rgba(200, 205, 25, 0.12), transparent 32%);
}
.skg-board-topbar,
.skg-board-panel {
border-color: var(--skg-border) !important;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.022)),
rgba(17, 17, 17, 0.74) !important;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.06),
0 18px 54px rgba(0, 0, 0, 0.34);
backdrop-filter: blur(10px);
radial-gradient(circle at 88% 22%, rgba(162, 198, 56, 0.08), transparent 38%),
linear-gradient(180deg, rgba(255, 255, 255, 0.105), rgba(255, 255, 255, 0.052)),
rgba(36, 36, 36, 0.68) !important;
box-shadow: var(--skg-shadow-card);
backdrop-filter: blur(5px);
}
.skg-board-topbar {
background:
linear-gradient(100deg, rgba(214, 179, 106, 0.075), rgba(255, 255, 255, 0.03) 54%, rgba(214, 179, 106, 0.035)),
rgba(12, 12, 12, 0.76) !important;
linear-gradient(100deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.045) 58%, rgba(162, 198, 56, 0.08)),
rgba(38, 38, 38, 0.72) !important;
}
.skg-board-theme input:focus,
.skg-board-theme textarea:focus,
.skg-board-theme select:focus {
border-color: rgba(214, 179, 106, 0.58) !important;
box-shadow: 0 0 0 2px rgba(214, 179, 106, 0.14);
box-shadow: 0 0 0 2px rgba(162, 198, 56, 0.18);
}
.skg-board-theme input[type="checkbox"] {
@@ -558,6 +561,80 @@ nextjs-portal {
color: #fff;
}
.skg-board-shell {
min-height: calc(100vh - 32px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 24px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.032), rgba(255, 255, 255, 0.012)),
rgba(26, 26, 26, 0.58);
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.38);
backdrop-filter: blur(8px);
}
.skg-board-rail {
width: 65px;
min-height: 514px;
border: 1px solid #383838;
border-radius: 0 70px 70px 0;
background: #383838;
box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.3);
}
.skg-board-rail__logo {
border: 2px solid rgba(255, 255, 255, 0.2);
background:
radial-gradient(circle at 68% 38%, #a2c638 0 34%, transparent 36%),
radial-gradient(circle at 50% 50%, #c8cd19 0 47%, transparent 49%),
#ffffff;
color: #ffffff;
}
.skg-board-rail__button {
color: rgba(255, 255, 255, 0.52);
transition: color 180ms ease, background 180ms ease, transform 180ms ease;
}
.skg-board-rail__button:hover,
.skg-board-rail__button:focus-visible,
.skg-board-rail__button.is-active {
color: #ffffff;
background: rgba(255, 255, 255, 0.08);
transform: translateX(2px);
}
.skg-glass-card {
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 20px;
background:
radial-gradient(circle at 80% 86%, rgba(162, 198, 56, 0.18), transparent 36%),
linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.052)),
rgba(56, 56, 56, 0.62);
box-shadow: var(--skg-shadow-card);
backdrop-filter: blur(5px);
}
.skg-glass-card--flat {
border-radius: 16px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.035)),
rgba(24, 24, 24, 0.52);
}
.skg-status-orb {
display: inline-flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
border: 5px solid rgba(255, 255, 255, 0.2);
border-radius: 999px;
background:
radial-gradient(circle at 78% 32%, #a2c638 0 12%, transparent 13%),
conic-gradient(from 40deg, #a2c638 0 74%, rgba(255, 255, 255, 0.22) 75% 100%);
color: #ffffff;
}
.skg-board-theme--light {
--skg-bg-1: #faf8f4;
--skg-bg-2: #ffffff;
@@ -748,43 +825,46 @@ nextjs-portal {
}
.skg-stat-card {
border: 1px solid rgba(214, 179, 106, 0.18);
border-radius: var(--skg-radius-md);
background: var(--skg-cream);
color: #0a0a0a;
box-shadow: var(--skg-shadow-button);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 12px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.045)),
rgba(0, 0, 0, 0.16);
color: #ffffff;
box-shadow: 8px 8px 10px rgba(0, 0, 0, 0.22);
backdrop-filter: blur(5px);
}
.skg-stat-card__label {
color: rgba(0, 0, 0, 0.5);
color: rgba(255, 255, 255, 0.48);
}
.skg-stat-card__value {
color: #0a0a0a;
color: #ffffff;
}
.skg-primary-action {
border-radius: var(--skg-radius-md);
background: #f5efe3;
color: #0a0a0a;
background: linear-gradient(135deg, #c8cd19, #a2c638);
color: #101010;
box-shadow: var(--skg-shadow-button);
}
.skg-primary-action:hover {
background: #fff7df;
background: linear-gradient(135deg, #d6db25, #b0d83d);
}
.skg-secondary-action {
border: 1px solid rgba(214, 179, 106, 0.3);
border: 1px solid rgba(255, 255, 255, 0.13);
border-radius: var(--skg-radius-md);
background: rgba(214, 179, 106, 0.08);
color: var(--skg-gold-1);
background: rgba(255, 255, 255, 0.06);
color: rgba(255, 255, 255, 0.76);
}
.skg-secondary-action:hover {
border-color: rgba(214, 179, 106, 0.54);
background: rgba(214, 179, 106, 0.12);
color: #f5d98e;
border-color: rgba(162, 198, 56, 0.44);
background: rgba(162, 198, 56, 0.11);
color: #ffffff;
}
.skg-empty-state {

View File

@@ -2476,48 +2476,42 @@ export function AdRecreationBoard({
return (
<section className={`skg-board-theme ${boardTheme === "light" ? "skg-board-theme--light" : ""} relative z-20 min-h-screen w-full overflow-auto bg-black text-white`}>
<div className="skg-board-ambient pointer-events-none fixed inset-0" />
<div className="relative z-10 mx-auto flex min-h-screen w-full min-w-[1280px] max-w-[1920px] flex-col px-4 py-4 xl:px-5">
<header className="skg-board-topbar mb-3 flex items-center justify-between gap-4 rounded-lg border border-white/10 bg-white/[0.04] px-4 py-3">
<div className="skg-board-brand">
<div className="skg-board-brand__logo-chip" aria-hidden="true">
<img className="skg-board-brand__logo" src="/skg-logo-black.svg" alt="" />
</div>
<div className="relative z-10 mx-auto min-h-screen w-full min-w-[1280px] max-w-[1920px] px-4 py-4 xl:px-5">
<div className="skg-board-shell flex gap-4 p-4">
<WorkbenchRail
job={job}
jobsCount={jobs.length}
audioReady={audioReady}
visualReady={visualReady}
subjectAssetCount={subjectAssetCount}
generatedVideoCount={generatedVideos.length}
onOpenLibrary={() => setLibraryOpen(true)}
onToggleTheme={toggleBoardTheme}
boardTheme={boardTheme}
/>
<div className="flex min-w-0 flex-1 flex-col gap-3">
<header className="skg-board-topbar flex items-center justify-between gap-4 rounded-[20px] border border-white/10 bg-white/[0.04] px-4 py-3">
<div className="min-w-0">
<div className="skg-board-brand__system"> · </div>
<h1 className="skg-board-brand__title"> · TK </h1>
<p className="skg-board-brand__subtitle">广线</p>
<div className="flex items-center gap-3">
<span className="skg-status-orb shrink-0 text-[10px] font-semibold">SKG</span>
<div className="min-w-0">
<div className="text-[11px] font-medium uppercase tracking-[0.28em] text-white/40">Marketing Production Console</div>
<h1 className="mt-1 truncate text-[22px] font-semibold leading-tight text-white">广</h1>
</div>
</div>
<div className="flex shrink-0 items-center gap-2">
<button
type="button"
onClick={() => setLibraryOpen(true)}
className="skg-secondary-action inline-flex h-10 items-center gap-1.5 px-3 text-[11px] font-semibold transition"
title="打开全局资源中心"
>
<BookOpen className="h-3.5 w-3.5" />
</button>
<button
type="button"
onClick={toggleBoardTheme}
className="skg-board-theme-toggle skg-secondary-action inline-flex h-10 items-center gap-1.5 px-3 text-[11px] font-semibold transition"
title={boardTheme === "dark" ? "切换到明亮模式" : "切换到暗色模式"}
>
{boardTheme === "dark" ? <Sun className="h-3.5 w-3.5" /> : <Moon className="h-3.5 w-3.5" />}
{boardTheme === "dark" ? "明亮" : "暗色"}
</button>
<div className="grid min-w-[520px] grid-cols-5 gap-2 text-[11px]">
<p className="mt-2 truncate text-[12px] text-white/42"></p>
</div>
<div className="grid min-w-[560px] grid-cols-5 gap-2 text-[11px]">
<Metric label="素材" value={`${jobs.length}`} />
<Metric label="当前" value={shortId(activeJobId)} />
<Metric label="视频" value={job?.video_url ? "ready" : "-"} />
<Metric label="文案段" value={`${transcriptCount}`} />
<Metric label="背景音" value={backgroundReady ? "ready" : "-"} />
</div>
</div>
</header>
<div className="grid min-h-0 flex-1 grid-cols-[320px_minmax(0,1fr)] gap-3">
<div className="grid min-h-0 flex-1 grid-cols-[340px_minmax(0,1fr)] gap-3">
<MaterialColumn
data={data}
step={workflow.input}
@@ -2531,12 +2525,12 @@ export function AdRecreationBoard({
onStartProduction={startProduction}
/>
<section className="skg-board-panel flex min-h-0 flex-col rounded-lg border border-white/10 bg-white/[0.035] shadow-2xl">
<section className="skg-board-panel flex min-h-0 flex-col rounded-[20px] border border-white/10 bg-white/[0.035] shadow-2xl">
<header className="shrink-0 border-b border-white/10 p-3">
<div className="flex items-center justify-between gap-4">
<div className="min-w-0">
<div className="flex items-center gap-2">
<span className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-[#d6b36a]/18 bg-[#d6b36a]/10 text-[#f2d58a]"><Mic className="h-3.5 w-3.5" /></span>
<span className="inline-flex h-8 w-8 items-center justify-center rounded-full border border-white/12 bg-white/[0.07] text-[#c8cd19]"><Mic className="h-4 w-4" /></span>
<WorkflowStepBadge step={workflow.source} compact />
<h2 className="text-[15px] font-semibold leading-tight text-white"></h2>
</div>
@@ -2579,6 +2573,8 @@ export function AdRecreationBoard({
</section>
</div>
</div>
</div>
</div>
<LibraryDrawer
open={libraryOpen}
currentJobId={job?.id}
@@ -2589,6 +2585,77 @@ export function AdRecreationBoard({
)
}
function WorkbenchRail({
job,
jobsCount,
audioReady,
visualReady,
subjectAssetCount,
generatedVideoCount,
onOpenLibrary,
onToggleTheme,
boardTheme,
}: {
job: Job | null
jobsCount: number
audioReady: boolean
visualReady: boolean
subjectAssetCount: number
generatedVideoCount: number
onOpenLibrary: () => void
onToggleTheme: () => void
boardTheme: BoardThemeMode
}) {
const railItems = [
{ key: "jobs", label: "素材任务", icon: <Link2 className="h-[18px] w-[18px]" />, active: jobsCount > 0 },
{ key: "source", label: "源视频", icon: <Play className="h-[18px] w-[18px]" />, active: !!job?.video_url },
{ key: "audio", label: "音频文案", icon: <Mic className="h-[18px] w-[18px]" />, active: audioReady },
{ key: "frames", label: "参考帧", icon: <ImageIcon className="h-[18px] w-[18px]" />, active: visualReady },
{ key: "subject", label: "主体套图", icon: <Sparkles className="h-[18px] w-[18px]" />, active: subjectAssetCount > 0 },
{ key: "video", label: "视频候选", icon: <Film className="h-[18px] w-[18px]" />, active: generatedVideoCount > 0 },
]
return (
<aside className="skg-board-rail sticky top-4 flex shrink-0 flex-col items-center py-5" aria-label="工作台导航">
<div className="skg-board-rail__logo mb-8 flex h-9 w-9 items-center justify-center rounded-full text-[12px] font-semibold" title="SKG Marketing Studio">
S
</div>
<nav className="flex flex-1 flex-col items-center gap-4">
{railItems.map((item) => (
<button
key={item.key}
type="button"
className={`skg-board-rail__button inline-flex h-9 w-9 items-center justify-center rounded-full ${item.active ? "is-active" : ""}`}
title={item.label}
aria-label={item.label}
>
{item.icon}
</button>
))}
</nav>
<div className="mt-8 flex flex-col items-center gap-3">
<button
type="button"
onClick={onOpenLibrary}
className="skg-board-rail__button inline-flex h-9 w-9 items-center justify-center rounded-full"
title="资源库"
aria-label="打开资源库"
>
<BookOpen className="h-[18px] w-[18px]" />
</button>
<button
type="button"
onClick={onToggleTheme}
className="skg-board-rail__button inline-flex h-9 w-9 items-center justify-center rounded-full"
title={boardTheme === "dark" ? "切换到明亮模式" : "切换到暗色模式"}
aria-label={boardTheme === "dark" ? "切换到明亮模式" : "切换到暗色模式"}
>
{boardTheme === "dark" ? <Sun className="h-[18px] w-[18px]" /> : <Moon className="h-[18px] w-[18px]" />}
</button>
</div>
</aside>
)
}
function MaterialColumn({
data,
step,
@@ -2616,10 +2683,10 @@ function MaterialColumn({
? job.video_url ? "重新解析" : "重新下载"
: "开始分析"
return (
<section className="skg-board-panel flex min-h-0 flex-col gap-3 rounded-lg border border-white/10 bg-white/[0.035] p-3 shadow-2xl">
<section className="skg-board-panel flex min-h-0 flex-col gap-3 rounded-[20px] border border-white/10 bg-white/[0.035] p-3 shadow-2xl">
<header className="shrink-0 border-b border-white/10 pb-3">
<div className="mb-2 flex items-center gap-2">
<span className="inline-flex h-8 w-8 items-center justify-center rounded-md border border-[#d6b36a]/18 bg-[#d6b36a]/10 text-[#f2d58a]"><Plus className="h-4 w-4" /></span>
<span className="inline-flex h-8 w-8 items-center justify-center rounded-full border border-white/12 bg-white/[0.07] text-[#c8cd19]"><Plus className="h-4 w-4" /></span>
<WorkflowStepBadge step={step} compact />
</div>
<h2 className="text-[15px] font-semibold leading-tight text-white"></h2>
@@ -2632,7 +2699,7 @@ function MaterialColumn({
onChange={(e) => setUrl(e.target.value)}
onKeyDown={(e) => { if (e.key === "Enter") onSubmitUrl() }}
placeholder="粘贴 TK / 信息流视频链接"
className="h-10 min-w-0 flex-1 rounded-md border border-white/10 bg-black/45 px-3 text-[13px] text-white outline-none placeholder:text-white/28 focus:border-[#d6b36a]/60"
className="h-10 min-w-0 flex-1 rounded-md border border-white/10 bg-black/35 px-3 text-[13px] text-white outline-none placeholder:text-white/28 focus:border-[#a2c638]/60"
/>
<button
type="button"
@@ -2909,7 +2976,7 @@ function AudioIntakePanel({
}
return (
<section className="rounded-lg border border-white/10 bg-black/28 p-2.5">
<section className="skg-glass-card border border-white/10 p-3">
<div className="mb-2 flex items-center justify-between gap-3">
<SectionTitle icon={<Film className="h-4 w-4" />} title="源视频工作区" />
<div className="flex items-center gap-2 font-mono text-[11px] text-white/38">
@@ -2930,7 +2997,7 @@ function AudioIntakePanel({
<span className="font-mono text-[11px] text-white/38">{currentTime.toFixed(1)}s</span>
</div>
<div
className="relative mx-auto aspect-[9/16] overflow-hidden rounded-md border border-white/10 bg-black"
className="relative mx-auto aspect-[9/16] overflow-hidden rounded-[20px] border border-white/10 bg-black shadow-[10px_10px_10px_rgba(0,0,0,0.3)]"
style={{ height: SOURCE_VIDEO_HEIGHT }}
>
{job.video_url ? (
@@ -2959,7 +3026,7 @@ function AudioIntakePanel({
onClick={() => void addFrameAtCurrentTime()}
disabled={!job.video_url || !onAddFrame || manualBusy || job.status === "splitting"}
title={`按当前播放位置手动抽帧:${currentTime.toFixed(1)}s`}
className="absolute right-2 top-2 inline-flex h-7 items-center justify-center gap-1 rounded-md border border-emerald-200/30 bg-black/78 px-2 text-[10.5px] font-semibold text-emerald-100 shadow-lg backdrop-blur transition hover:border-emerald-100/65 hover:bg-emerald-300/18 disabled:cursor-not-allowed disabled:opacity-35"
className="absolute right-2 top-2 inline-flex h-7 items-center justify-center gap-1 rounded-md border border-[#a2c638]/35 bg-black/78 px-2 text-[10.5px] font-semibold text-[#e0f5a0] shadow-lg backdrop-blur transition hover:border-[#a2c638]/70 hover:bg-[#a2c638]/18 disabled:cursor-not-allowed disabled:opacity-35"
>
{manualBusy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Plus className="h-3.5 w-3.5" />}
@@ -2976,7 +3043,7 @@ function AudioIntakePanel({
</div>
<div className="min-w-0 space-y-2">
<div className="relative z-40 overflow-visible rounded-md border border-white/10 bg-black/32 p-2">
<div className="skg-glass-card--flat relative z-40 overflow-visible border border-white/10 p-2">
<div className="mb-1 flex items-center justify-end gap-3 text-[10px] text-white/40">
<FilmstripDensityControls
density={filmstripDensity}
@@ -3916,12 +3983,12 @@ function SourceSubjectPipeline({
</button>
</div>
<div
className={`rounded-md border p-1.5 transition ${
className={`skg-glass-card--flat border p-1.5 transition ${
filmstripDragging
? referenceDropActive
? "border-[#d6b36a]/80 bg-[#d6b36a]/12 ring-1 ring-[#d6b36a]/45"
: "border-[#d6b36a]/45 bg-[#d6b36a]/[0.065]"
: "border-white/10 bg-black/32"
? "border-[#a2c638]/80 bg-[#a2c638]/12 ring-1 ring-[#a2c638]/45"
: "border-[#a2c638]/45 bg-[#a2c638]/[0.065]"
: "border-white/10 bg-black/28"
}`}
onDragEnter={(event) => {
if (!onDropFilmstripFrame) return
@@ -4017,7 +4084,7 @@ function SourceSubjectPipeline({
</span>
</div>
<div
className="flex flex-col gap-2 overflow-y-auto rounded-md border border-white/10 bg-black/24 p-2"
className="skg-glass-card--flat flex flex-col gap-2 overflow-y-auto border border-white/10 p-2"
style={{ maxHeight: SOURCE_CONVERSION_MAX_HEIGHT }}
>
<div className="grid shrink-0 grid-cols-2 gap-1.5">
@@ -4028,8 +4095,8 @@ function SourceSubjectPipeline({
onClick={() => setSubjectModelBundle(option.value)}
className={`rounded-md border px-2 py-1.5 text-left transition ${
subjectModelBundle === option.value
? "border-cyan-200/65 bg-cyan-300/12 text-cyan-50"
: "border-white/10 bg-black/26 text-white/52 hover:border-white/24 hover:text-white/76"
? "border-[#a2c638]/65 bg-[#a2c638]/12 text-white"
: "border-white/10 bg-black/24 text-white/52 hover:border-white/24 hover:text-white/76"
}`}
title={option.detail}
>
@@ -4042,7 +4109,7 @@ function SourceSubjectPipeline({
<div
className={`shrink-0 rounded-md border p-2 transition ${
agentDropActive || referenceFrameDragging || filmstripDragging || agentReferenceUploadBusy
? "border-cyan-200/65 bg-cyan-300/[0.08] ring-1 ring-cyan-200/25"
? "border-[#a2c638]/65 bg-[#a2c638]/[0.08] ring-1 ring-[#a2c638]/25"
: "border-white/10 bg-black/22"
}`}
onDragEnter={handleAgentReferenceDragEnter}
@@ -4076,7 +4143,7 @@ function SourceSubjectPipeline({
</div>
) : (
<div className="flex h-[72px] flex-col items-center justify-center rounded border border-dashed border-white/15 px-3 text-center text-[10px] leading-snug text-white/34">
{agentReferenceUploadBusy ? <Loader2 className="mb-1.5 h-4 w-4 animate-spin text-cyan-100/80" /> : <Upload className="mb-1.5 h-4 w-4 text-cyan-100/55" />}
{agentReferenceUploadBusy ? <Loader2 className="mb-1.5 h-4 w-4 animate-spin text-[#d7efbc]" /> : <Upload className="mb-1.5 h-4 w-4 text-[#d7efbc]/70" />}
<span className="font-semibold text-white/50"></span>
<span className="mt-0.5 text-white/28"> +</span>
</div>
@@ -4098,9 +4165,9 @@ function SourceSubjectPipeline({
</div>
{agentAnalysis ? (
<div className="shrink-0 rounded-md border border-emerald-200/18 bg-emerald-300/[0.055] p-2">
<div className="shrink-0 rounded-md border border-[#a2c638]/24 bg-[#a2c638]/[0.07] p-2">
<div className="flex items-center justify-between gap-2">
<span className="text-[10px] font-semibold text-emerald-50/76"></span>
<span className="text-[10px] font-semibold text-[#d7efbc]"></span>
<span className="text-[9px] text-white/34">
= ·
</span>
@@ -4109,7 +4176,7 @@ function SourceSubjectPipeline({
{agentTraits.length ? (
<>
<div className="mt-2 flex items-center justify-between gap-2 text-[9px]">
<span className={agentSelectedTraitsDirty ? "text-cyan-100/56" : "text-white/34"}>
<span className={agentSelectedTraitsDirty ? "text-[#d7efbc]/70" : "text-white/34"}>
{selectedAgentTraits.length} {agentSelectedTraitsDirty ? " · 待发送" : ""}
</span>
{selectedAgentTraits.length ? (
@@ -4134,7 +4201,7 @@ function SourceSubjectPipeline({
title={active ? "已作为保留元素,再点取消" : "点一下加入保留元素"}
className={`inline-flex min-h-[22px] cursor-pointer items-center gap-1 rounded-full border px-2 py-0.5 text-[9px] transition ${
active
? "border-emerald-100/65 bg-emerald-300/16 text-emerald-50 shadow-[0_0_0_1px_rgba(167,243,208,0.12)]"
? "border-[#a2c638]/65 bg-[#a2c638]/16 text-[#e9f6b8] shadow-[0_0_0_1px_rgba(162,198,56,0.12)]"
: "border-white/10 bg-black/26 text-white/46 hover:border-white/22 hover:text-white/70"
}`}
>
@@ -4152,11 +4219,11 @@ function SourceSubjectPipeline({
<div className="flex shrink-0 flex-col rounded-md border border-white/10 bg-black/22 p-2">
<div className="mb-1.5 flex items-center justify-between gap-2">
<span className="inline-flex items-center gap-1 text-[10px] font-semibold text-white/72">
<MessageSquare className="h-3.5 w-3.5 text-cyan-100/55" />
<MessageSquare className="h-3.5 w-3.5 text-[#d7efbc]/70" />
</span>
{effectivePrompt ? (
<span className="inline-flex h-6 items-center gap-1 rounded-md border border-[#d6b36a]/24 bg-[#d6b36a]/[0.07] px-2 text-[9px] font-semibold text-[#f4dc88]">
<span className="inline-flex h-6 items-center gap-1 rounded-md border border-[#a2c638]/28 bg-[#a2c638]/[0.08] px-2 text-[9px] font-semibold text-[#d7efbc]">
<Check className="h-3 w-3" />
· {effectiveAgentViews.length}
</span>
@@ -4171,7 +4238,7 @@ function SourceSubjectPipeline({
value={agentInput}
onChange={(event) => setAgentInput(event.target.value)}
placeholder="直接写要怎么生成,或补充要改什么。"
className="h-32 w-full resize-none rounded border border-transparent bg-transparent px-2 py-2 text-[11px] leading-relaxed text-white outline-none transition placeholder:text-white/24 focus:border-cyan-200/45"
className="h-32 w-full resize-none rounded border border-transparent bg-transparent px-2 py-2 text-[11px] leading-relaxed text-white outline-none transition placeholder:text-white/24 focus:border-[#a2c638]/45"
/>
<div className="mt-2 flex items-center gap-2">
<div className="flex h-10 shrink-0 items-center overflow-hidden rounded-md border border-white/10 bg-black/35">
@@ -4242,7 +4309,7 @@ function SourceSubjectPipeline({
{subjectAssetPacks.length ? `${subjectAssetPacks.length}` : "待生成"}
</span>
</div>
<div className="rounded-md border border-white/10 bg-black/32 p-2">
<div className="skg-glass-card--flat border border-white/10 p-2">
{subjectBusyFor ? (
<div className="mb-2 rounded-md border border-cyan-200/20 bg-cyan-300/[0.07] px-2.5 py-2 text-[10px] leading-snug text-cyan-50/70">
{reconstructionModeConfig(subjectBusyFor.mode).label} {subjectBusyFor.viewCount} {subjectBusyFor.sourceCount || "自主描述"}
@@ -4253,7 +4320,7 @@ function SourceSubjectPipeline({
{subjectAssetPacks.length ? (
<div className="grid grid-cols-[minmax(0,1fr)_260px] gap-2">
{activeSubjectPack ? (
<div className="rounded-md border border-[#d6b36a]/28 bg-[#d6b36a]/[0.07] p-2">
<div className="rounded-md border border-[#a2c638]/28 bg-[#a2c638]/[0.07] p-2">
<div className="mb-2 flex items-center justify-between gap-2">
<div className="min-w-0">
<div className="truncate text-[11px] font-semibold text-white">{activeSubjectPack.label}</div>
@@ -7883,7 +7950,7 @@ function MaterialCard({
<button
type="button"
onClick={onClick}
className={`group w-full rounded-lg border p-3 text-left transition ${active ? "border-[#d6b36a]/55 bg-[#d6b36a]/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.05)]" : "border-white/10 bg-black/28 hover:border-[#d6b36a]/28 hover:bg-white/[0.045]"}`}
className={`group skg-glass-card--flat w-full border p-3 text-left transition ${active ? "border-[#a2c638]/55 bg-[#a2c638]/10 shadow-[inset_0_1px_0_rgba(255,255,255,0.05)]" : "border-white/10 bg-black/24 hover:border-[#a2c638]/30 hover:bg-white/[0.055]"}`}
>
<div className="flex items-start justify-between gap-2">
<div className="min-w-0">
@@ -7918,7 +7985,7 @@ function MaterialCard({
onDelete()
}
}}
className="mt-3 hidden h-8 items-center justify-center gap-1 rounded-md border border-white/10 text-[11px] text-white/50 transition hover:border-[#d6b36a]/40 hover:text-[#f2d58a] group-hover:flex"
className="mt-3 hidden h-8 items-center justify-center gap-1 rounded-md border border-white/10 text-[11px] text-white/50 transition hover:border-[#a2c638]/40 hover:text-[#c8cd19] group-hover:flex"
>
<Trash2 className="h-3.5 w-3.5" />