24 Commits
Author SHA1 Message Date
LeoVasanko 0ec9be330e Add the 'eyes' banner design; seed banners only on select sub pages
Banner designs can now ship arbitrary markup as banner.html (canvas +
style + script), taking precedence over banner.svg; the artwork is
inlined in a div[data-design] wrapper either way, which the editor's
live preview preserves (and never re-runs its scripts).

The bundled 'eyes' design (themes/eyes/banner.html + banner.css sizing
the stage) replaces the eyes canvas script that was embedded in the
notes-on-urls page's own banner — the page now just picks the design.
Seeds set banners only on select sub pages (the-long-read gradient,
canvas-nights stars): the front page no longer gets a banner image and
shows the theme's default design. Seed entries carry a banner_design
field.
2026-08-18 06:36:05 +00:00
LeoVasanko 1c0ef315ff Refine dateline format; fix stale page caching breaking theme hot swap
Dateline is now '1 Jan 2026', with ' – edited 3 Jan 2026' appended only
when the last edit came at least 24h after publishing.

The Last-Modified header added heuristic browser caching of pages (no
Cache-Control was sent), so the site editor's re-fetch after a theme
change served the cached page with the old stylesheet link. Pages now
send 'Cache-Control: no-cache' — always revalidate, still cheap via the
ETag.
2026-08-18 06:20:38 +00:00
LeoVasanko 87c0aac3c0 Add Server/Last-Modified headers and a {dates} dateline tag
An http middleware sets 'Server: pagerite' (dropping uvicorn's versioned
default) and content pages return Last-Modified from Node.modified. In
markdown, a {dates} line expands to the article's published/updated
dateline (updated shown only when it falls on a later day); the editor
preview resolves it for pages that exist, unsaved pages show it literal.
Demonstrated in the long-read seed page.
2026-08-18 06:15:45 +00:00
LeoVasanko e044ab86ee Unwrap seed markdown paragraphs to single lines
With markdown-it breaks:True, the 80ch hard wraps rendered as forced
<br>s: frozen wrapping at the source's line breaks, ragged unjustified
lines and stale manual hyphenation. One line per paragraph lets the
browser reflow, justify and hyphenate normally.
2026-08-18 06:04:39 +00:00
LeoVasanko 30947df16b Backend-served themes and selectable, inheritable banner designs
Themes move from Vite-built frontend assets to pagerite/themes/{name}/
folders holding theme.css and/or banner.css (+ banner.svg), served by the
backend at /_themes/{name}/... and re-read from disk per request (etag by
mtime), so on-disk edits show on the next page load even in prod and new
themes need no build or config. The theme and banner-design selectors
enumerate these folders via GET /_api/settings.

Banner designs: Node.banner_design picks a design per page (None inherits
from ancestors, then the front page, then the active theme's own design;
"" = none). The design's banner.css is linked in <head> (id
pagerite-banner, between theme and custom CSS) and its banner.svg inlined
into #page-banner first (marked svg[data-design]); the page's own
Node.banner HTML renders after it, so author code always wins. #page-banner
is now a stacking grid so artwork and author code overlay.

Dev/prod hot loading unified: the backend renders the theme/design links
in both modes; in dev pagerite.js only re-appends them (and the custom
CSS) after the Vite-injected base styles. Theme switches just swap the
link href. The pagerite:theme meta and Vite theme build entries are gone.
2026-08-18 05:46:02 +00:00
LeoVasanko c0817330e7 Add favicon upload to the site editor
Data.favicon names a blob in the content-addressed files store (no
migration: msgspec default). PUT/DELETE /_api/settings/favicon upload and
clear it; when set, every page links it as <link rel="icon">, otherwise
browsers fall back to the build's /favicon.ico. SiteEditor shows a preview
with upload/replace/remove and applies the change to the live page head.
2026-08-18 05:22:25 +00:00
LeoVasanko f9e314e5ea Enable markdown-it typographer and breaks; remove custom dash rule 2026-08-18 04:32:54 +00:00
LeoVasanko f125966bb7 Fix various inconsistencies of sidebar and link handling on categories with only one child. 2026-08-18 03:57:41 +00:00
LeoVasanko 32f30dbdaa Don't let whitespace be considered a custom page banner. 2026-08-18 03:14:04 +00:00
LeoVasanko 9fcf4ee8e0 Stricter slug path processing, only serve site on 404 of missing article paths, not any other path. 2026-08-17 22:02:48 +00:00
LeoVasanko ae19dc58b1 Preserve CSS ordering on hot theme changes. 2026-08-17 20:33:09 +00:00
LeoVasanko c0bb3b73c1 Add corporate and nitro themes, inline theme banners, code palette sets
- Two new themes (corporate light/dark, nitro racing) and a purple
  retune; theme banner SVGs moved to pagerite/themes/, inlined by the
  backend, recolored per scheme via CSS classes, with scroll parallax.
- pygments.css maps tokens onto --code-* variables; light and dark
  palette sets in the base stylesheet resolve via light-dark() from the
  theme's color-scheme; themes just pick a set or retint --code-bg.
- Sidebar omitted unless the section has at least two published items;
  fetch-navigation and the site editor handle it appearing/disappearing.
- Floated figures keep captions below at 30% of the text column; h1/h2
  clear floats so images never overflow into the next section.
- Links use --link (color-mix of text and accent), weight 500, no
  underlines; hover goes full accent.
2026-08-17 19:16:45 +00:00
LeoVasanko dcd1e5afc9 Prepare for forward-auth; edit buttons and functions conditional on server 401, login button if needed. 2026-08-17 03:58:59 +00:00
LeoVasanko 7db08ea821 Fix new-page flow, save/delete semantics, add Cormorant font
- New-page flow: slug placeholder shows the slug derived live from the
  title (placeholders keep browser-default styling; slug values no longer
  muted). Committing PUTs empty markdown, which now creates an empty page
  rendering with its title instead of 404, then hands over to the page
  editor (CodeMirror focuses on mount)
- Saving never deletes: REST PUT and WS save store empty content as an
  empty page; deletion is the page editor's explicit choice — saving
  trimmed-empty text issues a REST DELETE
- Fonts: add Cormorant (variable 300-700, normal+italic) to the serif
  picks, replacing single-weight Gloock; Playfair Display files kept on
  disk but not offered
2026-08-17 02:54:12 +00:00
LeoVasanko 4a84aceb4f Add selectable site theme, custom CSS, and new font set
- Data.theme/Data.custom_css site settings with /_api/settings support;
  theme stylesheet linked per page, custom CSS inline as #pagerite-user,
  swapped during fetch-navigation
- Site editor: theme selector, custom CSS CodeMirror field; in-place
  stylesheet swap (diff-based, preserves editor stylesheets); dev swaps
  Vite-injected style tags since no <link>s exist there
- Dev theme delivery via <meta name="pagerite:theme"> + dynamic import
  in pagerite.js instead of a hardcoded purple import
- Fix dead edit pens in prod: Vite app builds strip entry exports, so
  the dynamic-imported main.js had no openEditor/closeEditor; build with
  preserveEntrySignatures 'exports-only' and log editor load failures
  instead of swallowing them
- Editor slide-in is one-shot: cleared on animationend so stylesheet
  swaps cannot restart a finished animation
- Replace Fraunces/Literata with Source Sans 3/Serif 4, Inter and
  Montserrat variable fonts; font stacks as CSS variables
2026-08-16 23:39:11 +00:00
LeoVasanko 658dea77b9 Remove stale /_admin app and disable SPA fallback
- Remove the /_admin route, views.render_editor, and standalone mode from
  the Vue editor (main.js / PageEditor.vue)
- Remove /_admin dev proxy and preload exclusion
- Set vite appType to 'mpa' and delete frontend/index.html so unknown
  /_ paths return 404 instead of an empty Vue shell
- Update AGENTS.md and docs/design-principles.md
2026-08-16 20:20:19 +00:00
LeoVasanko 53d98f0583 Restructure internal URL prefixes from /_/... to /_...
- Move API routes from /_/api/ to /_api/
- Move uploaded files from /_/f/ to /_f/
- Move built assets from /_/assets/ to /_assets/
- Move admin shell from /_/admin to /_admin
- Update Vite proxy/build config, frontend fetches/WebSockets, devserver health URL, seed content, and docs
- Fix README database name to pagerite.kantadb
2026-08-16 20:04:16 +00:00
LeoVasanko 6de0307856 Split CSS into base and theme, link them separately
- Move shared structural styles to frontend/src/assets/pagerite.css
  with conservative variables, and purple theme overrides to
  frontend/src/assets/themes/purple/theme.css.
- Backend now links the base and theme stylesheets as separate files
  so they can be swapped or augmented.
- Add blocking="render" to stylesheet links to avoid FOUC.
- Drop redundant defer from module script tags.
- Update related docs and comments.
2026-08-16 19:51:17 +00:00
LeoVasanko a8cf5a6a82 Rework category labels, slug validation, and task-list checkboxes
- Remove the section-header  "add landing page" button; landing pages are
  now created via the page editor pen.
- Treat saving a page with empty (after stripping) Markdown as deleting it:
  childless nodes are removed, nodes with children become content-less labels.
- Restrict server-side slugs to [a-z0-9_-] with no leading underscore or dot;
  drop the reserved-filename blacklist.
- Render placeholder pages for content-less category labels and link them to
  their first published child in the navigation.
- Make task-list checkboxes live, non-disabled inputs: toggling updates the
  Markdown source, updates the open CodeMirror document when the page editor is
  open, and persists to the server when no editor is open. Errors revert the UI.
- Update docs and AGENTS.md conventions accordingly.
2026-08-16 19:04:55 +00:00
LeoVasanko e38063a522 Slug input filtering, title-derived slugs, reserved file names
Slug inputs in the site editor now filter as you type via slugify.js
(built on the transliteration npm package: unicode incl. asian scripts
folds to ASCII, spaces become hyphens, anything outside [a-z0-9-] is
dropped) instead of erroring on commit. A new page left with an empty
slug gets one derived from its title. Server-side, _check_reserved
additionally rejects reserved root file names (robots.txt, ads.txt,
sitemap.xml, openapi.json, favicon.ico, site.webmanifest) with a
human-readable reason, which the editor surfaces in its error line so
the row can be edited and committed again; those URLs are also never
looked up as content when serving.
2026-08-16 16:45:57 +00:00
LeoVasanko 37af433704 Reserve slugs beginning with _ or .
Enforced at three layers: the site editor validates slug inputs before
committing (rename and new-page rows), the API rejects such paths in
_check_reserved (page save/delete, structure moves, editor socket), and
the content catch-all 404s them without a tree lookup.
2026-08-16 16:25:26 +00:00
LeoVasanko 508795437f Mirror the URL space in the frontend build layout
Build with assetsDir: '_/assets' so hashed assets land under
frontend-build/_/assets/ and favicon.ico (from frontend/public) at the
build root, then serve the whole build directory at the site root again
(frontend.route(app, "/"), cached="/_/assets/"). The explicit
favicon route is dropped — the Frontend serves it as an ordinary
unhashed (no-cache) file. Manifest paths now carry the _/assets/
prefix, so views.py only prepends a slash.
2026-08-16 16:22:39 +00:00
LeoVasanko d5e40fba12 Serve built assets under /_/assets, admin at /_/admin
Reorganize the URL space so all machinery lives under /_/: the Vite
build (now with assetsDir: '', two ES-module entries and hashed shared
assets: style.css, pygments.css, banner.svg, fonts moved from
pagerite/static to frontend/src/assets) is served at /_/assets via
frontend.route(app, "/_/assets") with cached="/", and the admin
shell moves to /_/admin, leaving only "_" as a reserved top-level
slug. A /favicon.ico route serves the file Vite copies from
frontend/public. In dev, Vite proxies content pages and /_/admin to
the backend.

Editor changes: drop the noisy status line for a save-error indicator,
reconnect the WebSocket with exponential backoff, and re-establish the
connection from send() when it has dropped. The socket connects when
an editor is opened (they mount on pen click), not before.
2026-08-16 16:13:12 +00:00
LeoVasanko 36b250a15c Pagerite: single-user CMS/blog
FastAPI backend rendering HTML with html5tagger, content persisted in a
kanta database and rendered per request. Vue only for the editing tools
(page editor over a WebSocket, site/structure editor); public pages are
plain HTML with fetch navigation. No auth: single trusted author.
2026-08-16 05:49:38 +00:00