1# Chapter 22: jev-ui — what the Jev sites' pages share 2 3lmjtfy.fun and whiskers.lmjtfy.fun look alike on purpose: near-black on white, 4one pink band, ordered-dither dot fields and old operating system windows with 5a black title bar, after typesafe.ai. This crate is the one copy of that look, 6so the second site did not get a second copy of it. 7 8It is the opposite of its neighbours in one way: nothing here talks to Jev. 9It is the page around whatever a site says. 10 11## What a site gets 12 13| From | What | 14| --- | --- | 15| `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. | 16| `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. | 17| `components` | `nav`, `headline`, `window` (and `window_with_id`), `sheet`, `band`, `copy_line`, `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). | 18| `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. | 19| `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. | 20| `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. | 21| `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. | 22 23A page, in whiskers' shape: 24 25```rust 26use jev_ui::components::{Link, Nav, band, nav, sheet, window}; 27use jev_ui::shell::{Assets, Attr, Head, document}; 28 29let head = Head { title: "Whiskers", meta: preview_tags, style: SITE_CSS, assets: Assets::Linked, 30 datastar: true, icon: Some("/favicon.svg"), extra: maud::html! {} }; 31let page = document(&head, &[Attr::new("data-signals", "{}")], body); 32``` 33 34and in the Worker, every asset the crate owns in one route: 35 36```rust 37// as the router's fallback; `path` and `query` are the request's 38if let Some(asset) = jev_ui::asset::find(path) { 39 // content-type: asset.content_type, cache-control: asset.cache_control(query), body: asset.body 40} 41``` 42 43and the script Datastar needs, from the Aldebaran crate that owns it: 44 45```rust 46// a route for `jev_ui::shell::DATASTAR_PATH` 47// content-type: text/javascript; charset=utf-8, body: aldebaran_datastar::SCRIPT 48``` 49 50## What is a parameter and what is not 51 52Everything a site differs in is a field: the title, the tags, the site's own 53stylesheet (it comes after the shared one), the nav's links, what sits between 54the name and the links, the footer's words, a picture's query. The look is not 55a parameter: there is one palette, light only, as typesafe.ai's is. A site 56that wants another look is not a Jev site. 57 58Fonts are served by the site itself, from this crate (Inter Tight, JetBrains 59Mono and VT323, see [assets/](assets/)). A Jev site makes no request to another 60site for them. 61 62## Try it 63 64``` 65cargo test -p jev-ui 66cargo build -p jev-ui --target wasm32-unknown-unknown 67``` 68 69## lmjtfy on it 70 71lmjtfy (`~/lmjtfy`) wears this crate: its head and body come from `shell::document` 72with `Assets::Inline` (its pages set no content security policy), its nav, headline, 73windows, sheet, band, footer and copy line from `components`, its icons from 74`components::icons`, its JSON panels, a choice's rule and its Jev, LLM and tool call 75windows from `wire`, and its fonts from `/fonts/*`, one route per `asset::ALL` entry 76(`/{repo}/{*path}` would otherwise take them). `page.css` holds only lmjtfy's own 77rules, after the shared sheet, and `page.js` only its own behaviour. Datastar's script 78is `aldebaran_datastar::SCRIPT`, served by each site at `shell::DATASTAR_PATH`. 79 80## Outstanding 81 82- [ ] lmjtfy's own Open Graph tags (`view.rs`'s `preview` and `view/code.rs`'s) are still 83 its own: the home page's carries a canonical link and `noindex` that 84 `preview::Preview` has no field for, and they should move onto it. 85- [ ] A score's bars (a tag in the label) and the budget's (a figure of its own, not a 86 percentage) are still lmjtfy's; `wire::Bar` has neither a tag nor a figure. 87- [ ] `packages/card` draws lmjtfy's own card straight into a PNG with the 88 same palette, dither and pixel text as `card.rs`; now that lmjtfy depends on 89 this crate, one of the two should draw from the other. 90- [ ] lmjtfy's `.rete` diagram is Rete-specific and stays its own, but its CSS box language is what `flow` borrows. 91- [ ] Mermaid (lmjtfy's code pages) is still fetched from jsdelivr there; it is 92 not part of this crate. 93 94## For the people who maintain it 95 96### In this folder 97 98| Path | What | 99| --- | --- | 100| [src/](src/) | The code: Chapter 22½. | 101| [assets/](assets/) | The stylesheet, the script and the fonts: Chapter 22¾. | 102| [Cargo.toml](Cargo.toml) | Dependencies: `maud` and `font8x8` only. | 103| [CLAUDE.md](CLAUDE.md) | Invariants for agents. | 104 105← Previous: [Chapter 21½: inside jev-mock/src](../jev-mock/src/) · Up: [jevcrates](../) · Next: [Chapter 22½: inside jev-ui/src](src/) →