mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-11 13:28:57 +00:00
d4da83d2cd
Three fixes from the final full-diff review of phase 3b. 1. RE-CLAMP on a same-id decode. `loadKey` includes the pixel dimensions, so an async dimension fill re-runs the load — but the reset effect keys on `img.id` only and the ResizeObserver watches only the stage, so neither re-clamps the transform. The concrete failure: the unknown-dims desktop cell loads the original; dims fill; the policy switches to thumb-md; the thumb's smaller natural size lowers actualScale and MAX_SCALE, stranding the scale above the new ceiling with out-of-bounds pan. Re-clamp (clampState + rebaseDrag — not a reset; a valid zoom survives) in the <img> onload handler, where geometry is first measurable, fenced to the live element (el === imgEl) so a stale detached decode can't drive the current zoom. 2. INERT error state. `errored()` flips only the phase and leaves `displaySrc` set, so the broken <img> still satisfied readGeometry and every gesture entry point acted over the error UI with nothing decoded. `bitmapPresent` now also requires `phase !== 'error'`, and the wheel, double-click and live drag-move paths (which read geometry directly) bail on it too — a drag armed before the error aborts on its next move. All re-enable after a successful retry. 3. Three stale doc comments updated to the assembled contracts: the Lightbox header no longer claims original-only loading, and the "upload event carries only four fields" notes in Lightbox and ItemAttachmentStrip now reflect UploadedAttachment carrying the pixel dimensions since TASK-2459. Three new mutation-checked unit tests (each fails when its fix is reverted); zoom e2e spec re-run green on both projects. Claude-Session: https://claude.ai/code/session_01WFBYxdBuSZs2tjipATxAZu
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