feat: add command palette, accessibility, scroll animations, demo workspace, and keyboard navigation

- COMP-139: Command palette for quick navigation
- COMP-140: Accessibility improvements
- COMP-141: Scroll animations with animate-on-scroll component
- COMP-143: Demo workspace with seed data and demo banner
- COMP-145: Keyboard navigation and shortcuts help

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Vectry
2026-02-10 18:06:36 +00:00
parent f9e7956e6f
commit 64c827ee84
18 changed files with 2047 additions and 40 deletions

View File

@@ -1,24 +1,29 @@
import { Suspense } from "react";
import { TraceList } from "@/components/trace-list";
import { DemoSeedTrigger } from "@/components/demo-seed-trigger";
import { DemoBanner } from "@/components/demo-banner";
export const dynamic = "force-dynamic";
interface TraceItem {
id: string;
name: string;
status: "RUNNING" | "COMPLETED" | "ERROR";
startedAt: string;
endedAt: string | null;
durationMs: number | null;
tags: string[];
metadata: Record<string, unknown>;
isDemo?: boolean;
_count: {
decisionPoints: number;
spans: number;
events: number;
};
}
interface TracesResponse {
traces: Array<{
id: string;
name: string;
status: "RUNNING" | "COMPLETED" | "ERROR";
startedAt: string;
endedAt: string | null;
durationMs: number | null;
tags: string[];
metadata: Record<string, unknown>;
_count: {
decisionPoints: number;
spans: number;
events: number;
};
}>;
traces: TraceItem[];
total: number;
page: number;
limit: number;
@@ -55,14 +60,21 @@ async function getTraces(
export default async function DashboardPage() {
const data = await getTraces(50, 1);
const hasTraces = data.traces.length > 0;
const allTracesAreDemo =
hasTraces && data.traces.every((t) => t.isDemo === true);
return (
<Suspense fallback={<div className="p-8 text-zinc-400">Loading traces...</div>}>
<TraceList
initialTraces={data.traces}
initialTotal={data.total}
initialTotalPages={data.totalPages}
initialPage={data.page}
/>
</Suspense>
<DemoSeedTrigger hasTraces={hasTraces}>
{allTracesAreDemo && <DemoBanner allTracesAreDemo={allTracesAreDemo} />}
<Suspense fallback={<div className="p-8 text-zinc-400">Loading traces...</div>}>
<TraceList
initialTraces={data.traces}
initialTotal={data.total}
initialTotalPages={data.totalPages}
initialPage={data.page}
/>
</Suspense>
</DemoSeedTrigger>
);
}