diff --git a/Cargo.toml b/Cargo.toml index ce890e9..00b049f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,25 @@ include = [ "/LICENSE-APACHE", ] +# Off by default, and the only feature this crate has. +# +# `www` compiles `atgc www`, which builds the project's landing page out of +# this tree. Nobody who installed atgc wants that command: it is a thing this +# repository does, not a thing the tool does, and a marketing page has no +# business appearing in the surface a user can reach. Gated rather than merely +# hidden, so a released binary does not carry the subcommand, the page, or the +# 43 KB of font it inlines — `--help` cannot list what was never compiled. +# +# Build the site with `cargo run --features www -- www`; see www/README.md. +# +# The site's own tests are *not* behind it. They are `cfg(any(feature = "www", +# test))`, so a plain `cargo test` still runs them: a feature that quietly +# takes a hundred assertions out of the default test run is a feature that +# rots, and the point of building the page from the binary was that its claims +# get checked. +[features] +www = [] + # These apply to this package only. vendor/jacquard-oauth is a separate # package with its own manifest, so it is not linted by them. [lints.rust] diff --git a/plan/www.md b/plan/www.md index f77166a..e522987 100644 --- a/plan/www.md +++ b/plan/www.md @@ -58,11 +58,15 @@ spindle — and neither is blocked on the other. ## Done -- [x] `atgc www` builds the page — one hidden command, into `www/dist/`, +- [x] `cargo run --features www -- www` builds the page, into `www/dist/`, which is ignored rather than checked in: everything on the page that could be wrong is something the binary already knows, so a copy in git is a copy that goes stale on the next release. `www/README.md` is what - lives in `www/` instead + lives in `www/` instead. Behind an off-by-default feature and not + merely hidden: an installed atgc has no `www` command, no page and no + font, because a marketing page does not belong in the surface a user + can reach. Its tests are `cfg(any(feature, test))` so `cargo test` + still covers them - [x] The page, answering the three questions in order: what is this, what does it need, how do I install it. One file, no external requests — no font CDN, no analytics, no framework — with the stylesheet, the script, diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 3225448..712d4f0 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -50,6 +50,9 @@ pub(crate) mod repo; pub(crate) mod report; pub(crate) mod search; pub(crate) mod stack; +// The site builder. `test` as well as the feature so `cargo test` still +// covers it — see the `[features]` note in Cargo.toml. +#[cfg(any(feature = "www", test))] pub(crate) mod www; use anyhow::{Result, bail}; diff --git a/src/html/brand.rs b/src/html/brand.rs index 6ac176d..26b77cd 100644 --- a/src/html/brand.rs +++ b/src/html/brand.rs @@ -1,7 +1,7 @@ //! The one palette, the one mark, and the CSS that draws the field. //! //! atgc renders itself in a browser in two places now — the pages the OAuth -//! callback serves ([`super::pages`]) and the site [`super::site`] builds — +//! callback serves ([`super::pages`]) and the site `site` builds — //! and the promise `brand/` was built on is that atgc looks like one thing //! wherever it is drawn. Two pages that each declared their own `--a` //! is exactly the drift `brand/build.py --check` exists to catch on the @@ -64,7 +64,9 @@ const LIGHT_VARS: &str = "\ pub(crate) enum Scheme { /// Light, unless the reader's system asks for dark. System, - /// Dark, unless the reader's system asks for light. + /// Dark, unless the reader's system asks for light. Only the site + /// wants this, so it is compiled where the site is. + #[cfg(any(feature = "www", test))] DarkFirst, } @@ -78,6 +80,7 @@ pub(crate) enum Scheme { pub(crate) fn theme_css(scheme: Scheme) -> String { let (first, second, query, declared) = match scheme { Scheme::System => (LIGHT_VARS, DARK_VARS, "dark", "light dark"), + #[cfg(any(feature = "www", test))] Scheme::DarkFirst => (DARK_VARS, LIGHT_VARS, "light", "dark light"), }; format!( @@ -91,6 +94,10 @@ pub(crate) fn theme_css(scheme: Scheme) -> String { /// Sixteen lines rather than a dependency: the whole of what atgc needs /// from base64 is one direction, no line wrapping, and no configuration, /// and a crate for that is a supply chain for that. +/// +/// Only `site` wants this — the favicon is percent-encoded, not +/// base64 — so it is compiled where that is. +#[cfg(any(feature = "www", test))] pub(crate) fn base64(bytes: &[u8]) -> String { const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; let mut out = String::with_capacity(bytes.len().div_ceil(3) * 4); diff --git a/src/html/field.rs b/src/html/field.rs index 1f67a94..f2aa0be 100644 --- a/src/html/field.rs +++ b/src/html/field.rs @@ -99,6 +99,10 @@ pub(crate) fn field() -> String { /// Any canvas as markup, with the muted ink marked up too: for a block whose /// text is the subject rather than the texture, where a border has to read /// as quieter than the line inside it. +/// +/// Only `site` wants this, so it is compiled where that is — it is +/// behind the `www` feature, which is why this is not a doc link. +#[cfg(any(feature = "www", test))] pub(crate) fn panel(canvas: &Canvas) -> String { render(canvas, "m") } diff --git a/src/html/mod.rs b/src/html/mod.rs index d6d04bf..6bd85a1 100644 --- a/src/html/mod.rs +++ b/src/html/mod.rs @@ -2,8 +2,10 @@ //! //! Two kinds of page live here. [`pages`] is what a browser lands on when //! `atgc auth login` finishes, which is the only part of atgc a person sees -//! rendered rather than printed; [`site`] is atgc.codes, which `atgc www` -//! writes out and nothing at runtime ever asks for. +//! rendered rather than printed; `site` is atgc.codes, which `atgc www` +//! writes out and nothing at runtime ever asks for. That one is behind the +//! off-by-default `www` feature, so an installed atgc has neither the module +//! nor the command — see the `[features]` note in `Cargo.toml`. //! //! The first of them used to live inside the OAuth client, next to the //! socket that serves it, which put markup and SVG in the middle of a module @@ -29,6 +31,7 @@ pub(crate) mod brand; pub(crate) mod field; pub(crate) mod pages; +#[cfg(any(feature = "www", test))] pub(crate) mod site; /// Text bound for a page. diff --git a/src/html/site/mod.rs b/src/html/site/mod.rs index 0c8a6ab..a19bc4c 100644 --- a/src/html/site/mod.rs +++ b/src/html/site/mod.rs @@ -79,8 +79,13 @@ fn font_faces() -> String { const INSTALL: &str = "cargo install --git https://tangled.org/permadeath.com/atgc"; /// The sign-off. The letters of the name are the bases, so a page about -/// atgc gets to say this and mean it literally. -const DNA_LINE: &str = "It's in our DNA."; +/// atgc gets to say this and mean it literally — and it is about the thing +/// the tool is actually built around, which is a dozen worktrees running at +/// once. +/// +/// Lower case, including the DNA, because it is a slogan in a hand-drawn +/// face rather than a sentence with an initialism in it. +const SLOGAN: &str = "agents are in our dna"; /// The forge atgc is a client for, and the reason there is anything here to /// be a client of. Its own name carries three of the four bases — t, a and @@ -478,6 +483,7 @@ pub(crate) fn index_page() -> String {
{slogan}
A terminal client for Tangled, a git forge with no database behind it. Your repos, pull requests and issues are records in your own PDS — you can read @@ -633,7 +639,6 @@ pub(crate) fn index_page() -> String {