cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

main
012 / docs / contributing / site.md
site.md 12.7K rendered
1---2title: "The docs site"3sidebar_position: 94---56# The docs site78`website/` builds these docs into a static site with9[Docusaurus](https://docusaurus.io). It reads `docs/` where it is, so a10page is written once and reads the same on GitHub and on the site. It is11the only part of the repository that needs Node: `make build`,12`make check` and the Go toolchain never touch it.1314```sh15make site # install from website/package-lock.json, build into website/build16make site-serve # a dev server on http://localhost:3000 that reloads as docs change17```1819Both need Node 20.11 or later and npm. `npm ci` installs exactly what20the lockfile pins, with install scripts off (no dependency needs one).21To look at the built site as a static host serves it, run22`npm run serve` in `website/` after `make site`. `SITE_URL` sets the23address canonical links and the sitemap use (`SITE_URL=https://... make24site`), [012.dev.site](#where-it-lives) unless set; the site sits at the25root of its host.2627## Where it lives2829The site is published at [012.dev.site](https://012.dev.site/), which30also serves the install scripts and the latest release's archives. It31is a Cloudflare Worker with static assets and no code of its own,32configured in `website/wrangler.jsonc`: the worker `012-site` serves33`website/build`, `012.dev.site` is its custom domain (Cloudflare keeps34the DNS record and the certificate), an address that names a page's35directory without its trailing slash redirects to it, and an address36with no file gets the site's 404 page. `website/static/_headers` gives37the files whose extension names no type, `install.ps1` and38`SHA256SUMS`, a text one. To publish a new build:3940```sh41make site-publish VERSION=v1.2.342```4344`make site-publish` is `make site-release`, which is `make site` with45the release added ([Publishing](releasing.md#publishing)), followed by46`wrangler deploy` in `website/`, the version `website/package.json` pins.47It needs Node 22 or later, which wrangler does, and wrangler logged in48to the Cloudflare account that holds the `dev.site` zone49(`npx wrangler login` in `website/`). Every deploy replaces the whole50site, so a deploy of a plain `make site` build would take the install51script and the archives off it. A file may be at most 25 MiB, which the52release archives stay well under.5354`f58b.n.zip`, on the owner's nzip server, keeps links to the site55there working: each page's address serves a page that sends the browser56on to the same page here, and its `install.sh` and `install.ps1` run57this site's.5859## The build is a docs check6061`make site` fails on a link to a page that doesn't exist, an anchor no62heading makes, a missing image, two pages at one address or a63[diagram](#diagrams) Mermaid can't parse. It checks64the same links `scripts/doccheck` does, as the site resolves them, so a65page that passes `make lint` but breaks on the site shows up here.6667## Old addresses keep working6869A page's address is its path under `docs/`, so moving or deleting a70page would break links to it from elsewhere. A page that moves or goes71leaves a redirect in `website/redirects.json`, from its old address to72the page its reader wants now:7374```json75{"from": "/docs/terminal/nushell/", "to": "/docs/nushell/notebooks/"}76```7778`@docusaurus/plugin-client-redirects` writes a page at each old address79that sends the browser on, since a static host can't redirect by80itself, and the build fails on a redirect to a page that doesn't exist.81`scripts/doccheck` (in `make lint`) fails when a page the site has82published is gone without a redirect: it reads git's history back to83the site's first commit for every page there has been.8485## How the docs become pages8687- Pages are Markdown as GitHub reads it (`markdown.format: 'detect'`):88 `.md` files are CommonMark, so `<`, `{` and HTML comments are text and89 markup rather than MDX. A page that needs components would be `.mdx`.90- Each folder's `README.md` is its category's page (`/docs/sheets/`),91 and each section (top-level folder) has a sidebar of its own92 (`website/sidebars.ts`), generated from its folder: `_category_.json`93 for folders, `title` and `sidebar_position` for pages94 ([Docs](testing.md#docs) has the rules the tree follows).95- Images in `docs/media/` are bundled from the pages that show them;96 an image marked `#gh-dark-mode-only` or `#gh-light-mode-only` shows in97 that color mode only ([Pictures of 012](#pictures-of-012)).98- Prism has no nushell grammar, so `nu` code blocks use a small one in99 `website/src/prism/nushell.ts`, loaded by the swizzled100 `website/src/theme/prism-include-languages.ts`.101- A relative link that leaves `docs/` (the roadmap, `CLAUDE.md`)102 becomes a link to the file on GitHub103 (`website/src/remark/repo-links.ts`).104- The generated pages, [Functions](../reference/functions.md) and105 [Configuration](../reference/config.md), are pages like any other.106- `mermaid` code blocks are drawn as diagrams107 (`@docusaurus/theme-mermaid`), as GitHub draws them; see108 [Diagrams](#diagrams).109- Search is local: `@easyops-cn/docusaurus-search-local` builds an index110 at build time, and nothing is sent to a service.111112## The look113114The landing page (`website/src/pages/index.tsx`) is drawn as a 012115screen: a control panel with the mode indicator, the recording in an116overlay frame, the features as cells of a sheet (the one under the117pointer shows its entry in the control panel), and a status line. The118navbar lists the docs' sections by folder, each opening its section's119sidebar, so the sidebar lists that section's pages rather than the120sections again (`website/docusaurus.config.ts`); the control panel's menu bar121lists the same sections, so on the landing page the navbar leaves them122to it. The123colors in `website/src/css/custom.css` are the reference palettes of the124golden screens, given the roles the app gives them: cyan where you are,125bright black header bands, blue links and selection. Code, headings and126chrome are JetBrains Mono, bundled with the site, the font of every127[picture of 012](#font-and-colors); body text is the system's own sans.128129## Diagrams130131Diagrams are Mermaid, in a `mermaid` code block, never ASCII art: the132same source is drawn on the site and on GitHub. A code block of text133stays for text a reader types or a shell prints; 012's own screen is a134picture ([Pictures of 012](#pictures-of-012)).135136- Draw one where a flow, a state machine or a sequence would otherwise137 take paragraphs: a flowchart for data moving through the code, a state138 diagram for modes, a sequence diagram for two programs talking. Not139 for its own sake: a list or a table that reads well stays one.140- A short sentence before it says what it shows, and the prose around141 it keeps the facts the diagram can't (why, limits, names to search142 for) without walking through it again.143- Labels are the words the docs use: the key, the command's title, the144 function or type name; menu paths in them are checked as in prose.145- Colors and fonts come from the site: `website/src/theme/Mermaid`146 (Docusaurus's component, swizzled) draws with Mermaid's `base` theme147 and variables read from the palette in `custom.css` for the color148 mode shown, so diagrams don't set their own styles.149- `make site` fails on a diagram Mermaid can't parse, which the site150 would draw as an error: `website/scripts/check-mermaid.mjs` (`npm run151 diagrams` in `website/`) parses every `mermaid` block in `docs/` with152 the Mermaid the site draws with, and names the page, the line and153 Mermaid's error. A `;` in a sequence diagram's message ends the154 statement, so write a comma, or `#59;` where the semicolon matters.155156## Pictures of 012157158A page shows 012 as a picture: a still of the screen in the site's159color mode, or a recording. A screen typed out in a code block reads as160a test fixture, loses the colors that carry meaning, and wraps on a161narrow page, so `scripts/doclint` fails a code block that draws one162(box-drawing lines with the menu bar or the notebook's toolbar, or the163grid's column headers).164165A still is a [golden screen](testing.md#golden-screens) drawn as a PNG.166Each is an entry of `docScreens` in `e2e/stills_test.go`: its name,167the screen whose setup it records, a terminal size that reads on a168page (80 columns, unless the state needs more) and the169[family](#font-and-colors) of the pages that show it. `make screens`170records it on a dark and a light terminal and draws both into171`docs/media`, in the family's dark and light schemes:172173```go174{name: "evaluate", from: "evaluate", cols: 80, rows: 12, family: "Catppuccin"},175// docs/media/evaluate-dark.png and docs/media/evaluate-light.png176```177178The drawing is Go (`e2e/stilldraw_test.go`): the golden's cells in its179page's [color schemes](#font-and-colors), text in JetBrains Mono, and180box drawing, blocks, braille and the chrome's symbols drawn as a181terminal draws them, so frames join and every machine draws the same182picture. Each PNG records which golden it was drawn from, and183`make e2e` fails when a golden has changed since.184185A page shows both pictures together, marked as GitHub marks an image for186one color mode; `custom.css` shows the site's the same way:187188```md189![Evaluate formula on B8, two steps in: the next part underlined](../media/evaluate-dark.png#gh-dark-mode-only)190![Evaluate formula on B8, two steps in: the next part underlined](../media/evaluate-light.png#gh-light-mode-only)191```192193- The alt text says what the picture shows, the state and what to look194 at, the same words on both. Write a range in it as `B3 to B5`: the site195 reads `:B5` in text as a directive and drops it.196- One still where the state is the point: what a feature looks like197 before a page explains it, or a state words describe badly (a box,198 marks in the grid). The prose keeps what the picture can't: keys,199 limits, why.200- A flow of several steps is a recording, a VHS tape in `demos/`201 ([Demo recordings](testing.md#demo-recordings)).202- `scripts/doccheck` fails on a still no page shows, or one shown203 without its other color mode.204205## Font and colors206207Every picture of 012 is set in one font, JetBrains Mono: the208recordings, the stills, and the site's code and terminal frames. It is209VHS's and Ghostty's default, so the pictures look like the terminals210people use; it reads well small, its italic isn't cursive, and the SIL211Open Font License lets it be bundled. The site's comes from212`@fontsource/jetbrains-mono`, and the stills and recordings use the213TTFs in `e2e/testdata/fonts` (licence in `NOTICE`). VHS's browser draws214with the fonts the system or the page gives it, so `make demos` serves215ttyd's own page with the font added (`demos/lib/font-page`) and the216recordings need nothing installed. Box drawing and blocks are drawn as217shapes in both, by xterm.js in the recordings and by the stills'218drawing, so frames join whatever the font.219220The pictures' colors are a few terminal color schemes people know, in221families of a dark and a light scheme, so the docs don't all look alike222while each picture stays plainly 012. Each page is in one family:223224| Family | Dark | Light | Pages |225|---|---|---|---|226| Catppuccin | `Catppuccin Mocha` | `Catppuccin Latte` | `getting-started/`, `contributing/`, `reference/`, `formulas/tracing.md` |227| Tokyo Night | `tokyonight` | `tokyonight-day` | `nushell/` |228| Rosé Pine | `rose-pine` | `rose-pine-dawn` | `sheets/rules.md`, `sheets/formatting.md`, `sheets/tables.md` |229| GitHub | `GitHub Dark` | `Github` | `sheets/` |230| Gruvbox | `GruvboxDark` | `Gruvbox Light` | `files/`, `formulas/` |231| Nord | `nord` | `nord-light` | `agents/`, `terminal/` |232233- A page is in the family that names it, or else the one naming its234 deepest folder. Its stills are drawn in the family's dark and light235 schemes, and its recordings use either one (`Set Theme` in the tape,236 or `demos/lib/setup.tape`'s). The README and the landing page, a tour237 of every topic, show each recording as its own page does.238- `scripts/doccheck` fails on a page showing a picture in no family,239 and on a still or a tape in a family other than its pages'.240- A family is a restrained, widely used scheme with both a dark and a241 light variant: no neon or high-saturation schemes. Its schemes are242 named as in 012's built-in list (`internal/ui/theme/themes.json`,243 VHS's own list, so `Set Theme` takes the same names), and244 `TestPictureSchemes` (`internal/ui/theme`) holds each to readable245 contrast: its text on its background at least 4.5:1, and 012's roles246 drawn in it (header bands, the selection, the pointer, muted text)247 at their minimums.248- The recordings run 012 with its theme set to the tape's scheme249 (`make demos` sets `O12_THEME` from `Set Theme`), so 012's roles get250 the scheme's colors with their contrast held, as for anyone who picks251 that scheme. A still draws its golden's palette colors in the scheme252 and holds each cell to the same minimums (4.5:1 for text, 3:1 for253 lines and muted text, 2:1 for faint text), moving the text toward the254 scheme's text color as 012 does, so it stays drawn from the golden.