Per organized-ideas.md §8: the storage layer (DiagramRepository etc.) was already renamed in an earlier phase; this finishes it everywhere else. - domain/types.ts: Project -> Diagram. domain/project.ts -> domain/diagram.ts (createEmptyProject -> createEmptyDiagram, default name "Untitled Diagram"). - domain/compatibility.ts, domain/bom.ts: Project param/type -> Diagram. - data/exportImport.ts: ProjectImportError -> DiagramImportError, projectToJson/downloadProjectFile/readProjectFile/normalizeProject -> their Diagram equivalents. - state/projectStore.ts -> state/diagramStore.ts: useProjectStore -> useDiagramStore, the `project` field -> `diagram`, newProject/renameProject/ importProject/applyRestoredProject -> *Diagram, restoredProjectUpdatedAt -> restoredDiagramUpdatedAt. - Every component updated to match, compiler-guided (tsc -b enumerated each remaining call site after the core rename, the same approach used for the earlier catalog-parameter refactor). - README updated for the terminology, and to match the repository class names (which had already been renamed but the README hadn't caught up). No backend/schema changes: the JSON shape stored in diagrams.data never changed, only TypeScript-side identifiers, so existing diagrams are unaffected. One SQL comment fixed for accuracy (no migration needed). Verified: tsc -b and oxlint clean; grepped src/ for any remaining Project/project reference (none) after the sweep.
96 lines
3.4 KiB
TypeScript
96 lines
3.4 KiB
TypeScript
import { useEffect } from 'react'
|
|
import { useDiagramStore } from '../../state/diagramStore'
|
|
import Modal from '../common/Modal'
|
|
|
|
function formatUpdatedAt(iso: string): string {
|
|
const date = new Date(iso)
|
|
return date.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' })
|
|
}
|
|
|
|
export default function DiagramManagerModal({ onClose }: { onClose: () => void }) {
|
|
const diagram = useDiagramStore((s) => s.diagram)
|
|
const diagramList = useDiagramStore((s) => s.diagramList)
|
|
const refreshDiagramList = useDiagramStore((s) => s.refreshDiagramList)
|
|
const newDiagram = useDiagramStore((s) => s.newDiagram)
|
|
const switchToDiagram = useDiagramStore((s) => s.switchToDiagram)
|
|
const deleteDiagram = useDiagramStore((s) => s.deleteDiagram)
|
|
|
|
useEffect(() => {
|
|
refreshDiagramList()
|
|
}, [refreshDiagramList])
|
|
|
|
const handleOpen = async (id: string) => {
|
|
if (id === diagram.id) return
|
|
await switchToDiagram(id)
|
|
onClose()
|
|
}
|
|
|
|
const handleNew = async () => {
|
|
await newDiagram()
|
|
onClose()
|
|
}
|
|
|
|
const handleDelete = async (id: string, name: string) => {
|
|
const confirmed = window.confirm(
|
|
diagramList.length === 1
|
|
? `Delete "${name}"? This is your only diagram, so a fresh empty one will replace it.`
|
|
: `Delete "${name}"? This can't be undone.`,
|
|
)
|
|
if (!confirmed) return
|
|
await deleteDiagram(id)
|
|
}
|
|
|
|
return (
|
|
<Modal title="Diagrams" onClose={onClose} width="max-w-lg">
|
|
<div className="space-y-3">
|
|
<button
|
|
onClick={handleNew}
|
|
className="w-full rounded bg-indigo-600 py-1.5 text-xs font-medium text-white hover:bg-indigo-500"
|
|
>
|
|
+ New Diagram
|
|
</button>
|
|
|
|
<ul className="space-y-1">
|
|
{diagramList.map((d) => {
|
|
const isCurrent = d.id === diagram.id
|
|
return (
|
|
<li
|
|
key={d.id}
|
|
className={`group flex items-center justify-between gap-2 rounded border px-3 py-2 text-xs ${
|
|
isCurrent ? 'border-indigo-300 bg-indigo-50' : 'border-slate-200 bg-white'
|
|
}`}
|
|
>
|
|
<button
|
|
onClick={() => handleOpen(d.id)}
|
|
disabled={isCurrent}
|
|
className="min-w-0 flex-1 text-left disabled:cursor-default"
|
|
>
|
|
<div className="flex items-center gap-1.5">
|
|
<span className="truncate font-medium text-slate-700">{d.name}</span>
|
|
{isCurrent && (
|
|
<span className="shrink-0 rounded bg-indigo-100 px-1 text-[10px] font-medium text-indigo-700">
|
|
current
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="truncate text-[10px] text-slate-400">Updated {formatUpdatedAt(d.updatedAt)}</div>
|
|
</button>
|
|
<button
|
|
onClick={() => handleDelete(d.id, d.name)}
|
|
title="Delete this diagram"
|
|
className="shrink-0 rounded px-1.5 py-0.5 text-slate-400 opacity-0 hover:bg-red-50 hover:text-red-600 group-hover:opacity-100"
|
|
>
|
|
✕
|
|
</button>
|
|
</li>
|
|
)
|
|
})}
|
|
{diagramList.length === 0 && (
|
|
<p className="py-2 text-center text-xs italic text-slate-400">No diagrams yet.</p>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
</Modal>
|
|
)
|
|
}
|