Finishes UI5 and kicks off UI7 by migrating the remaining form-heavy components plus the note-detail right-rail panels. Drops legacy class matches from 92 → 67 (-25) and raw interactive controls from 38 → 25 (-13). Ratchet baseline updated to the new floor. Components migrated: UI5 finish: - NoteEditor.tsx — surface-card wrapper → Card, title input → Input, Tiptap editor className updated to use border + bg classes instead of input-shell. Toolbar buttons left as raw (intentional, tightly styled icon controls). - SmartActionsPanel.tsx — result panel surface-muted → Tailwind bg-[var(--nl-surface-muted)] utility. - ArtifactPanel.tsx — section→Card, badge→Badge, all three input-shell inputs/selects/textareas→Input/Select/Textarea, surface-muted form shell + per-artifact row → Tailwind bg-utility, raw <button> Open → Button. - CommandPalette.tsx — surface-card command sheet → Tailwind layered classes, search input → Input (now ref-forwarded), kind badge → Badge. UI7 component pass: - MetadataPanel.tsx — section→Card, tag badge→Badge. - LinkedNotesPanel.tsx — section→Card, surface-muted link row → Tailwind bg-utility with hover state. - PalaceStats.tsx — section→Card, inline styles → Tailwind utilities. - ExtractedTasksPanel.tsx — surface-muted row → Tailwind. - NoteVersionsPanel.tsx — all three section/surface-card variants → Card + raw button → preserved (interactive disclosure). - Pagination.tsx — raw <button> Previous/Next → Button, surface-muted → built-in secondary variant. - TaskReviewPanel.tsx — full migration: section→Card, badge→Badge, input-shell + textarea + raw button → Input/Textarea/Button. - SurveyBanner.tsx — survey answer input-shell → Input. Adapter changes: - web/src/components/ui/Primitives.tsx — Input and Textarea now use React.forwardRef so callers like CommandPalette can attach refs. Verified: - pnpm --filter @notelett/web run typecheck: passes - pnpm --filter @notelett/web test: 96/96 still pass - pnpm run audit:ui:ratchet: at new baseline (25/67/0/0) - pnpm run audit:ui: legacy class matches now in dashboard / search / workspaces / notes-detail / palace / chat pages (UI6/UI7 page targets)
53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { Card } from "@/components/ui/Primitives";
|
|
import { getPalaceStats, type PalaceStats as PalaceStatsData } from "@/lib/palace-client";
|
|
|
|
export function PalaceStats() {
|
|
const [stats, setStats] = useState<PalaceStatsData | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
void (async () => {
|
|
try {
|
|
const data = await getPalaceStats();
|
|
setStats(data);
|
|
} catch {
|
|
setError("Failed to load palace stats");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
})();
|
|
}, []);
|
|
|
|
if (loading) return <div style={{ color: "var(--nl-text-secondary)" }}>Loading stats...</div>;
|
|
if (error) return <div style={{ color: "var(--nl-status-error)" }}>{error}</div>;
|
|
if (!stats) return null;
|
|
|
|
const items = [
|
|
{ label: "Wings", value: stats.wings },
|
|
{ label: "Rooms", value: stats.rooms },
|
|
{ label: "Memories", value: stats.memories },
|
|
{ label: "KG Triples", value: stats.kgTriples },
|
|
];
|
|
|
|
return (
|
|
<Card padding="md">
|
|
<div className="mb-3 text-[length:var(--nl-text-lg)] font-bold">Memory Palace</div>
|
|
<div className="grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(100px,1fr))]">
|
|
{items.map(({ label, value }) => (
|
|
<div
|
|
key={label}
|
|
className="rounded-[var(--nl-radius-md)] border border-[color:var(--nl-border-subtle)] p-3 text-center"
|
|
>
|
|
<div className="text-2xl font-bold text-[color:var(--nl-accent-primary)]">{value}</div>
|
|
<div className="text-xs text-[color:var(--nl-text-secondary)]">{label}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|