Files
pad/web
xarmian 634e834f22 feat(board): Trello-style inline draft card creation (TASK-1676) (#678)
* feat(board): Trello-style inline draft card creation (TASK-1676)

Replace the lane `+` direct-navigate (TASK-1671) with an inline draft
card. Clicking `+` (or "Add item here") opens an editable card in the
lane — no item exists yet. Enter creates it (group value pre-filled) and
opens it; blur keeps the card without saving; Escape hides it but
retains the text so reopening restores it (until reload). Drafts are
per-lane and in-memory.

A beforeNavigate guard intercepts in-app navigation while any lane has
unsaved draft text and shows a Save / Discard / Stay dialog: Save
creates all pending drafts (in place, no navigate) then proceeds,
Discard drops them, Stay cancels. Reload/tab-close aren't guarded (nav.to
is null) — drafts intentionally live only until reload.

quickCreateInColumn now takes (groupValue, title, navigate) and returns
the created item / throws so the draft can be restored on failure. The
draft card renders above the dndzone so it isn't draggable.

* fix(board): lift draft state to page + clear-each-on-save per Codex review (round 1)

(1) BoardView unmounts on a board↔list view switch, which destroyed
unsaved inline drafts and bypassed the leave guard. Move the draft state
(draftText/draftOpen) to the page and bind it into BoardView, and move
the beforeNavigate guard + Save/Discard/Stay dialog to the page (always
mounted). A draft now survives view switches (state persists; the card
just isn't rendered off-board) and the guard fires regardless of view.

(2) leaveSaveAll cleared all drafts only after the whole loop, so a
retry after a partial failure re-created already-saved drafts. Clear
each draft as its create succeeds.

* fix(board): only guard true leaves, not same-page URL syncs per Codex review (round 2)

beforeNavigate fired on every goto while a draft existed — including the
replaceState query/view-state syncs from updateUrlFilters (view toggle,
filters, search). Switching Board→List or tweaking a filter wrongly
opened the Save/Discard dialog. Skip navigations whose destination
pathname equals the current one (internal same-page sync); the draft
survives those as page state, so only true page leaves are guarded.

* fix(board): don't guard willUnload navigations per Codex review (round 3)

For native/external navigations (willUnload), goto can't replay the leave
after cancel, so Save/Discard could strand the user. Skip guarding
willUnload (and full-unload) navigations — treated like reload, drafts
intentionally lost — so the replay path is always a client-side goto.

* fix(board): replay Back/Forward with history.go to preserve history per Codex review (round 4)

Cancelling a popstate (Back/Forward) navigation then replaying via
goto(url) pushed the target as a new history entry, corrupting Back.
Capture nav.type/nav.delta and replay popstate with history.go(delta);
non-popstate leaves still replay with goto.
2026-05-30 23:38:23 -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