- commit
- def2bdd37c699269249d45f6d79c0009e70a53b0
- parent
- 3907f34ef71afdc004134c25eee6317f9a1c2ff0
- author
- Dami <dami.etoile@gmail.com>
| A | .github/ | 32 | ++++++++++ |
| A | scripts/ | 97 | ++++++++++++++++++++++++++++++ |
@@ -0,0 +1,32 @@
1+# Publishes the latest main as a static site: every library, the bundle, the demos and a landing page.2+name: pages3+on:4+ push:5+ branches: [main]6+ workflow_dispatch:7+permissions:8+ contents: read9+ pages: write10+ id-token: write11+concurrency:12+ group: pages13+ cancel-in-progress: true14+jobs:15+ deploy:16+ runs-on: ubuntu-latest17+ environment:18+ name: github-pages19+ url: ${{ steps.deployment.outputs.page_url }}20+ steps:21+ - uses: actions/checkout@v422+ - uses: denoland/setup-deno@v223+ with:24+ deno-version: v2.x25+ - run: deno task size26+ - run: deno task bundle27+ - run: deno task site28+ - uses: actions/upload-pages-artifact@v329+ with:30+ path: _site31+ - id: deployment32+ uses: actions/deploy-pages@v4@@ -0,0 +1,97 @@
1+// Builds the static site in _site/: every library, the bundle, the demos and a landing page.2+// Run `deno task bundle` first so dist/ exists.3+import { brotliCompressSync } from "node:zlib";4+import { copy } from "jsr:@std/fs@1/copy";5+6+const REPO = "FelineStateMachine/nobel";7+const groups: [string, string, [string, string, number][]][] = [8+ ["nonmetal", "the base: relays, signatures, hooks", [["hydrogen", "H", 1]]],9+ ["noble gases", "the core: data and transport", [["xenon", "Xe", 54], ["krypton", "Kr", 36], ["argon", "Ar", 18], ["helium", "He", 2], ["neon", "Ne", 10], ["radon", "Rn", 86], ["oganesson", "Og", 118]]],10+ ["halogens", "secrets and trust", [["fluorine", "F", 9], ["chlorine", "Cl", 17], ["iodine", "I", 53]]],11+ ["transition metals", "signed exchanges", [["gold", "Au", 79], ["mercury", "Hg", 80]]],12+ ["lanthanides", "visual presets", [["praseodymium", "Pr", 59], ["europium", "Eu", 63], ["cerium", "Ce", 58]]],13+];14+const prefix: Record<string, string> = { hydrogen: "nhy", fluorine: "nfl", iodine: "nio" };15+const root = new URL("../", import.meta.url), out = new URL("_site/", root);16+const esc = (s: string) => s.replace(/[&<>"]/g, (c) => `&#${c.charCodeAt(0)};`);17+const kb = (n: number) => (n / 1024).toFixed(1);18+19+await Deno.remove(out, { recursive: true }).catch(() => {});20+await Deno.mkdir(out, { recursive: true });21+for (const d of ["dist", "demo"]) await copy(new URL(d, root), new URL(d, out));22+23+let cells = "";24+for (const [group, about, libs] of groups) {25+ cells += `<section class="${group.split(" ")[0]}"><h2>${group} <small>${about}</small></h2><div class="row">`;26+ for (const [name, sym, z] of libs) {27+ const src = await Deno.readFile(new URL(`${name}/${name}.js`, root));28+ const head = (await Deno.readTextFile(new URL(`${name}/README.md`, root))).split("\n")[0];29+ const tagline = head.split(" - ").slice(1).join(" - ");30+ await Deno.mkdir(new URL(`${name}/`, out), { recursive: true });31+ await Deno.writeFile(new URL(`${name}/${name}.js`, out), src);32+ const p = prefix[name] ?? `n${sym.toLowerCase()}`;33+ cells += `<article><a class="doc" href="https://github.com/${REPO}/tree/main/${name}#readme">34+<span class="z">${z}</span><b class="sym">${sym}</b><span class="name">${name}</span><span class="tag">${esc(tagline)}</span></a>35+<span class="meta"><code>${p}-</code> ${kb(src.length)}/${kb(brotliCompressSync(src).length)}kb</span>36+<a class="src" href="${name}/${name}.js">${name}.js</a></article>`;37+ }38+ cells += `</div></section>`;39+}40+41+const min = await Deno.readFile(new URL("dist/nobel.min.js", root));42+const cdn = `https://cdn.jsdelivr.net/gh/${REPO}@main`, site = "https://felinestatemachine.github.io/nobel/";43+const html = `<!doctype html>44+<html lang="en">45+<head>46+<meta charset="utf-8">47+<meta name="viewport" content="width=device-width, initial-scale=1">48+<title>nobel: tiny nostr libraries for plain HTML</title>49+<meta name="description" content="A family of tiny, dependency-free nostr libraries for plain HTML, each named for an element.">50+<style>51+ :root { --ink:#1d1b16; --paper:#f4efe4; --line:#d8cfbd; --muted:#7a7263; color-scheme:light dark; }52+ @media (prefers-color-scheme:dark) { :root { --ink:#ece6d8; --paper:#171512; --line:#3a352c; --muted:#9c9384; } }53+ * { box-sizing:border-box; }54+ body { margin:0; background:var(--paper); color:var(--ink); font:15px/1.55 ui-serif, Georgia, serif; }55+ main { max-width:1080px; margin:0 auto; padding:48px 20px 80px; }56+ h1 { font:600 15px/1 ui-monospace, Menlo, monospace; letter-spacing:.14em; text-transform:uppercase; margin:0 0 10px; }57+ .lede { max-width:62ch; margin:0 0 32px; font-size:17px; }58+ h2 { font:600 12px/1 ui-monospace, Menlo, monospace; letter-spacing:.12em; text-transform:uppercase; margin:28px 0 10px; }59+ h2 small { color:var(--muted); letter-spacing:0; text-transform:none; font-weight:400; margin-left:.5em; }60+ .row { display:grid; grid-template-columns:repeat(auto-fill, minmax(150px, 1fr)); gap:8px; }61+ article { border:1px solid var(--line); border-top:4px solid var(--g); border-radius:6px; padding:10px 12px; display:flex; flex-direction:column; gap:6px; min-height:170px; }62+ .doc { color:inherit; text-decoration:none; display:flex; flex-direction:column; flex:1; }63+ .z { font:11px ui-monospace, Menlo, monospace; color:var(--muted); }64+ .sym { font:600 34px/1.1 ui-serif, Georgia, serif; color:var(--g); }65+ .name { font:600 13px ui-monospace, Menlo, monospace; }66+ .tag { font-size:13px; color:var(--muted); }67+ .meta, .src { font:11px ui-monospace, Menlo, monospace; color:var(--muted); }68+ .src { color:var(--g); }69+ .nonmetal { --g:#2f7d5b; } .noble { --g:#6a4fb3; } .halogens { --g:#b0452a; } .transition { --g:#a17a12; } .lanthanides { --g:#2d6fa3; }70+ pre { background:color-mix(in srgb, var(--ink) 6%, transparent); border:1px solid var(--line); border-radius:6px; padding:12px 14px; overflow:auto; font:13px/1.5 ui-monospace, Menlo, monospace; }71+ a { color:inherit; }72+ footer { margin-top:40px; color:var(--muted); font-size:13px; }73+</style>74+</head>75+<body>76+<main>77+ <h1>nobel</h1>78+ <p class="lede">Tiny nostr libraries for plain HTML, in the spirit of <a href="https://fixiproject.org">the fixi project</a>. Each one is a single dependency-free script under 5kb, named for an element, and they compose through DOM events. Pick the ones you need, or take them all.</p>79+ <pre><script src="${cdn}/hydrogen/hydrogen.js"></script>80+<script src="${cdn}/xenon/xenon.js"></script>81+82+<ol nhy-relay="wss://relay.example" nxe-filter='{"kinds":[1],"limit":20}'>83+ <template><li>{content}</li></template>84+</ol></pre>85+ ${cells}86+ <h2>all of them <small>one file, ${kb(min.length)}kb minified, ${kb(brotliCompressSync(min).length)}kb brotli</small></h2>87+ <pre><script src="${site}dist/nobel.min.js"></script></pre>88+ <p>Or from this site: <a href="dist/nobel.js">dist/nobel.js</a>, <a href="dist/nobel.min.js">dist/nobel.min.js</a>. Load hydrogen before the libraries that use it, and the peers before xenon.</p>89+ <h2>demos <small>add ?relay=wss://... to each</small></h2>90+ <p><a href="demo/">feed</a>, <a href="demo/iodine.html">private messages</a>, <a href="demo/oganesson.html">presence, typing, cursors</a>, <a href="demo/lanthanides.html">profiles and theme</a>, <a href="demo/europium.html">note embeds</a></p>91+ <footer>Always the latest <code>main</code>. <a href="https://github.com/${REPO}">Source on GitHub</a>, released into the public domain (Unlicense).</footer>92+</main>93+</body>94+</html>95+`;96+await Deno.writeTextFile(new URL("index.html", out), html);97+console.log(`_site/ built: ${groups.flatMap((g) => g[2]).length} libraries`);