Files
Genarrative/src/components/creative-agent/CreativeAgentProcessPanel.tsx
T
kdletters ebf181d53b 收口智能创作过程空态
creative-agent 过程面板空态改用 PlatformEmptyState 承接共享空态外观
同步更新工作台空态测试断言与收口计划文档
补充 Hermes 验证记录保持后续组件收口路径一致
2026-06-10 15:36:44 +08:00

130 lines
4.1 KiB
TypeScript

import {
CheckCircle2,
CircleDot,
Loader2,
TriangleAlert,
} from 'lucide-react';
import { PlatformEmptyState } from '../common/PlatformEmptyState';
import { PlatformIconBadge } from '../common/PlatformIconBadge';
import { PlatformPillBadge } from '../common/PlatformPillBadge';
import { PlatformSubpanel } from '../common/PlatformSubpanel';
import type { CreativeAgentProcessItem } from './creativeAgentViewModel';
type CreativeAgentProcessPanelProps = {
items: CreativeAgentProcessItem[];
isStreaming: boolean;
};
const PROCESS_TONE_CLASS: Record<CreativeAgentProcessItem['tone'], string> = {
active: 'border-[rgba(255,105,145,0.38)] bg-white/82',
done: 'border-emerald-200/80 bg-emerald-50/82',
info: 'border-[var(--platform-subpanel-border)] bg-white/68',
warning: 'border-amber-200/80 bg-amber-50/82',
danger: 'border-red-200/80 bg-red-50/86',
};
function ProcessIcon({ item }: { item: CreativeAgentProcessItem }) {
if (item.tone === 'active') {
return <Loader2 className="h-3.5 w-3.5 animate-spin" />;
}
if (item.tone === 'done') {
return <CheckCircle2 className="h-3.5 w-3.5" />;
}
if (item.tone === 'warning' || item.tone === 'danger') {
return <TriangleAlert className="h-3.5 w-3.5" />;
}
return <CircleDot className="h-3.5 w-3.5" />;
}
export function CreativeAgentProcessPanel({
items,
isStreaming,
}: CreativeAgentProcessPanelProps) {
const visibleItems = items.slice(-12).reverse();
if (visibleItems.length === 0) {
return (
<PlatformEmptyState
surface="subpanel"
size="compact"
className="rounded-[1.35rem] font-semibold"
>
等待新的创作输入
</PlatformEmptyState>
);
}
return (
<PlatformSubpanel
title={
<span className="flex items-center gap-2">
{isStreaming ? (
<Loader2 className="h-3.5 w-3.5 animate-spin" />
) : null}
过程
</span>
}
titleClassName="tracking-[0.16em]"
actions={
<PlatformPillBadge tone="neutral" size="xs">
{items.length}
</PlatformPillBadge>
}
radius="lg"
>
<div className="mt-3 max-h-[22rem] space-y-2 overflow-y-auto pr-1">
{visibleItems.map((item) => (
<article
key={item.id}
className={`rounded-[1rem] border px-3 py-3 ${PROCESS_TONE_CLASS[item.tone]}`}
>
<div className="flex items-start gap-3">
<PlatformIconBadge
icon={<ProcessIcon item={item} />}
size="xs"
tone="soft"
className="mt-0.5"
/>
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-2">
<PlatformPillBadge
tone="muted"
size="xs"
className="px-2 py-0.5"
>
{item.meta}
</PlatformPillBadge>
<div className="min-w-0 flex-1 text-sm font-black leading-5 text-[var(--platform-text-strong)]">
{item.title}
</div>
</div>
{item.detail ? (
<div className="mt-1 text-xs leading-5 text-[var(--platform-text-base)]">
{item.detail}
</div>
) : null}
{item.detailLines.length > 0 ? (
<div className="mt-2 space-y-1">
{item.detailLines.map((line, index) => (
<div
key={`${item.id}-line-${index}`}
className="truncate rounded-[0.7rem] bg-white/58 px-2 py-1 text-[11px] font-semibold leading-4 text-[var(--platform-text-base)]"
title={line}
>
{line}
</div>
))}
</div>
) : null}
</div>
</div>
</article>
))}
</div>
</PlatformSubpanel>
);
}
export default CreativeAgentProcessPanel;