mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-22 02:23:46 +00:00
50975e7b91
* fix: sidebar + button for new collections, desktop sidebar reopen affordance, auto-resizing title editor - Add "+" button next to Collections header in sidebar to open CreateCollectionModal (IDEA-130) - Show a chevron tab at the left edge when sidebar is hidden on desktop so users can reopen it without knowing the keyboard shortcut (IDEA-131) - Switch item title editor from single-line input to auto-resizing textarea so long titles are fully visible while editing (BUG-27) * fix: reduce editor save jitter by increasing debounce and wiring up SSE guards Three root causes for BUG-25 (page jumps, stutters, lost keystrokes while typing): 1. Debounce too short (500ms → 1200ms): fast typists frequently pause ~500ms between words, triggering saves mid-thought 2. Item page never updated editorStore.lastSaveTime or dirty flag, so the SSE handler's 2-second guard never activated — every self-triggered save caused an SSE item_updated → re-fetch → store update cycle 3. saveStatus was set to 'saving' on every keystroke (before debounce), causing unnecessary re-renders; now only set when save actually fires Also sets collectionStore.activeItem from the item page so the SSE handler's active-item guard works correctly. * fix: suppress timeline refresh during active content editing The ItemTimeline's SSE handler was re-fetching the entire timeline on every item_updated event, including self-triggered content saves. This caused visible re-rendering/shakiness in the timeline section each time the debounce fired. Now skips item_updated events within 3 seconds of the last editor save, matching the existing SSE guard pattern. * fix: eliminate spurious network requests from self-triggered SSE events Each content save was causing 3 network requests instead of 1: the save itself, plus /collections and /children re-fetches triggered by the SSE item_updated event echoing back from our own save. - Workspace layout SSE handler: skip all side-effects (loadCollections, item refetch) for self-triggered content saves using editorStore.dirty and lastSaveTime guards - ChildItems SSE handler: skip item_updated events from self-saves since content edits can't affect children - Timeline SSE handler: remove item_updated from relevant events entirely (version diffs appear on next natural refresh); debounce remaining events to prevent rate-limit errors from SSE replay on reconnect * feat: collapsible topbar, sidebar close buttons, quick-add modal, rate limit bump - Topbar: centered workspace list, collapsible via chevron button or Cmd-\, hover-reveal expand tab when hidden, persisted to localStorage - Sidebar: added close button in footer for independent hiding - Cmd-\ now toggles both sidebar and topbar together - Quick-add: sidebar + buttons and "New Item" button open a modal with auto-resizing textarea for title input instead of creating "Untitled" items (IDEA-132, IDEA-133) - Dashboard "New Idea"/"New Task" buttons now link to /new form page - API rate limit bumped from 100/min to 600/min — more appropriate for a local-first tool with SSE-driven UI cascading refreshes * fix: board view drag-and-drop snap-back and re-render cascade Root cause: isDragging was set to false before the async onStatusChange API call, triggering a reactive $effect that overwrote columnData with stale positions — item snapped back to the original column then bounced to the new one. Additionally, handleReorder fired per-item API calls that each triggered SSE events, causing cascading re-renders. - Add dropCooldown flag that freezes columnData for 2s after a drop, preventing the $effect from overwriting the visual state while API calls and SSE events settle - Only persist sort_order for items whose order actually changed - On failed moves: skip reorder, immediately drop cooldown so the original state restores cleanly to the correct position - handleStatusChange re-throws on failure so BoardView can distinguish success from failure * feat: add theme toggle and quick-add modal to sidebar - Light/dark mode toggle button in sidebar footer row (sun/moon icon), to the left of the notification bell (IDEA-134) - Quick-add modal with auto-resizing textarea for title input, triggered from per-collection + buttons and "New Item" button (IDEA-132, IDEA-133) - Removed old "Untitled" item creation flow from sidebar * fix: remove all /new page references, use quick-add modal and inline create - Empty collection "Create" button now opens the inline quick-create input instead of navigating to /new (BUG-29) - Cmd-N opens the sidebar quick-add modal (defaults to active collection or Tasks) instead of navigating to /new - Dashboard "New Idea"/"New Task" buttons trigger quick-add modal - Onboarding checklist links go to collection pages instead of /new - Cleaned up dead quickCreate function and unused imports from dashboard * chore: remove dead /new page route All item creation now goes through the sidebar quick-add modal or collection page inline create. The /new form page is no longer referenced anywhere.
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