- Node.language sets an article's primary language, inherited down the
hierarchy, configured per row in the structure tab; English is now a
regular language in the lang tab, still the root fallback
- Flags map a base tag to the language's home country (en → GB,
pt → PT); explicit variant tags resolve their own region
- Lang tab flag grid: geographic group rows, shading-only selection
- ConnNote.vue: a status strip for the WebSocket-backed panels (page and
banner editors, analytics view) — "connecting…" while the socket is
pending (the staggered slot included), "reconnecting in ~N s…" during
backoff, hidden once open. A pending/lost socket no longer reads as a
silently empty or stale panel.
- PageEditor/BannerEditor: CodeMirror stays non-editable until the
page/banner doc has been accepted — typing before it would be clobbered
by the accept. A mere disconnect keeps the editor live: text stashes
and pending saves flush on reconnect.
- LangSelect.vue: one language selector for the page and structure tabs
(small flag, clean dropdown), v-modeled on the shell-wide editorLang —
switching in either panel switches both AND the page preview. While the
panel is open the selection overrides the normal language preferences
(swapdoc.setLangOverride: loadPlain and pagerite.js fetches/prefetches
pin ?lang=, the primary language by its own code); closing restores.
- reconnect.js: every socket (page/banner editors, analytics view, the
activity channel) now connects through a staggered slot — simultaneous
attempts at page load (Vite's HMR socket plus ours, repeated on every
refresh) trip the browser's WebSocket throttling, leaving all sockets
to the host "pending" for minutes, which was the recurring empty
editor. A watchdog closes sockets stuck CONNECTING so they reschedule
through the policy (jittered exponential backoff, reset only by a
healthy connection) instead of hanging forever; a reconnected editor
re-opens its document when the previous open died with its socket.
uploadImage and insertTable no longer inject at the cursor: on a
non-empty line (e.g. inside an existing image tag) the block goes on a
fresh blank-separated line after it, never into it.
Cursor-driven editor→page scroll sync pinned the cursor's page position
at a fixed window height, so every cursor move dragged the page along.
Now the page scrolls only when the cursor's mapped position crosses a
viewport edge margin, and just enough to bring it back inside.
- Image insert always adds an empty "" caption with the cursor inside.
- Fenced blocks (``` code, ::: aside) share one toggle: clicked inside
one it is removed and the content selected; otherwise the selection
(expanded to whole lines) is wrapped, cursor left on the opener line.
- Code button: inline wrap toggles (selection preserved, backtick runs),
line-spanning selections make fenced blocks.
- Link button toggles: clicked inside [label](url) it unwraps.
- Block classes via two pickers (placement, AA size) with current-class
indication and a "normal" reset; placement replaces ::: container
names, fences get their own attribute line.
- New .small/.large/.huge text-size classes (0.7/1.5/3em); base body is
exactly 1rem so the scale is uniform.
- .left/.right floats generalized from figures to any block.
- Toolbar polish: non-emoji glyphs, scaled-up symbols, borderless
hover/active states, reordered (B/i and size last).
- Editor panel no longer closes on Escape.
- CodeMirror editors capture Tab/Shift-Tab for indent/dedent.
The cube view-transition block moves out of pagerite.css into transition
designs (pagerite/themes/{name}/transition.css), handled like banner
designs: served from disk at /_themes/..., injected by the backend as
#pagerite-transition after the banner sheet, and picked site-wide in the
site settings (Data.transition, default cube; GET/PUT /_api/settings
carry transition + the designs found on disk). The site editor swaps the
sheet in place on change; the dev-mode order fixup knows the new id.
Designs: cube (unchanged), crossfade (all navigations), slide (sideways,
both pages moving together) and reveal (clip-path wipe over the
stationary old page) — the latter two mirrored on history-back and
crossfading within a section like cube.
Also compress the site settings form into a two-column grid: site name +
favicon on one row, theme + transition on the next.
Anchored h1/h2s carry data-line (markdown source line, top-level
headings only) and h2s get dimmed section pens that open the page
editor at that section. Editor scroll sync is now piecewise-linear
keyed on those anchors: the page follows the cursor (fractional,
wrap-aware, fixed window anchor; editor scroll no longer drives it),
the editor follows page scroll with a progress-based viewport anchor,
so document ends line up exactly in both directions. The editor always
follows the URL — fetch-navigation retargets it — with unsaved text
stashed per path for the session and restored on return. Banner pen
removed (the tab stays in the shell); top-right order is now
analytics, site settings, login/logout.