feat: port notes list page from playground design #77
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/pal-e-docs-app!77
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "70-port-notes-list"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Changes
src/routes/notes/+page.svelte: Complete rewrite to match playgroundnotes.htmllayout. Flat.note-listof.note-cardelements using.note-card-row(badge + title + meta-time). Dynamic filter pills from API response, search input, smart routing (boards to/boards/, project-pages to/projects/).src/app.css: Add 7 missingbadge--*classes (reference, journal, template, agent, skill, post, incident) and 7 matchingdata-typeborder-left-color rules for note cards.Test Plan
npm run buildpassessvelte-checkreports 0 errors/notes-- flat list with type badges, titles, relative timestamps?note_type=X/boards/{slug}, project-page notes link to/projects/{slug}Review Checklist
Related Notes
pal-e-app-- the project this work belongs toQA Review -- PR #77
Scope Verification
src/routes/notes/+page.svelte,src/app.css) -- matches scopeCode Quality
Positive:
py-4,mb-6,flex,text-2xl, etc.) -- correct per no-Tailwind convention.home-title,.home-subtitle,.filter-bar,.filter-pill,.note-list,.note-card,.note-card-row,.badge,.meta-time-- all defined in app.css$state,$derived.by()for compound filteringnoteHref()smart routing sends board notes to/boards/and project-page notes to/projects/badgeClass()falls back to inlinetypeColor()for unknown note types -- defensivegoto()withreplaceState-- correct SvelteKit patternVerified no regression:
/notes?tags=or/notes?project=, so removing those server-side filter params is safeNits (non-blocking)
relativeTime()duplication -- identical function exists insrc/routes/+page.svelte(home page) and now insrc/routes/notes/+page.svelte. Could be extracted to$lib/time.tsin a follow-up issue.Build Verification
npm run build-- passessvelte-check-- 0 errors, 1 pre-existing warning (unrelated autofocus in search page)VERDICT: APPROVE
One nit (relativeTime duplication) tracked as discovered scope for a follow-up issue.
PR #77 Review
DOMAIN REVIEW
Tech stack: SvelteKit 5 (runes mode), pure CSS design tokens, TypeScript, client-side SPA.
Architecture assessment: This is a complete rewrite of the notes list page from a grouped-by-type layout to a flat list with filter pills, client-side search, and URL-synced type filtering. Two files changed:
src/routes/notes/+page.svelte(component rewrite) andsrc/app.css(7 new badge + 7 new border-left-color rules).What works well:
<button>elements (correct for accessibility, good keyboard behavior)goto()withreplaceState: true, noScroll: trueis the correct SvelteKit patternBADGE_CLASS_MAPwithtypeColor()fallback is a solid pattern -- known types get CSS classes, unknown types degrade gracefully to runtime-resolved inline styles$derived.by()for combined type + search filtering is clean reactive compositionnoteHref()routing function correctly maps board/project-page types to their dedicated routes--type-reference,--type-journal, etc.) are confirmed defined in:root.filter-bar,.filter-pill,.note-card,.note-card-row,.meta-time,.home-title,.home-subtitle) are defined inapp.cssdata-typeon untyped notes degrades correctly to default border colorBLOCKERS
None. This is a UI port from an approved playground design. No new auth paths, no user input sent to a backend, no secrets, and no security-sensitive logic introduced. The project has Playwright E2E infrastructure but zero test files -- that is a pre-existing condition, not introduced by this PR. A visual rewrite of a list page with client-side filtering does not meet the "new functionality with zero test coverage" blocker threshold.
NITS
1. DRY:
relativeTimeduplicated across two pagesrelativeTime()is defined in bothsrc/routes/+page.svelte(landing page, lines 59-73) and this PR'ssrc/routes/notes/+page.svelte. The implementations differ slightly -- the landing page version jumps from "N days ago" totoLocaleDateString()at 30 days, while this PR's version adds week granularity ("1 week ago", "N weeks ago") before falling back at 5 weeks. This should be extracted to a shared utility (e.g.,$lib/format.ts) with the richer week-aware logic as the canonical version.2. Private note indicator removed
The old code rendered a lock SVG icon with
aria-label="Private note"for notes whereis_public === false. The new code drops this entirely. Private notes are no longer visually distinguished in the list. If this is intentional (the playground design omits it), document that decision. If not, it should be restored -- even a small lock icon or badge modifier would preserve the information.3. Search input lacks accessible label
The
<input class="notes-search-input" placeholder="Filter notes...">has no associated<label>oraria-label. Screen readers will only announce the placeholder, which disappears on focus. Addingaria-label="Filter notes by title, slug, or project"would be a low-effort accessibility improvement. (Consistent with the rest of the app -- the dashboard also lacks labels, but no reason to perpetuate the gap.)4. Magic number
limit: 200listNotes({ limit: 200 }, opts)uses a hardcoded limit. If note count exceeds 200, notes will silently be missing from the list with no user indication. Consider either: (a) extracting to a named constant, or (b) adding a "showing N of M" indicator when the API returns exactly 200 results (suggesting truncation).5.
BADGE_CLASS_MAPcould derive from CSS conventionThe map manually duplicates what is already a naming convention (
badge--{type}). A function like(type) => document.querySelector(\.badge--${type}`) ? `badge--${type}` : ''would be fragile, but simply usingbadge--${noteType}directly with thetypeColor` fallback for unknown types would eliminate the map entirely. Minor -- the explicit map is safer and more readable.SOP COMPLIANCE
70-port-notes-listnamed after issue #70PROCESS OBSERVATIONS
limit: 200is the only runtime behavior change worth monitoring post-deploy.relativeTimeduplication should be addressed before more pages copy it. A$lib/format.tsutility would be the right home. Consider filing a cleanup ticket.VERDICT: APPROVED
The PR is a clean port of the playground design to SvelteKit. No blockers. The nits (especially the
relativeTimeDRY violation and private note indicator removal) should be tracked as follow-up work.69d9008d4a0a9c8c25b7