jevcrates.git / jev-ui / README.md
README.mdpreviewREADME.mdsource105 lines · 6.0 KB · raw

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

FromWhat
assetThe files a page loads, embedded: ui.css, ui.js (the copy buttons and the dither fields), Datastar's datastar.js, 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.
shelldocument(head, body_attrs, body): the one head (title, preview tags, preloaded fonts, the shared sheet and script, Datastar) and the body's open and close. Assets::Linked for a site whose policy forbids inline script, Assets::Inline for one that does not.
componentsnav, headline, window, 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).
previewPreview: 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.
wireA 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, bars is lmjtfy's probability rule with an optional decision tick, printed_json reads a panel back for a test.
flowspine: 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.
cardThe 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
}

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, all under the SIL Open Font License, see assets/). lmjtfy fetched them from Google Fonts; a Jev site makes no request to another site.

Try it

cargo test -p jev-ui
cargo build -p jev-ui --target wasm32-unknown-unknown

Moving lmjtfy onto it

lmjtfy (~/lmjtfy) still carries its own copy of all of this, which is temporary debt: apps/lmjtfy/src/page.css and page.js (the shared half of each is this crate's ui.css and ui.js), view.rs's icon, nav, footer, clone_line, head and preview, ds-bundle/ (this crate's datastar.js, byte for byte), the Google Fonts link, and packages/card's palette, dither and pixel text. To move it:

  1. Move third-party/jevcrates to a commit with jev-ui; depend on it by path.
  2. Delete the shared half of page.css and page.js; what remains (transcript, feed, rules diagram, code pages, toasts) is lmjtfy's Head.style and its own script. Its .bar-title, .win, .share and the rest already mean the same thing here.
  3. Replace view.rs's head and footer with shell::document and components::footer, with Assets::Inline, and its preview with preview::Preview (a ?q= card is Picture { query: Some("q=…&a=…") }).
  4. Serve jev_ui::asset::find as a fallback instead of /datastar.js, and drop the Google Fonts preconnect and link.
  5. Hold lmjtfy's page tests to the same checks, then delete ds-bundle/.

Outstanding

  • Move lmjtfy onto this crate (the steps above), then delete its copies.
  • packages/card draws lmjtfy's own card straight into a PNG with the same palette, dither and pixel text as card.rs; once lmjtfy depends on this crate, one of the two should draw from the other.
  • lmjtfy's tool-call panels and bars (view.rs: json, node, choice, jev_card) are the same markup as wire; lmjtfy's .rete diagram is Rete-specific and stays its own, but its CSS box language is what flow borrows.
  • 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

PathWhat
src/The code: Chapter 22½.
assets/The stylesheet, the script, Datastar and the fonts: Chapter 22¾.
Cargo.tomlDependencies: maud and font8x8 only.
CLAUDE.mdInvariants for agents.

← Previous: Chapter 21½: inside jev-mock/src · Up: jevcrates · Next: Chapter 22½: inside jev-ui/src →