Implement comprehensive content localization, admin panels for editing each language, AI translation interface with automatic updates when base language version is changed.
- SEO tags for all language URLs
- Uses accept-language by default, ?lang=en overrides temporarily
- User edits patched on top of translations
- RTL language supportReviewed-on: #1
Add server-side visit analytics collection, a public-page ping endpoint,
and a full-screen AnalyticsView for admins.
Backend:
- Add pagerite/analytics.py: Analytics/Visit model, Store, and persistence
- Wire /_a ping endpoint and GET /_api/analytics into pagerite/app.py
Frontend:
- Add full-screen AnalyticsView with visitor charts and transition map
- Add VisitorCharts and TransitionGraph subcomponents
- Add analytics JS helpers in frontend/src/analytics/
- Send navigation pings from frontend/src/pagerite.js
- Mount AnalyticsView from frontend/src/main.js
- Document the feature in docs/analytics.md and update AGENTS.md
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.
- 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.
- 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
- 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
- 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
- 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.
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.
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.
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.