feat: add operational timeline workspace

This commit is contained in:
2026-08-19 16:42:41 +08:00
parent d2f2895c36
commit 45f1ebee7e
19 changed files with 1127 additions and 105 deletions
@@ -70,7 +70,7 @@ export function AnalysisArtifactWorkspace({
return (
<article
aria-label={`${artifact.title}分析成果`}
className="relative grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden bg-[#eef2f6] text-slate-900"
className="acrylic-panel relative m-3 grid h-[calc(100%-1.5rem)] min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-2xl border text-slate-900"
lang="zh-CN"
>
<ArtifactHeader artifact={artifact} />
@@ -138,7 +138,7 @@ export function AnalysisArtifactWorkspace({
function ArtifactHeader({ artifact }: { artifact: AnalysisArtifact }) {
return (
<header className="relative z-10 bg-white px-4 py-4 shadow-[0_1px_0_rgba(15,23,42,0.08),0_5px_18px_rgba(15,23,42,0.04)] xl:px-5">
<header className="surface-control relative z-10 border-b px-4 py-4 xl:px-5">
<div className="flex items-start justify-between gap-5">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2 text-xs font-medium text-slate-500">
@@ -190,7 +190,7 @@ function AnalysisBlockView({
<section
aria-labelledby={`${block.id}-title`}
className={cn(
"group min-w-0 overflow-hidden bg-white shadow-[0_1px_4px_rgba(15,23,42,0.12)]",
"surface-reading group min-w-0 overflow-hidden rounded-xl border shadow-[0_1px_4px_rgba(15,23,42,0.08)]",
"focus-within:shadow-[0_0_0_2px_rgba(37,99,235,0.35),0_8px_24px_rgba(15,23,42,0.12)]",
spanClass,
selected && "shadow-[0_0_0_2px_rgba(37,99,235,0.28),0_8px_24px_rgba(15,23,42,0.12)]"
@@ -281,11 +281,11 @@ function AnalysisBlockBody({ block }: { block: Exclude<AnalysisBlock, { kind: "m
function ArtifactProvenance({ artifact }: { artifact: AnalysisArtifact }) {
return (
<section className="mt-5 grid gap-3 pb-2 xl:grid-cols-2" aria-label="成果依据与限制">
<div className="bg-[#e7edf3] px-4 py-3.5">
<div className="surface-well rounded-xl border px-4 py-3.5">
<h3 className="flex items-center gap-2 text-xs font-semibold text-slate-800"><Database size={14} aria-hidden="true" /></h3>
<ul className="mt-2 flex flex-wrap gap-2">{artifact.sources.map((source) => <li key={source} className="rounded-md bg-white px-2.5 py-1 text-xs text-slate-600 shadow-[0_1px_2px_rgba(15,23,42,0.08)]">{source}</li>)}</ul>
</div>
<div className="bg-amber-50 px-4 py-3.5">
<div className="material-tone-warning rounded-xl border px-4 py-3.5">
<h3 className="flex items-center gap-2 text-xs font-semibold text-amber-900"><AlertTriangle size={14} aria-hidden="true" /></h3>
<ul className="mt-2 space-y-1 text-xs leading-5 text-amber-900/75">{artifact.limitations.map((item) => <li key={item}> {item}</li>)}</ul>
</div>
@@ -303,7 +303,7 @@ function ArtifactDetailDrawer({
onClose: () => void;
}) {
return (
<aside aria-label="证据详情" className="absolute bottom-[57px] right-0 top-0 z-30 w-full max-w-[420px] overflow-y-auto overscroll-contain bg-white shadow-[-12px_0_36px_rgba(15,23,42,0.18)]">
<aside aria-label="证据详情" className="surface-reading absolute bottom-[57px] right-0 top-0 z-30 w-full max-w-[420px] overflow-y-auto overscroll-contain border-l shadow-[-12px_0_36px_rgba(15,23,42,0.18)]">
<div className="sticky top-0 z-10 flex items-center justify-between bg-slate-950 px-4 py-3 text-slate-100">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.14em] text-blue-300">Evidence detail</p>
@@ -355,7 +355,7 @@ function ArtifactActionBar({
onDestroy: () => void;
}) {
return (
<footer className="relative z-20 flex min-h-14 items-center justify-between gap-3 bg-white px-3 shadow-[0_-1px_0_rgba(15,23,42,0.08),0_-6px_18px_rgba(15,23,42,0.04)]">
<footer className="surface-control relative z-20 mb-[calc(var(--workbench-timeline-height)+0.25rem)] flex min-h-14 items-center justify-between gap-3 border-t px-3">
<div className="flex min-w-0 items-center gap-1">
{artifact.mapRelation !== "none" ? (
<button type="button" onClick={() => onSetView(surfaceMode === "map_split" ? "focus" : mapSplitAvailable ? "map_split" : "map_only")} className="inline-flex h-10 items-center gap-2 rounded-md px-3 text-xs font-semibold text-slate-700 hover:bg-slate-100 active:scale-95">
@@ -392,7 +392,7 @@ function ArtifactPrimaryAction({ action, artifact }: { action: AnalysisArtifactA
function MetricTile({ metric }: { metric: AnalysisMetric }) {
return (
<div className="min-w-0 bg-white px-3.5 py-3 shadow-[0_1px_4px_rgba(15,23,42,0.12)]">
<div className="surface-reading min-w-0 rounded-xl border px-3.5 py-3 shadow-[0_1px_4px_rgba(15,23,42,0.08)]">
<div className="flex items-center gap-2">
<span className={cn("h-2 w-2 rounded-full", metricToneClass(metric.tone))} aria-hidden="true" />
<p className="truncate text-xs font-medium text-slate-500">{metric.label}</p>