Block renderer + Jinja2 sunset #8

Closed
opened 2026-03-14 05:50:36 +00:00 by forgejo_admin · 0 comments

Lineage

plan-pal-e-docs → Phase 4 (Block Renderer + Jinja2 Sunset)

Repo

forgejo_admin/pal-e-app (primary), forgejo_admin/pal-e-docs (Jinja2 removal — separate PR)

User Story

As a platform user
I want to browse all notes, projects, tags, and repos through the SvelteKit frontend
So that the Jinja2 frontend can be removed and all rendering uses the structured block system

Context

pal-e-docs has two content representations:

  1. html_content — monolithic HTML blob on the notes table
  2. blocks table — 5,197 typed JSON fragments (heading, paragraph, table, list, code, mermaid)

Blocks are already the source of truth — both write paths (update_note and update_block) converge through recompile() which keeps html_content as a cache. But the Jinja2 frontend ignores blocks and reads html_content, running a request-time pipeline (sanitize_html → autolink_slugs → wrap_tables).

The Jinja2 frontend is ~320 lines of Python routing + ~460 lines of HTML/CSS templates. The block API already exists. SvelteKit already has layout, dark theme, nav, API client, and a working board kanban as proof of the pattern.

No reason to maintain two frontends in parallel. Build the block renderer and remove Jinja2 in one pass.

File Targets

Files to create in pal-e-app:

  • src/lib/components/blocks/HeadingBlock.svelte — renders heading JSON
  • src/lib/components/blocks/ParagraphBlock.svelte — renders paragraph HTML with autolinked slugs
  • src/lib/components/blocks/TableBlock.svelte — renders structured table with scroll wrapper
  • src/lib/components/blocks/ListBlock.svelte — renders nested list items
  • src/lib/components/blocks/CodeBlock.svelte — renders code with optional syntax highlighting
  • src/lib/components/blocks/MermaidBlock.svelte — renders mermaid diagrams
  • src/lib/components/blocks/BlockRenderer.svelte — dispatches block_type to component
  • src/lib/components/NoteLayout.svelte — metadata (breadcrumb, tags, project, updated date, child notes, linked notes)
  • src/routes/notes/[slug]/+page.server.ts — fetches note + blocks from API
  • src/routes/notes/[slug]/+page.svelte — renders blocks via BlockRenderer
  • src/routes/projects/[slug]/+page.server.ts + +page.svelte — project note list
  • src/routes/tags/+page.server.ts + +page.svelte — tag list
  • src/routes/tags/[name]/+page.server.ts + +page.svelte — notes by tag
  • src/routes/repos/+page.server.ts + +page.svelte — repo list
  • src/lib/api.ts — add getNote(), getNoteBlocks(), listProjects(), listTags(), listRepos(), listNotes() etc.

Files to update:

  • src/routes/+page.svelte — replace stub landing with project/tag overview
  • src/routes/+layout.svelte — add nav links (Projects, Tags, Repos)

Files the agent should NOT touch:

  • src/routes/boards/** — existing kanban, already working
  • src/routes/api/** — existing board proxy, already working

Acceptance Criteria

  • /notes/{slug} renders any note from blocks (all 6 block types)
  • Heading blocks have anchor links (matching existing anchor_id)
  • Paragraph/list blocks autolink <code>slug-ref</code> patterns to /notes/{slug}
  • Table blocks render with horizontal scroll on mobile
  • Code blocks render in <pre><code> with language class
  • Mermaid blocks render diagrams (client-side mermaid.js)
  • Child notes render inline below parent content (composition rendering)
  • Linked notes (outgoing/incoming) shown at bottom
  • Breadcrumb shows parent note link when viewing a child
  • /projects/{slug} lists notes in that project
  • /tags lists all tags, /tags/{name} lists notes with that tag
  • /repos lists all repos
  • Landing page shows project cards + recent notes
  • Dark theme consistent with existing board UI
  • Mobile responsive (matches existing board layout patterns)

Test Expectations

  • Block renderer handles all 6 block types without errors
  • Block renderer gracefully handles empty/null content
  • Note page loads for notes with 0 blocks (empty content)
  • Navigation between notes via autolinked slugs works
  • Board links in nav still work (no regression)
  • Run command: npm run check && npm run build

Constraints

  • Render from blocks API (GET /notes/{slug}/blocks), NOT from html_content
  • Follow existing patterns in src/lib/api.ts (server-side only, apiFetch helper)
  • Follow existing SvelteKit 5 patterns (runes: $state, $derived, $props)
  • Dark theme colors must match existing board UI (#0a0a14 bg, #0e0e18 nav, #e94560 accent)
  • Autolink: find <code> elements inside paragraph/list HTML whose text matches a known note slug, wrap in <a href="/notes/{slug}">
  • For autolink, add a GET /slugs (or similar) lightweight endpoint to the pal-e-docs API that returns all known slugs, OR accept a list in the notes response

Checklist

  • PR opened
  • Tests pass (npm run check && npm run build)
  • No unrelated changes
  • Jinja2 removal tracked as separate pal-e-docs PR
  • pal-e-docs — project
  • phase-pal-e-docs-note-renderer — phase note
  • phase-pal-e-docs-jinja-sunset — absorbed phase
### Lineage `plan-pal-e-docs` → Phase 4 (Block Renderer + Jinja2 Sunset) ### Repo `forgejo_admin/pal-e-app` (primary), `forgejo_admin/pal-e-docs` (Jinja2 removal — separate PR) ### User Story As a platform user I want to browse all notes, projects, tags, and repos through the SvelteKit frontend So that the Jinja2 frontend can be removed and all rendering uses the structured block system ### Context pal-e-docs has two content representations: 1. `html_content` — monolithic HTML blob on the `notes` table 2. `blocks` table — 5,197 typed JSON fragments (heading, paragraph, table, list, code, mermaid) Blocks are already the source of truth — both write paths (`update_note` and `update_block`) converge through `recompile()` which keeps `html_content` as a cache. But the Jinja2 frontend ignores blocks and reads `html_content`, running a request-time pipeline (`sanitize_html → autolink_slugs → wrap_tables`). The Jinja2 frontend is ~320 lines of Python routing + ~460 lines of HTML/CSS templates. The block API already exists. SvelteKit already has layout, dark theme, nav, API client, and a working board kanban as proof of the pattern. No reason to maintain two frontends in parallel. Build the block renderer and remove Jinja2 in one pass. ### File Targets Files to create in pal-e-app: - `src/lib/components/blocks/HeadingBlock.svelte` — renders heading JSON - `src/lib/components/blocks/ParagraphBlock.svelte` — renders paragraph HTML with autolinked slugs - `src/lib/components/blocks/TableBlock.svelte` — renders structured table with scroll wrapper - `src/lib/components/blocks/ListBlock.svelte` — renders nested list items - `src/lib/components/blocks/CodeBlock.svelte` — renders code with optional syntax highlighting - `src/lib/components/blocks/MermaidBlock.svelte` — renders mermaid diagrams - `src/lib/components/blocks/BlockRenderer.svelte` — dispatches block_type to component - `src/lib/components/NoteLayout.svelte` — metadata (breadcrumb, tags, project, updated date, child notes, linked notes) - `src/routes/notes/[slug]/+page.server.ts` — fetches note + blocks from API - `src/routes/notes/[slug]/+page.svelte` — renders blocks via BlockRenderer - `src/routes/projects/[slug]/+page.server.ts` + `+page.svelte` — project note list - `src/routes/tags/+page.server.ts` + `+page.svelte` — tag list - `src/routes/tags/[name]/+page.server.ts` + `+page.svelte` — notes by tag - `src/routes/repos/+page.server.ts` + `+page.svelte` — repo list - `src/lib/api.ts` — add `getNote()`, `getNoteBlocks()`, `listProjects()`, `listTags()`, `listRepos()`, `listNotes()` etc. Files to update: - `src/routes/+page.svelte` — replace stub landing with project/tag overview - `src/routes/+layout.svelte` — add nav links (Projects, Tags, Repos) Files the agent should NOT touch: - `src/routes/boards/**` — existing kanban, already working - `src/routes/api/**` — existing board proxy, already working ### Acceptance Criteria - [ ] `/notes/{slug}` renders any note from blocks (all 6 block types) - [ ] Heading blocks have anchor links (matching existing anchor_id) - [ ] Paragraph/list blocks autolink `<code>slug-ref</code>` patterns to `/notes/{slug}` - [ ] Table blocks render with horizontal scroll on mobile - [ ] Code blocks render in `<pre><code>` with language class - [ ] Mermaid blocks render diagrams (client-side mermaid.js) - [ ] Child notes render inline below parent content (composition rendering) - [ ] Linked notes (outgoing/incoming) shown at bottom - [ ] Breadcrumb shows parent note link when viewing a child - [ ] `/projects/{slug}` lists notes in that project - [ ] `/tags` lists all tags, `/tags/{name}` lists notes with that tag - [ ] `/repos` lists all repos - [ ] Landing page shows project cards + recent notes - [ ] Dark theme consistent with existing board UI - [ ] Mobile responsive (matches existing board layout patterns) ### Test Expectations - [ ] Block renderer handles all 6 block types without errors - [ ] Block renderer gracefully handles empty/null content - [ ] Note page loads for notes with 0 blocks (empty content) - [ ] Navigation between notes via autolinked slugs works - [ ] Board links in nav still work (no regression) - Run command: `npm run check && npm run build` ### Constraints - Render from blocks API (`GET /notes/{slug}/blocks`), NOT from `html_content` - Follow existing patterns in `src/lib/api.ts` (server-side only, `apiFetch` helper) - Follow existing SvelteKit 5 patterns (runes: `$state`, `$derived`, `$props`) - Dark theme colors must match existing board UI (`#0a0a14` bg, `#0e0e18` nav, `#e94560` accent) - Autolink: find `<code>` elements inside paragraph/list HTML whose text matches a known note slug, wrap in `<a href="/notes/{slug}">` - For autolink, add a `GET /slugs` (or similar) lightweight endpoint to the pal-e-docs API that returns all known slugs, OR accept a list in the notes response ### Checklist - [ ] PR opened - [ ] Tests pass (`npm run check && npm run build`) - [ ] No unrelated changes - [ ] Jinja2 removal tracked as separate pal-e-docs PR ### Related - `pal-e-docs` — project - `phase-pal-e-docs-note-renderer` — phase note - `phase-pal-e-docs-jinja-sunset` — absorbed phase
Sign in to join this conversation.
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#8
No description provided.