Compare commits
2 Commits
1f193e95f3
...
c805012adc
| Author | SHA1 | Date | |
|---|---|---|---|
| c805012adc | |||
| 536b4d7f59 |
@@ -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 @@
|
||||
## 最近助手会话概览
|
||||
|
||||
- Claude:a9e0449c-d9cb-4a2a-bb16-16596dfb552a · 时间未知
|
||||
- Codex:019e3db1-012e-7163-bc78-acf7cde326e7 · 时间未知
|
||||
- Codex:019e447d-68c7-7db1-a499-b5eb6a98a7c2 · 时间未知
|
||||
- Cursor:未找到匹配当前项目的最近会话
|
||||
|
||||
## Claude 最近会话
|
||||
@@ -92,27 +92,42 @@
|
||||
|
||||
## Codex 最近会话
|
||||
|
||||
- Session ID:019e3db1-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 ID:019e447d-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 最近会话
|
||||
|
||||
|
||||
4510
.memory/worklog.json
4510
.memory/worklog.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -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 {
|
||||
|
||||
@@ -2476,108 +2476,104 @@ 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="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>
|
||||
</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]">
|
||||
<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">
|
||||
<MaterialColumn
|
||||
data={data}
|
||||
step={workflow.input}
|
||||
jobs={jobs}
|
||||
<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}
|
||||
activeJobId={activeJobId}
|
||||
url={url}
|
||||
setUrl={setUrl}
|
||||
fileRef={fileRef}
|
||||
onSubmitUrl={submitUrl}
|
||||
onStartProduction={startProduction}
|
||||
jobsCount={jobs.length}
|
||||
audioReady={audioReady}
|
||||
visualReady={visualReady}
|
||||
subjectAssetCount={subjectAssetCount}
|
||||
generatedVideoCount={generatedVideos.length}
|
||||
onOpenLibrary={() => setLibraryOpen(true)}
|
||||
onToggleTheme={toggleBoardTheme}
|
||||
boardTheme={boardTheme}
|
||||
/>
|
||||
|
||||
<section className="skg-board-panel flex min-h-0 flex-col rounded-lg 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>
|
||||
<WorkflowStepBadge step={workflow.source} compact />
|
||||
<h2 className="text-[15px] font-semibold leading-tight text-white">视频拆解</h2>
|
||||
</div>
|
||||
<div className="mt-1 truncate text-[11px] text-white/38" title={statusMessage}>
|
||||
{statusMessage || "下载源视频后解析音频,再抽参考帧并生成相似主体。"}
|
||||
<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="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">
|
||||
<ModelTrace trace={audioModelTrace(runtimeModels)} compact />
|
||||
<ActionButton disabled={!job?.video_url || audioRunning} onClick={() => data.onTranscribeAudio?.(job?.id)}>
|
||||
<Mic className="h-3.5 w-3.5" />
|
||||
解析音频
|
||||
</ActionButton>
|
||||
</div>
|
||||
<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>
|
||||
</header>
|
||||
|
||||
<div className="min-h-0 flex-1 overflow-y-auto p-4">
|
||||
<AudioIntakePanel
|
||||
<div className="grid min-h-0 flex-1 grid-cols-[340px_minmax(0,1fr)] gap-3">
|
||||
<MaterialColumn
|
||||
data={data}
|
||||
step={workflow.input}
|
||||
jobs={jobs}
|
||||
job={job}
|
||||
selectedFrames={data.selectedFrames}
|
||||
onToggleFrame={data.onToggleFrame}
|
||||
onJobUpdate={data.onJobUpdate}
|
||||
onAddFrame={data.onAddManualFrameForJob}
|
||||
onDeleteFrame={data.onDeleteFrameForJob}
|
||||
runtimeModels={runtimeModels}
|
||||
/>
|
||||
<AudioStoryboardPlanPanel
|
||||
job={job}
|
||||
selectedFrames={data.selectedFrames}
|
||||
onJobUpdate={data.onJobUpdate}
|
||||
onDeleteVideo={data.onDeleteVideo}
|
||||
runtimeModels={runtimeModels}
|
||||
productStep={workflow.product}
|
||||
scriptStep={workflow.script}
|
||||
sceneStep={workflow.scene}
|
||||
videoStep={workflow.video}
|
||||
activeJobId={activeJobId}
|
||||
url={url}
|
||||
setUrl={setUrl}
|
||||
fileRef={fileRef}
|
||||
onSubmitUrl={submitUrl}
|
||||
onStartProduction={startProduction}
|
||||
/>
|
||||
|
||||
<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-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>
|
||||
<div className="mt-1 truncate text-[11px] text-white/38" title={statusMessage}>
|
||||
{statusMessage || "下载源视频后解析音频,再抽参考帧并生成相似主体。"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
<ModelTrace trace={audioModelTrace(runtimeModels)} compact />
|
||||
<ActionButton disabled={!job?.video_url || audioRunning} onClick={() => data.onTranscribeAudio?.(job?.id)}>
|
||||
<Mic className="h-3.5 w-3.5" />
|
||||
解析音频
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="min-h-0 flex-1 overflow-y-auto p-4">
|
||||
<AudioIntakePanel
|
||||
job={job}
|
||||
selectedFrames={data.selectedFrames}
|
||||
onToggleFrame={data.onToggleFrame}
|
||||
onJobUpdate={data.onJobUpdate}
|
||||
onAddFrame={data.onAddManualFrameForJob}
|
||||
onDeleteFrame={data.onDeleteFrameForJob}
|
||||
runtimeModels={runtimeModels}
|
||||
/>
|
||||
<AudioStoryboardPlanPanel
|
||||
job={job}
|
||||
selectedFrames={data.selectedFrames}
|
||||
onJobUpdate={data.onJobUpdate}
|
||||
onDeleteVideo={data.onDeleteVideo}
|
||||
runtimeModels={runtimeModels}
|
||||
productStep={workflow.product}
|
||||
scriptStep={workflow.script}
|
||||
sceneStep={workflow.scene}
|
||||
videoStep={workflow.video}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<LibraryDrawer
|
||||
open={libraryOpen}
|
||||
@@ -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,13 +3983,13 @@ function SourceSubjectPipeline({
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className={`rounded-md 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"
|
||||
}`}
|
||||
className={`skg-glass-card--flat border p-1.5 transition ${
|
||||
filmstripDragging
|
||||
? referenceDropActive
|
||||
? "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
|
||||
event.preventDefault()
|
||||
@@ -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}
|
||||
>
|
||||
@@ -4041,9 +4108,9 @@ 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-white/10 bg-black/22"
|
||||
agentDropActive || referenceFrameDragging || filmstripDragging || agentReferenceUploadBusy
|
||||
? "border-[#a2c638]/65 bg-[#a2c638]/[0.08] ring-1 ring-[#a2c638]/25"
|
||||
: "border-white/10 bg-black/22"
|
||||
}`}
|
||||
onDragEnter={handleAgentReferenceDragEnter}
|
||||
onDragOver={handleAgentReferenceDragOver}
|
||||
@@ -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"
|
||||
}`}
|
||||
>
|
||||
@@ -4149,14 +4216,14 @@ function SourceSubjectPipeline({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex shrink-0 flex-col rounded-md border border-white/10 bg-black/22 p-2">
|
||||
<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" />
|
||||
删除素材
|
||||
|
||||
Reference in New Issue
Block a user