learning_ai_notes/web/src/components/PalaceStats.tsx
saravanakumardb1 2408f43426 feat(web/ui5+ui7): migrate 12 components to @bytelyst/ui primitives
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)
2026-05-23 01:33:48 -07:00

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>
);
}