Files
pad/web
xarmian 00d529d325 fix(editor): add NodeView update() hook to AttachmentChip (TASK-1251) (#449)
* fix(editor): add NodeView update() hook to AttachmentChip (TASK-1251)

Audit confirmed the same gap pattern as BUG-1246 (mermaid) /
TASK-1250 (attachment-image): closure-captured uuid + filename, no
update() hook, so any attr change forces NodeView destroy+recreate.
No in-tab attr-change source today (no rotate/crop on chips), but
the upcoming Yjs collab work makes peer-driven uuid/filename swaps
the common case — destroying the NodeView on every peer keystroke
of a rename would jump the cursor and flicker the chip.

Refactor closure state to be mutable, add update() that:
- Returns false on type mismatch (defensive — should never fire for
  an attachmentChip).
- On uuid change: refresh href + data-attachment-id, reset MIME +
  size pending re-probe, re-fire the HEAD metadata fetch (with
  in-flight guard so a stale probe doesn't trample fresher state).
- On filename change: refresh data-filename, download attribute,
  visible name, and (only when MIME unknown) re-derive the
  filename-extension fallback icon.

Click handler now reads currentUuid (mutable) so a peer-swapped
chip target opens the new attachment, not the original.

Parent: PLAN-1248. Phase 0 — Production prerequisites complete.

* fix(editor): always refresh chip icon on rename per Codex review (round 1)

P3: refreshIcon() falls back to the filename-extension heuristic
whenever iconForMime() returns empty — both MIME-unknown and
MIME-known-but-unmapped (e.g. application/octet-stream) hit the same
fallback path. The previous `if (!currentMime) refreshIcon()` was too
narrow; renaming foo.csv → foo.pdf after a generic MIME resolved would
leave the stale .csv icon until the NodeView was recreated.

Drop the conditional. refreshIcon() is idempotent for MIMEs that DO
map to a specific icon (just rewrites the same emoji), so calling it
on every filename change is correct and trivially cheap.
2026-05-08 13:13:25 -04:00
..
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00

Pad Web UI

SvelteKit 2 + Svelte 5 frontend for Pad, compiled to static files and embedded into the Go binary.

Development

npm install
npm run dev          # Dev server at localhost:5173 (proxies API to localhost:7777)
npm run build        # Production build to build/
npm run check        # Type checking with svelte-check

When developing, run the Go backend separately with make dev from the project root.

Building for Production

Do not build in isolation. Always use make build from the project root — this builds the web frontend, then compiles the Go binary with the build output embedded via //go:embed.

Stack

  • Svelte 5 with runes ($state, $derived, $effect)
  • SvelteKit 2 with adapter-static (SPA mode)
  • Tiptap block editor with markdown round-trip
  • svelte-dnd-action for drag-and-drop in board/list views
  • SSE for real-time updates
  • TypeScript throughout

Structure

src/
  routes/                    SvelteKit pages
    +layout.svelte           App shell (sidebar + main)
    +page.svelte             Landing/redirect
    [workspace]/
      +page.svelte           Dashboard (collections, phases, activity)
      +layout.svelte         SSE connection per workspace
      [collection]/
        +page.svelte         Collection view (board/list)
      [collection]/[item]/
        +page.svelte         Item detail + editor
      conventions/            Purpose-built conventions page
      playbooks/              Purpose-built playbooks page
      settings/               Workspace settings
  lib/
    api/client.ts            HTTP API client
    components/
      layout/                Sidebar, navigation
      editor/                Tiptap editor, raw markdown editor
      fields/                FieldEditor, relation picker
      items/                 ItemCard, ItemDetail
      collections/           BoardView, ListView
      common/                StatusBadge, badges, modals
      search/                CommandPalette
      activity/              ActivityFeed
    stores/                  Svelte 5 reactive stores
      workspace.svelte.ts    Workspace state
      collections.svelte.ts  Collection + item state
      ui.svelte.ts           Sidebar, mobile state
    types/index.ts           TypeScript types and constants
  app.css                    Global styles and design tokens