Parent
#114 — v0.41.0-alpha.5: SPA Mode + Deno Desktop Proof
What to build
Implement all 5 route components in app/routes.ts. All routes return DOM Node/DocumentFragment (no Preact/React). Wire into reader.ts via defineApp({ mode: 'spa', routes }).
Routes
| Route |
Component |
Loader |
Action |
Notes |
/ |
Bookshelf |
Load books from books.json |
— |
Show covers/titles/progress. Continue reading affordance. Empty state. |
/books/:id |
Reading surface |
Load book + progress |
Create note |
<embed> the PDF. Show book title, page nav, note form. Missing id → error state. |
/notes |
Note list |
Load notes from storage |
— |
Group by book. Link back to /books/:id. Empty state. |
/search?q= |
Search results |
Search books/notes by q param |
— |
Highlight matches. Empty state for no results. + decoding tested. |
/settings |
Settings panel |
Load settings from storage |
Save settings |
Theme (light/dark/sepia), font size, line height, measure. Live preview. |
Component pattern (DOM-returning)
// routes.ts
export function bookshelfRoute(): DocumentFragment {
const frag = document.createDocumentFragment();
// ... build DOM elements with dom.ts helpers
return frag;
}
Data flow (SPA loader/action contract from #117/#118)
defineApp({
mode: 'spa',
routes: [
{
path: '/books/:id',
component: readingRoute,
loader: async ({ params }) => {
const book = books.find(b => b.id === params.id);
const progress = loadProgress(params.id);
return { book, progress };
},
action: async ({ params }) => {
// handle note creation form submit
}
}
]
})
Integration with other slices
- S4 (storage): routes call
storage.loadProgress(), storage.loadNotes(), storage.saveNote(), storage.loadSettings(), storage.saveSettings()
- S2 (fixtures):
/ reads fixtures/books.json
- S5 (UX): keyboard shortcuts and theme controls in separate slice
Acceptance criteria
Blocked by
Parent
#114 — v0.41.0-alpha.5: SPA Mode + Deno Desktop Proof
What to build
Implement all 5 route components in
app/routes.ts. All routes return DOMNode/DocumentFragment(no Preact/React). Wire intoreader.tsviadefineApp({ mode: 'spa', routes }).Routes
/books.json/books/:id<embed>the PDF. Show book title, page nav, note form. Missing id → error state./notes/books/:id. Empty state./search?q=qparam+decoding tested./settingsComponent pattern (DOM-returning)
Data flow (SPA loader/action contract from #117/#118)
Integration with other slices
storage.loadProgress(),storage.loadNotes(),storage.saveNote(),storage.loadSettings(),storage.saveSettings()/readsfixtures/books.jsonAcceptance criteria
/renders bookshelf with book titles and cover placeholders/books/:idrenders<embed>PDF + book metadata/books/:idshows error state for missing book/notesshows notes grouped by book (empty state when no notes)/search?q=testshows search results (empty state for no results)/search?q=hello+worldcorrectly decodes to "hello world"/settingsshows theme/font/line-height controlsDocumentFragmentBlocked by