Replaces the read-only stats dashboard with a three-pane wiki: a navigator tree (group by folder/type/tag/entity), a reader/editor with bare-slug auto-linking and revision history + diff, and a context rail for backlinks and related notes. Adds a Cleanup mode for the drift tools (duplicates, tag manager, orphans, trash) and a Cmd+K quick-open. Also: - Adds a real landing view (hero count, KPI row, Nomos-share meter, recently-updated, busiest tags) in place of the old "Select a note" empty state, and extends the design pass across the tree/reader/rail (kind icons instead of repeated text badges, accent-bar selection, constrained prose measure). - Guards every note-selection path behind a confirm when there's an unsaved edit in progress, so switching notes can no longer silently discard a draft. - Extracts the markdown-rendering CSS duplicated across ChatThread, EntityDetailContent, and the new WikiReader into a shared .markdown-body class in app.css, with ChatThread keeping only its decorative deltas. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
51 lines
2.3 KiB
TypeScript
51 lines
2.3 KiB
TypeScript
// Per-kind presentation, shared by the tree, the overview, and anywhere else
|
|
// a note's kind needs to be shown at a glance.
|
|
//
|
|
// Kind is encoded by **icon shape**, not colour. Three categories would be a
|
|
// categorical palette, and at the 12px mark size the tree uses, colour alone
|
|
// is the least reliable channel there is — it fails for colour-vision
|
|
// deficiency, and small low-chroma marks on a dark surface are hard for
|
|
// anyone to tell apart. Distinct silhouettes are legible at any size, in any
|
|
// theme, for every reader. Colour is left to carry state (selection, the
|
|
// agent badge), where it isn't the only thing distinguishing two items.
|
|
//
|
|
// It also fixes a plain redundancy: the tree previously stamped a literal
|
|
// "document" text badge on every row, which in a folder of 20 documents is
|
|
// 20 repetitions of the same word and no information at all.
|
|
import FileTextIcon from '@lucide/svelte/icons/file-text'
|
|
import MicroscopeIcon from '@lucide/svelte/icons/microscope'
|
|
import ListChecksIcon from '@lucide/svelte/icons/list-checks'
|
|
import type { Component } from 'svelte'
|
|
|
|
export type NoteKind = 'document' | 'investigation' | 'runbook'
|
|
|
|
export interface KindMeta {
|
|
icon: Component
|
|
label: string
|
|
/** Plural, for counts and section headings. */
|
|
plural: string
|
|
}
|
|
|
|
const FALLBACK: KindMeta = { icon: FileTextIcon, label: 'note', plural: 'notes' }
|
|
|
|
const KIND_META: Record<NoteKind, KindMeta> = {
|
|
document: { icon: FileTextIcon, label: 'document', plural: 'documents' },
|
|
investigation: { icon: MicroscopeIcon, label: 'investigation', plural: 'investigations' },
|
|
runbook: { icon: ListChecksIcon, label: 'runbook', plural: 'runbooks' }
|
|
}
|
|
|
|
// Tolerates an unknown kind rather than throwing — `kind` comes from the
|
|
// entity's type column, which the ontology could grow a fourth value for
|
|
// without this file knowing.
|
|
export function kindMeta(kind: string): KindMeta {
|
|
return KIND_META[kind as NoteKind] ?? FALLBACK
|
|
}
|
|
|
|
// True for notes last written by the agent rather than a human. Two spellings
|
|
// exist in the live data: 'nomos-agent' (written via the MCP upsert_knowledge
|
|
// tool) and 'agent:mcp' (the actor label the HTTP API records when the same
|
|
// agent calls in over REST with the MCP bearer token).
|
|
export function isAgentAuthored(editedBy: string): boolean {
|
|
return editedBy === 'nomos-agent' || editedBy === 'agent:mcp'
|
|
}
|