Files
pad/web
xarmian 350e8ef576 feat(web): saved view defaults applied on collection-page entry (TASK-1366) (#512)
* feat(web): saved view defaults applied on collection-page entry (TASK-1366)

Phase 3d of the local-first read model (PLAN-1343 / DOC-1342): per
the design note's recommendation, persist the user's preferred saved
view per (workspace, collection) in localStorage and re-apply it on
mount. No schema change in v1; cross-device sync can come later as a
server-side `is_default` column on saved views.

Behavior
- localStorage key: `pad-default-view:<wsSlug>:<collSlug>` → view id.
- On collection-page mount, after `savedViews` loads, look up the
  default and call `applyViewConfig` automatically.
- URL-driven state wins: if the user arrived via a shared link with
  `?q=...` or `?status=...`, the default is skipped so the link's
  intent isn't hijacked.
- "Make default" / "Default ★" toggle next to the saved-views bar
  flips the persistence state for the currently active view. The
  active default also renders a small pin icon on its tab so users
  can see which view is current at a glance.
- `deleteView` clears a dangling localStorage pointer when the
  default view is the one being removed.
- localStorage failures (private mode, quota) degrade silently — the
  toggle still works for the session.

Out of scope (deferred to a future PR)
- Cross-device sync via a server-side `is_default` column.
- Sharing defaults across workspace members.
- Auto-save view config changes back to the underlying saved view.

Parent: PLAN-1343. Completes Phase 3 of DOC-1342.

* fix(web): gate default-view apply on metaLoading per Codex review (round 1)

Codex round 1 P1 #1: `loadCollection` flips `metaLoading=true` at
entry, assigns `savedViews` mid-flight, then calls
`loadUrlFilters()` synchronously near the end, and only flips
`metaLoading=false` in the `finally` block. My default-view
effect tracked `savedViews` and ran as soon as it changed — so
a shared link like `?q=foo` could land in the local state AFTER
the savedViews assignment but BEFORE `loadUrlFilters` populated
`searchQuery`. The effect saw an empty searchQuery, thought there
were no URL overrides, and applied the default — clobbering the
incoming URL.

Codex round 1 P1 #2: on client-side navigation across collections,
`defaultViewApplied` got reset by the route-change effect but
`savedViews` still held the PREVIOUS collection's views until the
new fetch resolved. The default-apply effect would run with the
wrong list, fail to find the new collection's default view id in
the stale list, and ERASE the localStorage pointer — wiping the
default on every cross-collection navigation.

Gate the effect on `!metaLoading`. `metaLoading=false` only
fires after BOTH the new `savedViews` is assigned AND
`loadUrlFilters()` has run, so both races are eliminated.

* fix(web): URL-override check reads page.url directly per Codex review (round 2)

Codex round 2 P1: `?view=board` URLs are explicit user intent but
my urlOverrides check only looked at `searchQuery` and
`activeFilters`, so view-only URLs would be overwritten by the
default-view apply.

Codex round 2 P2: `loadUrlFilters` doesn't clear absent params, so
parsed `searchQuery` / `activeFilters` can carry leftover values
from the previous route on cross-collection navigation. A clean
URL on the new route would then look "overridden" via stale
parsed state, and the default would be incorrectly skipped.

Both fixed by reading `page.url.searchParams.size` directly. The
collection page only writes user-driven params (view, q, field
filters), so any non-empty searchParams signals explicit intent.
2026-05-12 01:08:38 -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