mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-22 02:23:46 +00:00
d1a5ea3975
Follow-up to the BUG-586 fix that surfaced several edge cases under
real-world use. Covers three related improvements to the wiki-link
experience in the editor.
Reference-based wiki-link storage
Previously `[Title](/url)` round-tripped to `[[Title]]`. That form
broke for titles containing `[`, `]`, `/`, or `|`. Storage now uses
the item's opaque ref (e.g. `[[BUG-586]]`, or `[[BUG-586|Custom]]`
when the visible text differs from the item's current title).
`wikiLinksToMarkdown` accepts three forms in preference order:
ref-only, ref-with-display-override, and legacy title lookup.
Titles can now contain any characters and links survive renames.
Escape-aware parsing
Both `markdownToWikiLinks` and `wikiLinksToMarkdown` now recognize
`\.` escape sequences inside their capture groups. tiptap-markdown
emits `\[`, `\]`, `\\` in link text when the text contains literal
brackets, so the prior regexes (`[^\]]+`) terminated prematurely and
missed valid links. Helper functions escape/unescape the markdown
link-text layer and the wiki-link body layer separately so `]`, `|`,
and `\` can appear in display-override text.
Leave unresolved [[X]] untouched
The `[[…]]` regex is greedy and can match spans that were never
intended as wiki-links — notably `[[` sequences inside another
markdown link's text. On miss, the function now returns the original
match verbatim instead of emitting `[…](broken)`, which previously
hijacked surrounding content and accumulated corruption on each
save cycle. Broken items heal themselves on the next auto-save.
Picker: show ref + align URL with the route
The `[[` picker now lists the ref badge next to the title and keys
`{#each}` by `doc.id` so duplicate titles don't collide. `execLink`
now reads `page.params.username`/`page.params.workspace` from the
live route (previously `workspaceStore.current`, which could be
empty), so the inserted `href` matches the URL shape that the
round-trip expects.
Clickable link popover
The popover's URL label is now a real `<a href="…">`. Plain click →
`goto()` for internal paths, full navigation for external. Ctrl /
Cmd / middle-click pass through to the browser so "new tab" and
"copy link" work naturally. `onmousedown.stopPropagation` keeps the
outer popover's focus-trap from swallowing the click.
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