fix: place current session info in left rail

This commit is contained in:
2026-05-19 19:20:58 +08:00
parent 3be26b8eb4
commit b0ff1e1935
2 changed files with 114 additions and 108 deletions

View File

@@ -22,6 +22,92 @@ import type {
} from '@/lib/types'; } from '@/lib/types';
import type { VIDEO_TEMPLATES } from '@/lib/templates'; import type { VIDEO_TEMPLATES } from '@/lib/templates';
function sessionModeLabel(mode?: GenSession['inputMode']) {
if (mode === 'remix') return '二创';
if (mode === 'replicate') return '复刻';
if (mode === 'extend') return '补全';
return '想法';
}
function sessionReferenceImages(session: GenSession) {
const uploaded = session.uploadedImages?.map(image => ({
url: image.url,
label: image.role === 'subject' ? '主体图' : image.role === 'reference' ? '参考图' : image.accessoryName || image.role,
})) ?? [];
if (uploaded.length) return uploaded;
return session.refImages.map((url, index) => ({ url, label: `参考 ${index + 1}` }));
}
function CurrentSessionRail({ session }: { session: GenSession }) {
const refs = sessionReferenceImages(session);
const selectedCount = session.images.filter(image => image.status === 'selected').length;
const packCount = session.packs?.length ?? 0;
return (
<aside className="border-b border-[#8cb478]/12 bg-black/16 p-5 lg:border-b-0 lg:border-r">
<div className="space-y-1.5">
<span className="section-eyebrow">Step · 02 · Session</span>
<div className="text-[10px] text-white/34"></div>
</div>
<div className="mt-5 rounded-[8px] border border-[#e6f578]/45 bg-[#e6f578]/10 p-3">
<div className="flex items-center justify-between gap-2">
<div className="text-[10px] uppercase tracking-[0.14em] text-[#e6f578]/65"></div>
<span className="rounded-full border border-white/10 bg-black/28 px-2 py-0.5 text-[10px] text-white/50">
{sessionModeLabel(session.inputMode)}
</span>
</div>
<div className="mt-3 line-clamp-5 text-sm font-semibold leading-relaxed text-white">
{session.characterSpec?.name || session.prompt || '未填写'}
</div>
<div className="mt-3 text-[10px] text-white/38">
{new Date(session.createdAt).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}
</div>
</div>
<div className="mt-5 grid grid-cols-3 gap-2 text-[10px] text-white/42">
<div className="rounded-[8px] border border-[#8cb478]/14 bg-black/22 p-2">
<div></div>
<b className="mt-1 block text-[13px] text-white">{session.images.length}</b>
</div>
<div className="rounded-[8px] border border-[#8cb478]/14 bg-black/22 p-2">
<div></div>
<b className="mt-1 block text-[13px] text-[#e6f578]">{selectedCount}</b>
</div>
<div className="rounded-[8px] border border-[#8cb478]/14 bg-black/22 p-2">
<div></div>
<b className="mt-1 block text-[13px] text-white">{packCount}</b>
</div>
</div>
<div className="mt-5">
<div className="mb-2 text-[10px] uppercase tracking-[0.14em] text-white/38">Reference</div>
{refs.length ? (
<div className="grid grid-cols-2 gap-2">
{refs.slice(0, 6).map((ref, index) => (
<div key={`${ref.url}-${index}`} className="relative aspect-square overflow-hidden rounded-[8px] bg-white ring-1 ring-white/10">
<img src={ref.url} alt={ref.label} className="h-full w-full object-contain" />
<span className="absolute bottom-1 left-1 rounded bg-black/70 px-1.5 py-0.5 text-[9px] text-white/70">
{ref.label}
</span>
</div>
))}
</div>
) : (
<div className="rounded-[8px] border border-dashed border-[#8cb478]/18 bg-black/18 px-3 py-4 text-xs text-white/34">
</div>
)}
</div>
<div className="mt-5 rounded-[8px] border border-[#8cb478]/14 bg-black/22 p-3">
<div className="text-[10px] uppercase tracking-[0.14em] text-white/38">Session ID</div>
<div className="mt-2 break-all font-mono text-[10px] text-white/42">{session.id}</div>
</div>
</aside>
);
}
export default function Home() { export default function Home() {
const [sessions, setSessions] = useState<GenSession[]>([]); const [sessions, setSessions] = useState<GenSession[]>([]);
const [current, setCurrent] = useState<GenSession | null>(null); const [current, setCurrent] = useState<GenSession | null>(null);
@@ -353,30 +439,35 @@ export default function Home() {
/> />
)} )}
{current && ( {current && (
<section className="space-y-5"> <section className="card overflow-hidden">
<div className="flex items-end justify-between"> <div className="grid lg:grid-cols-[268px_minmax(0,1fr)]">
<div> <CurrentSessionRail session={current} />
<span className="section-eyebrow">Step · 02 · Quick Screen</span> <div className="space-y-5 p-7">
<h2 className="mt-2 text-lg font-semibold text-white"></h2> <div className="flex items-end justify-between gap-4">
<p className="text-xs text-white/40 mt-1"> <div>
{new Date(current.createdAt).toLocaleString('zh-CN')} <span className="section-eyebrow">Step · 03 · Quick Screen</span>
</p> <h2 className="mt-2 text-lg font-semibold text-white"></h2>
<p className="text-xs text-white/40 mt-1">
{new Date(current.createdAt).toLocaleString('zh-CN')}
</p>
</div>
<code className="max-w-[220px] truncate text-[11px] text-white/30 font-mono">{current.id}</code>
</div>
<ResultGrid images={current.images} onAction={handleAction} />
<PackPanel
session={current}
loadingKind={loadingKind}
allLoading={allLoading}
characterLoading={characterLoading}
videoLoading={videoLoading}
onGenerate={handleGeneratePack}
onGenerateAll={handleGenerateAll}
onLockCharacter={handleLockCharacter}
onRegenerateAsset={handleRegenerateAsset}
onGenerateVideo={handleGenerateVideo}
/>
</div> </div>
<code className="text-[11px] text-white/30 font-mono">{current.id}</code>
</div> </div>
<ResultGrid images={current.images} onAction={handleAction} />
<PackPanel
session={current}
loadingKind={loadingKind}
allLoading={allLoading}
characterLoading={characterLoading}
videoLoading={videoLoading}
onGenerate={handleGeneratePack}
onGenerateAll={handleGenerateAll}
onLockCharacter={handleLockCharacter}
onRegenerateAsset={handleRegenerateAsset}
onGenerateVideo={handleGenerateVideo}
/>
</section> </section>
)} )}
</div> </div>

View File

@@ -2,72 +2,6 @@
import type { GenSession } from '@/lib/types'; import type { GenSession } from '@/lib/types';
function modeLabel(mode?: GenSession['inputMode']) {
if (mode === 'remix') return '二创';
if (mode === 'replicate') return '复刻';
if (mode === 'extend') return '补全';
return '想法';
}
function imageSourcesForSession(session: GenSession) {
const uploaded = session.uploadedImages?.map(image => ({
url: image.url,
label: image.role === 'subject' ? '主体图' : image.role === 'reference' ? '参考图' : image.accessoryName || image.role,
})) ?? [];
if (uploaded.length) return uploaded;
return session.refImages.map((url, index) => ({ url, label: `参考 ${index + 1}` }));
}
function ActiveSessionDetail({ session }: { session: GenSession }) {
const refs = imageSourcesForSession(session);
const selectedCount = session.images.filter(image => image.status === 'selected').length;
const packCount = session.packs?.length ?? 0;
return (
<div className="rounded-[8px] border border-[#e6f578]/18 bg-black/28 p-4 shadow-[0_18px_50px_-34px_rgba(230,245,120,0.72)]">
<div className="flex items-center justify-between gap-2">
<span className="text-[9px] uppercase tracking-[0.18em] text-[#e6f578]/60">Session</span>
<span className="rounded-full border border-white/10 bg-white/[0.04] px-2 py-0.5 text-[9px] text-white/42">
{modeLabel(session.inputMode)}
</span>
</div>
<div className="mt-3 line-clamp-4 text-[12px] font-medium leading-relaxed text-white/82">
{session.characterSpec?.name || session.prompt}
</div>
<div className="mt-3 grid grid-cols-3 gap-1.5 text-[9px] text-white/44">
<div className="rounded-[6px] bg-white/[0.045] px-2 py-1.5">
<div></div>
<b className="mt-0.5 block text-[11px] text-white/78">{session.images.length}</b>
</div>
<div className="rounded-[6px] bg-white/[0.045] px-2 py-1.5">
<div></div>
<b className="mt-0.5 block text-[11px] text-[#e6f578]">{selectedCount}</b>
</div>
<div className="rounded-[6px] bg-white/[0.045] px-2 py-1.5">
<div></div>
<b className="mt-0.5 block text-[11px] text-white/78">{packCount}</b>
</div>
</div>
{refs.length > 0 && (
<div className="mt-3">
<div className="mb-1.5 text-[9px] uppercase tracking-[0.14em] text-white/32">Reference</div>
<div className="grid grid-cols-4 gap-1.5">
{refs.slice(0, 4).map((ref, index) => (
<div key={`${ref.url}-${index}`} className="relative aspect-square overflow-hidden rounded-[6px] bg-white ring-1 ring-white/10">
<img src={ref.url} alt={ref.label} className="h-full w-full object-contain" />
</div>
))}
</div>
</div>
)}
<div className="mt-3 flex items-center justify-between gap-2 text-[9px] text-white/36">
<span>{new Date(session.createdAt).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}</span>
<span className="font-mono">{session.id.slice(0, 10)}</span>
</div>
</div>
);
}
export default function Sidebar({ export default function Sidebar({
open, open,
onToggle, onToggle,
@@ -99,10 +33,8 @@ export default function Sidebar({
); );
} }
const activeSession = sessions.find(session => session.id === currentId) ?? null;
return ( return (
<aside className="relative flex shrink-0 items-stretch overflow-visible"> <aside className="flex shrink-0 items-stretch">
<div className="glass-sidebar w-72 shrink-0 flex flex-col"> <div className="glass-sidebar w-72 shrink-0 flex flex-col">
<div className="px-4 pt-5 pb-3 flex items-center gap-3"> <div className="px-4 pt-5 pb-3 flex items-center gap-3">
<div className="w-8 h-8 rounded-[8px] bg-gradient-to-br from-[#e6f578] to-[#d6b36a] flex items-center justify-center shadow-glow-violet"> <div className="w-8 h-8 rounded-[8px] bg-gradient-to-br from-[#e6f578] to-[#d6b36a] flex items-center justify-center shadow-glow-violet">
@@ -186,23 +118,6 @@ export default function Sidebar({
4560 · / data 4560 · / data
</div> </div>
</div> </div>
{activeSession && (
<div className="absolute left-[calc(100%-1px)] top-0 z-20 w-80 pl-3">
<div className="glass-sidebar relative overflow-hidden rounded-[8px] border-l border-[#e6f578]/10 shadow-[0_30px_80px_-40px_rgba(0,0,0,0.9)]">
<div className="h-full overflow-y-auto px-4 py-5">
<div className="mb-3 flex items-center justify-between gap-3">
<div>
<div className="text-[10px] font-semibold uppercase tracking-[0.18em] text-[#e6f578]/70">Detail</div>
<div className="mt-1 text-[12px] text-white/45"></div>
</div>
<span className="h-2 w-2 rounded-full bg-[#e6f578] shadow-[0_0_18px_rgba(230,245,120,0.75)]" />
</div>
<ActiveSessionDetail session={activeSession} />
</div>
</div>
</div>
)}
</aside> </aside>
); );
} }