web: outfit draws the ui and prose and maple mono the code, both self-hosted latin subsets in place of plex mono
Signed-off-by: dawn <dawn@tangled.org>
141 unmodified linesExpand all1421431441451461471481491501511521531541551561571581461471481498 unmodified lines15815916016116216316416516616716816917017117217317417517617717845 unmodified lines2242252262272282292302312322332342352362372382392402412422432441 unmodified line24624724824923725025125225325425525625725825978 unmodified lines141 unmodified linesExpand all "type": "git", "url": "https://tangled.org/ptr.pet/hydrant" } }, "ibm-plex-mono-src": { "flake": false, "locked": { "lastModified": 1731402384, "narHash": "sha256-OwUmrPfEehLDz0fl2ChYLK8FQM2p0G1+EMrGsYEq+6g=", "type": "tarball", "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" }, "original": { "type": "tarball", "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" } }, "indigo": { "flake": false, "locked": { "lastModified": 1753693716,8 unmodified lines "repo": "indigo", "type": "github" } }, "maple-mono-src": { "flake": false, "locked": { "lastModified": 499162500, "narHash": "sha256-dLPdcm6c4/PqPfgAVcvBj7pRKoVoaqGbRFqoQWZm9Hk=", "type": "tarball", "url": "https://registry.npmjs.org/@fontsource/maple-mono/-/maple-mono-5.3.0.tgz" }, "original": { "type": "tarball", "url": "https://registry.npmjs.org/@fontsource/maple-mono/-/maple-mono-5.3.0.tgz" } }, "microvm": { "inputs": { "nixpkgs": [ "nixpkgs"45 unmodified lines "repo": "nixpkgs", "type": "github" } }, "outfit-src": { "flake": false, "locked": { "lastModified": 499162500, "narHash": "sha256-cumnAfh8tmt/GdYt+nqTka+o6M656VPZfHAp3xRXGKM=", "type": "tarball", "url": "https://registry.npmjs.org/@fontsource/outfit/-/outfit-5.3.0.tgz" }, "original": { "type": "tarball", "url": "https://registry.npmjs.org/@fontsource/outfit/-/outfit-5.3.0.tgz" } }, "root": { "inputs": { "fenix": "fenix", "fetch-tangled": "fetch-tangled",1 unmodified line "glisten-src": "glisten-src", "gomod2nix": "gomod2nix", "hydrant": "hydrant", "hydrant-dev": "hydrant-dev", "ibm-plex-mono-src": "ibm-plex-mono-src", "indigo": "indigo", "maple-mono-src": "maple-mono-src", "microvm": "microvm", "nixpkgs": "nixpkgs", "nixpkgs-pds": "nixpkgs-pds", "outfit-src": "outfit-src", "sqlite-lib-src": "sqlite-lib-src", "timeless-fonts-src": "timeless-fonts-src" } },78 unmodified lines25 unmodified lines26272829303130313233343536373839404125 unmodified lines6768697067717273747576142 unmodified linesExpand all219220221222218223224225226227606 unmodified linesExpand all25 unmodified lines timeless-fonts-src = { url = "https://media.timeless.co/type/Timeless-Type-Family-1.094.zip"; flake = false; }; ibm-plex-mono-src = { url = "https://github.com/IBM/plex/releases/download/%40ibm%2Fplex-mono%401.1.0/ibm-plex-mono.zip"; outfit-src = { url = "https://registry.npmjs.org/@fontsource/outfit/-/outfit-5.3.0.tgz"; flake = false; }; maple-mono-src = { url = "https://registry.npmjs.org/@fontsource/maple-mono/-/maple-mono-5.3.0.tgz"; flake = false; }; sqlite-lib-src = { url = "https://sqlite.org/2024/sqlite-amalgamation-3450100.zip"; flake = false; };25 unmodified lines gomod2nix, indigo, timeless-fonts-src, sqlite-lib-src, ibm-plex-mono-src, outfit-src, maple-mono-src, microvm, fetch-tangled, hydrant, hydrant-dev,142 unmodified linesExpand all }; lexgen = self.callPackage ./nix/pkgs/lexgen.nix {inherit indigo;}; goat = self.callPackage ./nix/pkgs/goat.nix {inherit indigo;}; web-static-files = self.callPackage ./nix/pkgs/web-static-files.nix { inherit timeless-fonts-src ibm-plex-mono-src; inherit outfit-src maple-mono-src; }; glisten = self.callPackage ./nix/pkgs/glisten.nix { inherit glisten-src; };606 unmodified linesExpand all12343456678789101112131410111215161718192021222324252627282914151617183031323334{ runCommandLocal, timeless-fonts-src, ibm-plex-mono-src, python3, outfit-src, maple-mono-src, dolly,}:runCommandLocal "web-static-files" {} '' mkdir -p $out/{fonts,logos}}: let fonttools = python3.withPackages (ps: [ps.fonttools ps.brotli]); # fontsource's latin range latin = "U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2190-2199,U+2212,U+2215,U+FEFF,U+FFFD";in runCommandLocal "web-static-files" {nativeBuildInputs = [fonttools];} '' mkdir -p $out/{fonts,logos}
cp -f ${timeless-fonts-src}/Sans-Grotesk/TimelessSansVF.woff2 $out/fonts/ cp -f ${timeless-fonts-src}/Sans-Grotesk/static/woff2/TimelessSans-Grotesk*Italic.woff2 $out/fonts/ cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono*.woff2 $out/fonts/ for weight in 400 500 600 700; do cp -f ${outfit-src}/files/outfit-latin-$weight-normal.woff2 $out/fonts/ done cp -f ${outfit-src}/LICENSE $out/fonts/outfit-LICENSE.txt
# maple mono's ligatures and character variants are most of its size, and code shows as written for weight in 400 700; do for style in normal italic; do pyftsubset ${maple-mono-src}/files/maple-mono-latin-$weight-$style.woff2 \ --unicodes=${latin} --layout-features=kern,mark,mkmk --flavor=woff2 \ --output-file=$out/fonts/maple-mono-latin-$weight-$style.woff2 done done cp -f ${maple-mono-src}/LICENSE $out/fonts/maple-mono-LICENSE.txt
${dolly}/bin/dolly -output $out/logos/dolly.png -size 180 ${dolly}/bin/dolly -output $out/logos/dolly.ico -size 48 ${dolly}/bin/dolly -output $out/logos/dolly.svg -color currentColor -favicon ${dolly}/bin/dolly -output $out/logos/logotype.svg -kind logotype -color currentColor'' ${dolly}/bin/dolly -output $out/logos/dolly.png -size 180 ${dolly}/bin/dolly -output $out/logos/dolly.ico -size 48 ${dolly}/bin/dolly -output $out/logos/dolly.svg -color currentColor -favicon ${dolly}/bin/dolly -output $out/logos/logotype.svg -kind logotype -color currentColor ''14 unmodified lines15161718191920212223242526262728293031323333343536373839404142434445464748495051525354555657585960616224 unmodified lines14 unmodified lines <link rel="apple-touch-icon" href="/logos/dolly.png" /> <!-- the faces a page's first screen draws, so it paints in them and not in a fallback --> <link rel="preload" href="/fonts/IBMPlexMono-Regular.woff2" href="/fonts/outfit-latin-400-normal.woff2" as="font" type="font/woff2" crossorigin /> <link rel="preload" href="/fonts/IBMPlexMono-Medium.woff2" href="/fonts/maple-mono-latin-400-normal.woff2" as="font" type="font/woff2" crossorigin /> <link rel="preload" href="/fonts/IBMPlexMono-Bold.woff2" href="/fonts/outfit-latin-600-normal.woff2" as="font" type="font/woff2" crossorigin /> <link rel="preload" href="/fonts/outfit-latin-700-normal.woff2" as="font" type="font/woff2" crossorigin /> <link rel="preload" href="/fonts/maple-mono-latin-700-normal.woff2" as="font" type="font/woff2" crossorigin /> <link rel="preload" href="/fonts/outfit-latin-500-normal.woff2" as="font" type="font/woff2" crossorigin /> <script> // a copy of applyTheme from lib/theme.ts since this runs before the app loads, keep them in sync (() => { const theme = /(?:^|;\s*)theme=([^;]*)/.exec(document.cookie)?.[1];24 unmodified lines1234556789789101112131415161718151617181920212223242523242526272829303132333132333435363738394041394041424344454647484950515253545556575859606162636465666768/* self-hosted fonts, served from /fonts (nix/pkgs/web-static-files.nix). shared with the docs site, which imports this file directly */
/* block, not swap: the head preloads the faces a first screen draws, so a page paints once they're in instead of painting a fallback mono and swapping */ paints once they're in instead of painting a fallback and swapping */@font-face { font-family: "IBMPlexMono"; src: url("/fonts/IBMPlexMono-Regular.woff2") format("woff2"); font-weight: normal; font-family: "Outfit"; src: url("/fonts/outfit-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: block;}
@font-face { font-family: "IBMPlexMono"; src: url("/fonts/IBMPlexMono-Italic.woff2") format("woff2"); font-weight: normal; font-style: italic; font-family: "Outfit"; src: url("/fonts/outfit-latin-500-normal.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: block;}
@font-face { font-family: "IBMPlexMono"; src: url("/fonts/IBMPlexMono-Medium.woff2") format("woff2"); font-weight: 500; font-family: "Outfit"; src: url("/fonts/outfit-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: block;}
@font-face { font-family: "IBMPlexMono"; src: url("/fonts/IBMPlexMono-Bold.woff2") format("woff2"); font-weight: bold; font-family: "Outfit"; src: url("/fonts/outfit-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: block;}
@font-face { font-family: "IBMPlexMono"; src: url("/fonts/IBMPlexMono-BoldItalic.woff2") format("woff2"); font-weight: bold; font-family: "Maple Mono"; src: url("/fonts/maple-mono-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: block;}
@font-face { font-family: "Maple Mono"; src: url("/fonts/maple-mono-latin-400-italic.woff2") format("woff2"); font-weight: 400; font-style: italic; font-display: block;}
@font-face { font-family: "Maple Mono"; src: url("/fonts/maple-mono-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: block;}
@font-face { font-family: "Maple Mono"; src: url("/fonts/maple-mono-latin-700-italic.woff2") format("woff2"); font-weight: 700; font-style: italic; font-display: block;}2 unmodified lines3456789101112300 unmodified linesExpand all2 unmodified lines@layer components { .markup { @apply typography-paragraph-body text-foreground-default; overflow-wrap: break-word; /* prose keeps proportional digits */ font-variant-numeric: normal; }
.markup > :first-child, /* the wrapper hides the render's first child from the rule above, so repeat it inside */300 unmodified linesExpand all41 unmodified lines424344454646474849125 unmodified linesExpand all175176177178179180181182183184185181186187188189190191192193194195196197198199311 unmodified linesExpand all41 unmodified lines --radius-lg: 0px; --radius-xl: 0px; --radius-2xl: 0px; --radius-3xl: 0px; --font-sans: var(--font-mono);
--color-background-default: var(--y-card); --color-background-subtle: var(--y-bg); --color-background-canvas: var(--y-bg);125 unmodified linesExpand all }}
@layer base { /* outfit's x-height is lower than maple mono's: both are drawn at one x-height, so a size reads the same in either and a fallback face lands close. ui digits are tabular, so counts and ages hold their columns */ html { font-size-adjust: ex-height 0.5; } body { font-family: var(--font-mono); font-family: var(--font-sans); font-variant-numeric: tabular-nums; } /* code shows as written: no ligatures, whichever face draws it */ code, kbd, pre, samp { font-variant-ligatures: none; }
:focus-visible { outline: 2px solid var(--y-accent); outline-offset: -2px;311 unmodified linesExpand all29 unmodified lines3031323334343536363738394041424142434445461025 unmodified linesExpand all29 unmodified lines@theme { --radius-sm: 0.375rem; --radius-md: 0.5rem;
--font-sans: "TimelessSans", "TimelessSans Fallback", ui-sans-serif, system-ui, sans-serif; --font-sans: "Outfit", ui-sans-serif, system-ui, sans-serif; --font-mono: "IBMPlexMono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Maple Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--font-sans--font-feature-settings: "kern" 1, "liga" 1, "tnum" 1;
--font-weight-medium: 510; --font-weight-semibold: 590; --font-weight-medium: 500; --font-weight-semibold: 600;
--ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1);
--ease-spring: linear(1025 unmodified linesExpand all20 unmodified lines21222324252526272829243 unmodified linesExpand all20 unmodified lines const cloneUrl = $derived(`${page.url.origin}${base}`); const website = $derived(safeHref(repo.website)); const trimScheme = (url: string) => url.replace(/^https?:\/\//, "").replace(/\/$/, ""); // a long name cuts to its first dozen letters at most, a short one keeps no room past its end const keep = (text: string) => `${Math.min(text.length, 12)}ch`; const keep = (text: string) => (text.length > 12 ? "12ch" : "max-content"); const topics = $derived([...new Set(repo.topics ?? [])]);
let copied = $state(false); // without js the link goes to the repo, the same url git clones243 unmodified linesExpand all