feat: restyle workbench with glassmorphism shell
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -469,29 +469,33 @@ nextjs-portal {
|
|||||||
信息流工作台 · 登录页同源质感
|
信息流工作台 · 登录页同源质感
|
||||||
============================================================ */
|
============================================================ */
|
||||||
.skg-board-theme {
|
.skg-board-theme {
|
||||||
--skg-gold-1: #d6b36a;
|
--skg-gold-1: #c8cd19;
|
||||||
--skg-gold-2: #c89b3c;
|
--skg-gold-2: #a2c638;
|
||||||
--skg-cream: #f5efe3;
|
--skg-cream: #f6f6ee;
|
||||||
--skg-bg-1: #0a0a0a;
|
--skg-bg-1: #1b1b1b;
|
||||||
--skg-bg-2: #111111;
|
--skg-bg-2: #242424;
|
||||||
--skg-bg-3: rgba(255, 255, 255, 0.035);
|
--skg-bg-3: rgba(255, 255, 255, 0.1);
|
||||||
--skg-border: rgba(255, 255, 255, 0.1);
|
--skg-border: rgba(255, 255, 255, 0.14);
|
||||||
--skg-text-1: #ffffff;
|
--skg-text-1: #ffffff;
|
||||||
--skg-text-2: rgba(255, 255, 255, 0.62);
|
--skg-text-2: rgba(255, 255, 255, 0.56);
|
||||||
--skg-text-3: rgba(255, 255, 255, 0.34);
|
--skg-text-3: rgba(255, 255, 255, 0.36);
|
||||||
--skg-success: #34d399;
|
--skg-success: #a2c638;
|
||||||
--skg-warn: #fcd34d;
|
--skg-warn: #c8cd19;
|
||||||
--skg-danger: #fb7185;
|
--skg-danger: #fb7185;
|
||||||
--skg-info: #67e8f9;
|
--skg-info: #a6d533;
|
||||||
--skg-radius-sm: 6px;
|
--skg-radius-sm: 6px;
|
||||||
--skg-radius-md: 8px;
|
--skg-radius-md: 8px;
|
||||||
--skg-radius-lg: 12px;
|
--skg-radius-lg: 20px;
|
||||||
--skg-shadow-button: 0 6px 24px -8px rgba(0, 0, 0, 0.45);
|
--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);
|
color: var(--skg-text-1);
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 52% 4%, rgba(214, 179, 106, 0.1), transparent 30%),
|
radial-gradient(circle at 20% 18%, rgba(162, 198, 56, 0.11), transparent 28%),
|
||||||
radial-gradient(circle at 12% 96%, rgba(214, 179, 106, 0.065), transparent 34%),
|
radial-gradient(circle at 86% 78%, rgba(200, 205, 25, 0.12), transparent 28%),
|
||||||
linear-gradient(120deg, #0a0a0a 0%, #10100f 46%, #050505 100%);
|
linear-gradient(120deg, #202020 0%, #242424 48%, #171717 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-board-theme::before {
|
.skg-board-theme::before {
|
||||||
@@ -501,10 +505,10 @@ nextjs-portal {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background:
|
background:
|
||||||
linear-gradient(90deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px),
|
linear-gradient(90deg, rgba(255, 255, 255, 0.018) 1px, transparent 1px),
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px);
|
linear-gradient(180deg, rgba(255, 255, 255, 0.016) 1px, transparent 1px);
|
||||||
background-size: 64px 64px;
|
background-size: 56px 56px;
|
||||||
opacity: 0.44;
|
opacity: 0.34;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-board-theme::after {
|
.skg-board-theme::after {
|
||||||
@@ -514,39 +518,38 @@ nextjs-portal {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, rgba(0, 0, 0, 0.22), transparent 42%, rgba(0, 0, 0, 0.4)),
|
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.28), transparent 38%, rgba(0, 0, 0, 0.24));
|
linear-gradient(90deg, rgba(0, 0, 0, 0.34), transparent 36%, rgba(0, 0, 0, 0.2));
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-board-ambient {
|
.skg-board-ambient {
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 78% 0%, rgba(232, 201, 122, 0.08), transparent 30%),
|
radial-gradient(circle at 72% 12%, rgba(162, 198, 56, 0.13), transparent 28%),
|
||||||
radial-gradient(circle at 8% 100%, rgba(214, 179, 106, 0.06), transparent 34%);
|
radial-gradient(circle at 18% 92%, rgba(200, 205, 25, 0.12), transparent 32%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-board-topbar,
|
.skg-board-topbar,
|
||||||
.skg-board-panel {
|
.skg-board-panel {
|
||||||
border-color: var(--skg-border) !important;
|
border-color: var(--skg-border) !important;
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.022)),
|
radial-gradient(circle at 88% 22%, rgba(162, 198, 56, 0.08), transparent 38%),
|
||||||
rgba(17, 17, 17, 0.74) !important;
|
linear-gradient(180deg, rgba(255, 255, 255, 0.105), rgba(255, 255, 255, 0.052)),
|
||||||
box-shadow:
|
rgba(36, 36, 36, 0.68) !important;
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.06),
|
box-shadow: var(--skg-shadow-card);
|
||||||
0 18px 54px rgba(0, 0, 0, 0.34);
|
backdrop-filter: blur(5px);
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-board-topbar {
|
.skg-board-topbar {
|
||||||
background:
|
background:
|
||||||
linear-gradient(100deg, rgba(214, 179, 106, 0.075), rgba(255, 255, 255, 0.03) 54%, rgba(214, 179, 106, 0.035)),
|
linear-gradient(100deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.045) 58%, rgba(162, 198, 56, 0.08)),
|
||||||
rgba(12, 12, 12, 0.76) !important;
|
rgba(38, 38, 38, 0.72) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-board-theme input:focus,
|
.skg-board-theme input:focus,
|
||||||
.skg-board-theme textarea:focus,
|
.skg-board-theme textarea:focus,
|
||||||
.skg-board-theme select:focus {
|
.skg-board-theme select:focus {
|
||||||
border-color: rgba(214, 179, 106, 0.58) !important;
|
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"] {
|
.skg-board-theme input[type="checkbox"] {
|
||||||
@@ -558,6 +561,80 @@ nextjs-portal {
|
|||||||
color: #fff;
|
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-board-theme--light {
|
||||||
--skg-bg-1: #faf8f4;
|
--skg-bg-1: #faf8f4;
|
||||||
--skg-bg-2: #ffffff;
|
--skg-bg-2: #ffffff;
|
||||||
@@ -748,43 +825,46 @@ nextjs-portal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.skg-stat-card {
|
.skg-stat-card {
|
||||||
border: 1px solid rgba(214, 179, 106, 0.18);
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
border-radius: var(--skg-radius-md);
|
border-radius: 12px;
|
||||||
background: var(--skg-cream);
|
background:
|
||||||
color: #0a0a0a;
|
linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.045)),
|
||||||
box-shadow: var(--skg-shadow-button);
|
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 {
|
.skg-stat-card__label {
|
||||||
color: rgba(0, 0, 0, 0.5);
|
color: rgba(255, 255, 255, 0.48);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-stat-card__value {
|
.skg-stat-card__value {
|
||||||
color: #0a0a0a;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-primary-action {
|
.skg-primary-action {
|
||||||
border-radius: var(--skg-radius-md);
|
border-radius: var(--skg-radius-md);
|
||||||
background: #f5efe3;
|
background: linear-gradient(135deg, #c8cd19, #a2c638);
|
||||||
color: #0a0a0a;
|
color: #101010;
|
||||||
box-shadow: var(--skg-shadow-button);
|
box-shadow: var(--skg-shadow-button);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-primary-action:hover {
|
.skg-primary-action:hover {
|
||||||
background: #fff7df;
|
background: linear-gradient(135deg, #d6db25, #b0d83d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-secondary-action {
|
.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);
|
border-radius: var(--skg-radius-md);
|
||||||
background: rgba(214, 179, 106, 0.08);
|
background: rgba(255, 255, 255, 0.06);
|
||||||
color: var(--skg-gold-1);
|
color: rgba(255, 255, 255, 0.76);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-secondary-action:hover {
|
.skg-secondary-action:hover {
|
||||||
border-color: rgba(214, 179, 106, 0.54);
|
border-color: rgba(162, 198, 56, 0.44);
|
||||||
background: rgba(214, 179, 106, 0.12);
|
background: rgba(162, 198, 56, 0.11);
|
||||||
color: #f5d98e;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skg-empty-state {
|
.skg-empty-state {
|
||||||
|
|||||||
@@ -2476,108 +2476,104 @@ export function AdRecreationBoard({
|
|||||||
return (
|
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`}>
|
<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="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">
|
<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">
|
||||||
<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-shell flex gap-4 p-4">
|
||||||
<div className="skg-board-brand">
|
<WorkbenchRail
|
||||||
<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}
|
|
||||||
job={job}
|
job={job}
|
||||||
activeJobId={activeJobId}
|
jobsCount={jobs.length}
|
||||||
url={url}
|
audioReady={audioReady}
|
||||||
setUrl={setUrl}
|
visualReady={visualReady}
|
||||||
fileRef={fileRef}
|
subjectAssetCount={subjectAssetCount}
|
||||||
onSubmitUrl={submitUrl}
|
generatedVideoCount={generatedVideos.length}
|
||||||
onStartProduction={startProduction}
|
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">
|
<div className="flex min-w-0 flex-1 flex-col gap-3">
|
||||||
<header className="shrink-0 border-b border-white/10 p-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="flex items-center justify-between gap-4">
|
<div className="min-w-0">
|
||||||
<div className="min-w-0">
|
<div className="flex items-center gap-3">
|
||||||
<div className="flex items-center gap-2">
|
<span className="skg-status-orb shrink-0 text-[10px] font-semibold">SKG</span>
|
||||||
<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>
|
<div className="min-w-0">
|
||||||
<WorkflowStepBadge step={workflow.source} compact />
|
<div className="text-[11px] font-medium uppercase tracking-[0.28em] text-white/40">Marketing Production Console</div>
|
||||||
<h2 className="text-[15px] font-semibold leading-tight text-white">视频拆解</h2>
|
<h1 className="mt-1 truncate text-[22px] font-semibold leading-tight text-white">信息流广告复刻工作台</h1>
|
||||||
</div>
|
|
||||||
<div className="mt-1 truncate text-[11px] text-white/38" title={statusMessage}>
|
|
||||||
{statusMessage || "下载源视频后解析音频,再抽参考帧并生成相似主体。"}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 items-center gap-2">
|
<p className="mt-2 truncate text-[12px] text-white/42">源视频分析、转换层确认、主体套图、逐句分镜和视频候选集中生产。</p>
|
||||||
<ModelTrace trace={audioModelTrace(runtimeModels)} compact />
|
</div>
|
||||||
<ActionButton disabled={!job?.video_url || audioRunning} onClick={() => data.onTranscribeAudio?.(job?.id)}>
|
<div className="grid min-w-[560px] grid-cols-5 gap-2 text-[11px]">
|
||||||
<Mic className="h-3.5 w-3.5" />
|
<Metric label="素材" value={`${jobs.length}`} />
|
||||||
解析音频
|
<Metric label="当前" value={shortId(activeJobId)} />
|
||||||
</ActionButton>
|
<Metric label="视频" value={job?.video_url ? "ready" : "-"} />
|
||||||
</div>
|
<Metric label="文案段" value={`${transcriptCount}`} />
|
||||||
|
<Metric label="背景音" value={backgroundReady ? "ready" : "-"} />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="min-h-0 flex-1 overflow-y-auto p-4">
|
<div className="grid min-h-0 flex-1 grid-cols-[340px_minmax(0,1fr)] gap-3">
|
||||||
<AudioIntakePanel
|
<MaterialColumn
|
||||||
|
data={data}
|
||||||
|
step={workflow.input}
|
||||||
|
jobs={jobs}
|
||||||
job={job}
|
job={job}
|
||||||
selectedFrames={data.selectedFrames}
|
activeJobId={activeJobId}
|
||||||
onToggleFrame={data.onToggleFrame}
|
url={url}
|
||||||
onJobUpdate={data.onJobUpdate}
|
setUrl={setUrl}
|
||||||
onAddFrame={data.onAddManualFrameForJob}
|
fileRef={fileRef}
|
||||||
onDeleteFrame={data.onDeleteFrameForJob}
|
onSubmitUrl={submitUrl}
|
||||||
runtimeModels={runtimeModels}
|
onStartProduction={startProduction}
|
||||||
/>
|
|
||||||
<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}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<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>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<LibraryDrawer
|
<LibraryDrawer
|
||||||
open={libraryOpen}
|
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({
|
function MaterialColumn({
|
||||||
data,
|
data,
|
||||||
step,
|
step,
|
||||||
@@ -2616,10 +2683,10 @@ function MaterialColumn({
|
|||||||
? job.video_url ? "重新解析" : "重新下载"
|
? job.video_url ? "重新解析" : "重新下载"
|
||||||
: "开始分析"
|
: "开始分析"
|
||||||
return (
|
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">
|
<header className="shrink-0 border-b border-white/10 pb-3">
|
||||||
<div className="mb-2 flex items-center gap-2">
|
<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 />
|
<WorkflowStepBadge step={step} compact />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-[15px] font-semibold leading-tight text-white">素材输入</h2>
|
<h2 className="text-[15px] font-semibold leading-tight text-white">素材输入</h2>
|
||||||
@@ -2632,7 +2699,7 @@ function MaterialColumn({
|
|||||||
onChange={(e) => setUrl(e.target.value)}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
onKeyDown={(e) => { if (e.key === "Enter") onSubmitUrl() }}
|
onKeyDown={(e) => { if (e.key === "Enter") onSubmitUrl() }}
|
||||||
placeholder="粘贴 TK / 信息流视频链接"
|
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
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -2909,7 +2976,7 @@ function AudioIntakePanel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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">
|
<div className="mb-2 flex items-center justify-between gap-3">
|
||||||
<SectionTitle icon={<Film className="h-4 w-4" />} title="源视频工作区" />
|
<SectionTitle icon={<Film className="h-4 w-4" />} title="源视频工作区" />
|
||||||
<div className="flex items-center gap-2 font-mono text-[11px] text-white/38">
|
<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>
|
<span className="font-mono text-[11px] text-white/38">{currentTime.toFixed(1)}s</span>
|
||||||
</div>
|
</div>
|
||||||
<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 }}
|
style={{ height: SOURCE_VIDEO_HEIGHT }}
|
||||||
>
|
>
|
||||||
{job.video_url ? (
|
{job.video_url ? (
|
||||||
@@ -2959,7 +3026,7 @@ function AudioIntakePanel({
|
|||||||
onClick={() => void addFrameAtCurrentTime()}
|
onClick={() => void addFrameAtCurrentTime()}
|
||||||
disabled={!job.video_url || !onAddFrame || manualBusy || job.status === "splitting"}
|
disabled={!job.video_url || !onAddFrame || manualBusy || job.status === "splitting"}
|
||||||
title={`按当前播放位置手动抽帧:${currentTime.toFixed(1)}s`}
|
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" />}
|
{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>
|
||||||
|
|
||||||
<div className="min-w-0 space-y-2">
|
<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">
|
<div className="mb-1 flex items-center justify-end gap-3 text-[10px] text-white/40">
|
||||||
<FilmstripDensityControls
|
<FilmstripDensityControls
|
||||||
density={filmstripDensity}
|
density={filmstripDensity}
|
||||||
@@ -3916,13 +3983,13 @@ function SourceSubjectPipeline({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`rounded-md border p-1.5 transition ${
|
className={`skg-glass-card--flat border p-1.5 transition ${
|
||||||
filmstripDragging
|
filmstripDragging
|
||||||
? referenceDropActive
|
? referenceDropActive
|
||||||
? "border-[#d6b36a]/80 bg-[#d6b36a]/12 ring-1 ring-[#d6b36a]/45"
|
? "border-[#a2c638]/80 bg-[#a2c638]/12 ring-1 ring-[#a2c638]/45"
|
||||||
: "border-[#d6b36a]/45 bg-[#d6b36a]/[0.065]"
|
: "border-[#a2c638]/45 bg-[#a2c638]/[0.065]"
|
||||||
: "border-white/10 bg-black/32"
|
: "border-white/10 bg-black/28"
|
||||||
}`}
|
}`}
|
||||||
onDragEnter={(event) => {
|
onDragEnter={(event) => {
|
||||||
if (!onDropFilmstripFrame) return
|
if (!onDropFilmstripFrame) return
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@@ -4017,7 +4084,7 @@ function SourceSubjectPipeline({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<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 }}
|
style={{ maxHeight: SOURCE_CONVERSION_MAX_HEIGHT }}
|
||||||
>
|
>
|
||||||
<div className="grid shrink-0 grid-cols-2 gap-1.5">
|
<div className="grid shrink-0 grid-cols-2 gap-1.5">
|
||||||
@@ -4028,8 +4095,8 @@ function SourceSubjectPipeline({
|
|||||||
onClick={() => setSubjectModelBundle(option.value)}
|
onClick={() => setSubjectModelBundle(option.value)}
|
||||||
className={`rounded-md border px-2 py-1.5 text-left transition ${
|
className={`rounded-md border px-2 py-1.5 text-left transition ${
|
||||||
subjectModelBundle === option.value
|
subjectModelBundle === option.value
|
||||||
? "border-cyan-200/65 bg-cyan-300/12 text-cyan-50"
|
? "border-[#a2c638]/65 bg-[#a2c638]/12 text-white"
|
||||||
: "border-white/10 bg-black/26 text-white/52 hover:border-white/24 hover:text-white/76"
|
: "border-white/10 bg-black/24 text-white/52 hover:border-white/24 hover:text-white/76"
|
||||||
}`}
|
}`}
|
||||||
title={option.detail}
|
title={option.detail}
|
||||||
>
|
>
|
||||||
@@ -4041,9 +4108,9 @@ function SourceSubjectPipeline({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
className={`shrink-0 rounded-md border p-2 transition ${
|
className={`shrink-0 rounded-md border p-2 transition ${
|
||||||
agentDropActive || referenceFrameDragging || filmstripDragging || agentReferenceUploadBusy
|
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"
|
: "border-white/10 bg-black/22"
|
||||||
}`}
|
}`}
|
||||||
onDragEnter={handleAgentReferenceDragEnter}
|
onDragEnter={handleAgentReferenceDragEnter}
|
||||||
onDragOver={handleAgentReferenceDragOver}
|
onDragOver={handleAgentReferenceDragOver}
|
||||||
@@ -4076,7 +4143,7 @@ function SourceSubjectPipeline({
|
|||||||
</div>
|
</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">
|
<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="font-semibold text-white/50">拖入参考帧或本地图片</span>
|
||||||
<span className="mt-0.5 text-white/28">也可点左侧缩略图上的 +</span>
|
<span className="mt-0.5 text-white/28">也可点左侧缩略图上的 +</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -4098,9 +4165,9 @@ function SourceSubjectPipeline({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{agentAnalysis ? (
|
{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">
|
<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 className="text-[9px] text-white/34">
|
||||||
点亮=保留 · 再点取消
|
点亮=保留 · 再点取消
|
||||||
</span>
|
</span>
|
||||||
@@ -4109,7 +4176,7 @@ function SourceSubjectPipeline({
|
|||||||
{agentTraits.length ? (
|
{agentTraits.length ? (
|
||||||
<>
|
<>
|
||||||
<div className="mt-2 flex items-center justify-between gap-2 text-[9px]">
|
<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 ? " · 待发送" : ""}
|
保留元素 {selectedAgentTraits.length} 个{agentSelectedTraitsDirty ? " · 待发送" : ""}
|
||||||
</span>
|
</span>
|
||||||
{selectedAgentTraits.length ? (
|
{selectedAgentTraits.length ? (
|
||||||
@@ -4134,7 +4201,7 @@ function SourceSubjectPipeline({
|
|||||||
title={active ? "已作为保留元素,再点取消" : "点一下加入保留元素"}
|
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 ${
|
className={`inline-flex min-h-[22px] cursor-pointer items-center gap-1 rounded-full border px-2 py-0.5 text-[9px] transition ${
|
||||||
active
|
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"
|
: "border-white/10 bg-black/26 text-white/46 hover:border-white/22 hover:text-white/70"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -4149,14 +4216,14 @@ function SourceSubjectPipeline({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : 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">
|
<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">
|
<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>
|
</span>
|
||||||
{effectivePrompt ? (
|
{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" />
|
<Check className="h-3 w-3" />
|
||||||
提示词就绪 · {effectiveAgentViews.length} 张
|
提示词就绪 · {effectiveAgentViews.length} 张
|
||||||
</span>
|
</span>
|
||||||
@@ -4171,7 +4238,7 @@ function SourceSubjectPipeline({
|
|||||||
value={agentInput}
|
value={agentInput}
|
||||||
onChange={(event) => setAgentInput(event.target.value)}
|
onChange={(event) => setAgentInput(event.target.value)}
|
||||||
placeholder="直接写要怎么生成,或补充要改什么。"
|
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="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">
|
<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} 套` : "待生成"}
|
{subjectAssetPacks.length ? `${subjectAssetPacks.length} 套` : "待生成"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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 ? (
|
{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">
|
<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 || "自主描述"}。
|
正在生成{reconstructionModeConfig(subjectBusyFor.mode).label} {subjectBusyFor.viewCount} 张;参考 {subjectBusyFor.sourceCount || "自主描述"}。
|
||||||
@@ -4253,7 +4320,7 @@ function SourceSubjectPipeline({
|
|||||||
{subjectAssetPacks.length ? (
|
{subjectAssetPacks.length ? (
|
||||||
<div className="grid grid-cols-[minmax(0,1fr)_260px] gap-2">
|
<div className="grid grid-cols-[minmax(0,1fr)_260px] gap-2">
|
||||||
{activeSubjectPack ? (
|
{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="mb-2 flex items-center justify-between gap-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="truncate text-[11px] font-semibold text-white">{activeSubjectPack.label}</div>
|
<div className="truncate text-[11px] font-semibold text-white">{activeSubjectPack.label}</div>
|
||||||
@@ -7883,7 +7950,7 @@ function MaterialCard({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick}
|
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="flex items-start justify-between gap-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
@@ -7918,7 +7985,7 @@ function MaterialCard({
|
|||||||
onDelete()
|
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" />
|
<Trash2 className="h-3.5 w-3.5" />
|
||||||
删除素材
|
删除素材
|
||||||
|
|||||||
Reference in New Issue
Block a user