/** * Snippet Library — the left pane (spec §02). * * M1 scope: the always-visible list with a pinned "Create New Snippet" item, * selection/highlight, and delete. Search, sort controls, the metadata panel, * status/dataset indicators, and the storage monitor arrive in later milestones. */ import { useShallow } from 'zustand/react/shallow'; import { useSnippetStore } from '../stores/SnippetStore'; import styles from './SnippetLibrary.module.css'; /** Compact relative date for the list (full date formatting lands in M5). */ function relativeDate(iso: string): string { const then = new Date(iso); const now = new Date(); const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const dayMs = 24 * 60 * 60 * 1000; const days = Math.floor( (startOfToday.getTime() - new Date(then.getFullYear(), then.getMonth(), then.getDate()).getTime()) / dayMs, ); if (days <= 0) return 'Today'; if (days === 1) return 'Yesterday'; if (days < 7) return `${days}d ago`; return then.toLocaleDateString(); } export function SnippetLibrary() { const snippets = useSnippetStore(useShallow((s) => s.snippets)); const activeId = useSnippetStore((s) => s.activeSnippetId); const createSnippet = useSnippetStore((s) => s.createSnippet); const selectSnippet = useSnippetStore((s) => s.selectSnippet); const removeSnippet = useSnippetStore((s) => s.removeSnippet); // Default ordering: newest-modified first (spec §02 → Sort). const ordered = [...snippets].sort((a, b) => b.modified.localeCompare(a.modified)); const handleDelete = (id: string, name: string) => { // TODO: M1 stopgap — route destructive confirms through the modal coordinator // (docs/architecture/03) when the modal system lands, and surface a deletion // toast (spec §02), instead of the native window.confirm. if (window.confirm(`Delete "${name}"? This cannot be undone.`)) removeSnippet(id); }; return (
); }