- Banner-corner auth link is now a button opening paskia-js's profile() dialog (handles login too); auth re-probed when the dialog closes. - Editor/analytics components call /_api via apiFetch/apiJson: an expired session opens the login dialog and the request retries. - pagerite.js: task-checkbox toggle uses apiJson (explicit edit attempt, reverts on any failure incl. cancelled login); auth probes use fetchJson (never a dialog); page-cache/navigation stay on plain fetch. - Add the paskia npm dependency; document the convention.
6.1 KiB
Frontend runtime
The public page runtime lives in frontend/src/.
main.js
Vue editor app entry, mounts the tabbed EditorShell. See docs/editing.md for the editor UI.
pagerite.js
Public page entry; runs fetch-navigation (backed by an in-memory page cache: every visible internal link is fetched once at load and clicks are then served from JS with no fetch — the current page itself is not refetched, it enters the cache when navigated to — and the editors' loadPlain keeps the cache current via a pagerite:page-fetched event; articles are cache-control: no-cache on the wire). Editors can drop the entire cache with the pagerite:drop-page-cache event when site-wide or page changes (theme, headings, structure, banners, etc.) invalidate the cached HTML of other pages; main.js triggers a fresh pagerite:preload-pages pass when the editor panel closes so navigation is fast again. Navigation that starts while the editor is open bypasses the cache and fetches the target page on demand. Also runs scroll-reveal, a scroll-driven section hash (the location hash tracks the h1/h2 above the viewport middle via replaceState — removed above the first tagged heading and at the very top, never set on unscrollable pages), OverlayScrollbars on document.body (floating, auto-hiding scrollbars that never reserve layout space or shift the page when appearing; native scroll APIs like window.scrollTo keep working; themed via the --os-* variables in pagerite.css), brand shrink-to-fit (the themed size is the maximum; JS reduces the font-size so a long brand or narrow viewport still fits one line), nav condense-to-fit (the top nav stays on one row: link gaps shrink first, then the side padding, then the font size; flex-wrap: wrap remains the no-JS fallback), code copy buttons, click-to-enlarge on article figure images (a full-viewport lightbox with the caption, closed by click or Esc), and the auth check.
It first probes GET /auth/api/settings to detect whether Paskia SSO is available, then GET /_api/settings to learn the current session's admin status. The same reverse proxy that gates /_api returns 401 for anonymous users, 403 for users without the admin permission, and 200 for admins. When Paskia is detected, a login button (anonymous) or profile button (logged in) is shown in the banner corner; clicking it opens the paskia-js profile() dialog (an iframe overlay served by Paskia itself, which also runs the login flow), and auth is re-probed when the dialog closes. A pageshow handler also re-probes auth when history navigation restores a cached page. Admins also get the page/banner edit pens and a site-settings pen, plus a modulepreload warm-up of the editor bundle (the hashed asset is immutable, so it costs nothing). If no Paskia SSO is detected (dev/no proxy), editing is left open. Pages themselves render identically for everyone; the real gate is the auth proxy in front of all of /_api.
The editor/analytics components (everything except pagerite.js and main.js) make their /_api calls through paskia-js's apiFetch/apiJson instead of plain fetch: when a call gets a 401/403 carrying an auth.iframe hint (expired session), the login dialog opens in place and the request retries transparently after authentication. pagerite.js uses apiJson only for the task-checkbox toggle (ticking a box is an explicit edit attempt, so a login dialog is welcome there; any failure — including a cancelled login — reverts the checkbox) and fetchJson for its auth probes (plain fetch with JSON handling and errors on non-OK, never a dialog); page-cache and navigation fetches stay on plain fetch, so anonymous visitors never get a login popup uninvited.
Asset wiring differs by mode. In dev the backend links the Vite dev-server URLs (pagerite:editor-src/-css/pagerite:analytics-src meta tags, <link> stylesheets) and Vite injects the entry CSS from JS for hot reloads. In production there are no pagerite meta tags: all page assets are inlined into the document — stylesheets as <style> elements in <head> (fixed order: base, theme, banner design, page transition, entry sheets, custom CSS last), module scripts as inline <script>s at the end of the body (relative chunk imports are rewritten to absolute /_assets/ paths) — and the on-demand bundles' URLs ride in a <script type="application/json" id="pagerite-assets"> config. The editor bundle always stays external, imported on demand when a pen is opened. Every stylesheet element carries a stable id so fetch-navigation and the site editor can sync <head> positionally across swaps (the analytics sheet exists on /_a only and is added/removed as you navigate). The analytics entry is inlined into the /_a page itself; pagerite.js re-creates that script element after fetch-navigating there (inline scripts don't execute on a DOM swap) and calls the module's exposed unmount before swapping away.
assets/
Shared styles and data files built by Vite and served hashed under /_assets/: pagerite.css (base layout + conservative variables), pygments.css, and fonts/ (self-hosted Source Sans 3/Source Serif 4/Fraunces/Literata/Cormorant/Playfair Display/Inter/Montserrat/Fira Code/Cause/Exo 2/New Rocker variable woff2).
The ::view-transition* rules live in the page-transition designs (pagerite/themes/{cube,crossfade}/transition.css), not in the base stylesheet. Themes, banner designs and transitions are NOT built — they live in pagerite/themes/{name}/ and are served by the backend. See docs/themes-and-assets.md for details.
Vite builds ES-module .js outputs; in dev the backend links them as <script type="module"> (module scripts defer by default), in production it inlines them at the end of the body.
Data directory
All site data lives under <hostname>/ in the cwd — content.kantadb,
analytics.json and files/ — where <hostname> is the CLI's first
positional argument (default localhost, passed to the app as JSON in
PAGERITE_CONFIG, see pagerite/config.py;
PAGERITE_DB/PAGERITE_ANALYTICS/PAGERITE_FILES override individual
paths). gitignored. Do not delete it without asking.