Chapter 22: jev-ui — what the Jev sites' pages share
lmjtfy.fun and whiskers.lmjtfy.fun look alike on purpose: near-black on white, one pink band, ordered-dither dot fields and old operating system windows with a black title bar, after typesafe.ai. This crate is the one copy of that look, so the second site did not get a second copy of it.
It is the opposite of its neighbours in one way: nothing here talks to Jev. It is the page around whatever a site says.
What a site gets
| From | What |
|---|---|
asset | The files a page loads, embedded: ui.css, ui.js (the copy buttons and the dither fields), the three fonts and a fourth, a small pixel-emoji font. asset::find(path) for a fallback route, Asset::href() for a link named by the hash of its bytes. |
shell | document(head, body_attrs, body): the one head (title, preview tags, preloaded fonts, the shared sheet and script, and a <script> for Datastar when asked) and the body's open and close. Assets::Linked for a site whose policy forbids inline script, Assets::Inline for one that does not. |
components | nav, headline, window (and window_with_id), sheet, band, copy_line, terminal (commands to copy, drawn as a terminal after typesafe.ai's: a black title bar with the copy button, a gutter of squares and a bold $ that are the stylesheet's and so are never copied), footer, skip_link, the 12 by 12 pixel_icon, and SerenityOS's pixel emoji: PixelEmoji (play, pause, the two hourglasses), pixel_emoji and an hourglass that turns over (still under reduced motion). |
preview | Preview: Open Graph and Twitter tags that cannot be built wrong (an origin that is not https, a video of odd size, a card too small to be shown large), for a still card or a looping video, and missing(html, kind) to check a rendered page. |
wire | A call to Jev as a window: json prints a body from the raw text (whitespace added, nothing else), exchange is the folding request-and-response window (exchange_with when the title bar is markup or the body starts with something of the site's), bars is lmjtfy's probability rule with an optional decision tick, printed_json reads a panel back for a test. |
flow | spine: a flow drawn as one SVG from rows of steps, each with the ways it can end. Built from the data it is given, so a site that builds the rows from the code that runs the flow cannot draw a step the code lacks. |
card | The preview card's look as SVG: Chrome (the dither, the pink band, the window with its title bar, in lmjtfy's measures), and pixel text. A site composes what goes inside the window. |
A page, in whiskers' shape:
use jev_ui::components::{Link, Nav, band, nav, sheet, window};
use jev_ui::shell::{Assets, Attr, Head, document};
let head = Head { title: "Whiskers", meta: preview_tags, style: SITE_CSS, assets: Assets::Linked,
datastar: true, icon: Some("/favicon.svg"), extra: maud::html! {} };
let page = document(&head, &[Attr::new("data-signals", "{}")], body);
and in the Worker, every asset the crate owns in one route:
// as the router's fallback; `path` and `query` are the request's
if let Some(asset) = jev_ui::asset::find(path) {
// content-type: asset.content_type, cache-control: asset.cache_control(query), body: asset.body
}
and the script Datastar needs, from the Aldebaran crate that owns it:
// a route for `jev_ui::shell::DATASTAR_PATH`
// content-type: text/javascript; charset=utf-8, body: aldebaran_datastar::SCRIPT
What is a parameter and what is not
Everything a site differs in is a field: the title, the tags, the site's own stylesheet (it comes after the shared one), the nav's links, what sits between the name and the links, the footer's words, a picture's query. The look is not a parameter: there is one palette, light only, as typesafe.ai's is. A site that wants another look is not a Jev site.
Fonts are served by the site itself, from this crate (Inter Tight, JetBrains Mono and VT323, see assets/). A Jev site makes no request to another site for them.
Try it
cargo test -p jev-ui
cargo build -p jev-ui --target wasm32-unknown-unknown
lmjtfy on it
lmjtfy (~/lmjtfy) wears this crate: its head and body come from shell::document
with Assets::Inline (its pages set no content security policy), its nav, headline,
windows, sheet, band, footer and copy line from components, its icons from
components::icons, its JSON panels, a choice's rule and its Jev, LLM and tool call
windows from wire, and its fonts from /fonts/*, one route per asset::ALL entry
(/{repo}/{*path} would otherwise take them). page.css holds only lmjtfy's own
rules, after the shared sheet, and page.js only its own behaviour. Datastar's script
is aldebaran_datastar::SCRIPT, served by each site at shell::DATASTAR_PATH.
Outstanding
-
lmjtfy's own Open Graph tags (
view.rs'spreviewandview/code.rs's) are still its own: the home page's carries a canonical link andnoindexthatpreview::Previewhas no field for, and they should move onto it. -
A score's bars (a tag in the label) and the budget's (a figure of its own, not a
percentage) are still lmjtfy's;
wire::Barhas neither a tag nor a figure. -
packages/carddraws lmjtfy's own card straight into a PNG with the same palette, dither and pixel text ascard.rs; now that lmjtfy depends on this crate, one of the two should draw from the other. -
lmjtfy's
.retediagram is Rete-specific and stays its own, but its CSS box language is whatflowborrows. - Mermaid (lmjtfy's code pages) is still fetched from jsdelivr there; it is not part of this crate.
For the people who maintain it
In this folder
| Path | What |
|---|---|
| src/ | The code: Chapter 22½. |
| assets/ | The stylesheet, the script and the fonts: Chapter 22¾. |
| Cargo.toml | Dependencies: maud and font8x8 only. |
| CLAUDE.md | Invariants for agents. |
← Previous: Chapter 21½: inside jev-mock/src · Up: jevcrates · Next: Chapter 22½: inside jev-ui/src →