Site and gallery: the repo and the showcase catalog live on Gitea at git.zacharyzhang.com
CI / crate (push) Failing after 2s
CI / site (push) Successful in 30s
CI / platforms (ubuntu-24.04) (push) Failing after 1m48s
CI / platforms (macos-15-intel) (push) Canceled after 0s
CI / platforms (ubuntu-24.04-arm) (push) Canceled after 0s
CI / platforms (windows-11-arm) (push) Canceled after 0s
CI / platforms (windows-latest) (push) Failing after 15s

Links, the header's Gitea mark, the catalog's archive download and the showcase pin
workflow (Gitea's API and commit status) move off GitHub; pinned at 6973834, which
restores TokenLedger.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 16:20:32 -04:00
1 parent 2a578d3238
commit 49ed1f8405
18 files changed
+45 -47

No files matched your search

+12 -17
View File
@@ -1,6 +1,6 @@
name: Showcase
# Moves the site's showcase pin to the catalog's main once its checks pass, then deploys.
# Moves the site's showcase pin to the Gitea catalog's main once its checks pass, then deploys.
on:
schedule:
- cron: "*/30 * * * *"
@@ -32,28 +32,26 @@ jobs:
persist-credentials: false
- id: head
env:
GH_TOKEN: ${{ github.token }}
API: ${{ github.server_url }}/api/v1/repos/${{ env.CATALOG }}
FORCE: ${{ inputs.deploy }}
run: |
head=$(gh api "repos/$CATALOG/commits/main" --jq .sha)
head=$(curl -fsS "$API/branches/main" | jq -r .commit.id)
pinned=$(tr -d '[:space:]' < frontend/showcase.lock)
if [ "$head" = "$pinned" ]; then
echo "showcase: pinned at ${head:0:7}, the catalog's main"
[ "$FORCE" = "true" ] && echo "commit=$head" >> "$GITHUB_OUTPUT"
exit 0
fi
runs=$(gh api "repos/$CATALOG/commits/$head/check-runs" --jq '.check_runs')
total=$(echo "$runs" | jq length)
waiting=$(echo "$runs" | jq '[.[] | select(.status != "completed")] | length')
failed=$(echo "$runs" | jq '[.[] | select(.status == "completed" and (.conclusion | IN("success", "skipped", "neutral") | not))] | length')
if [ "$total" -eq 0 ] || [ "$waiting" -gt 0 ]; then
status=$(curl -fsS "$API/commits/$head/status")
total=$(echo "$status" | jq .total_count)
state=$(echo "$status" | jq -r .state)
if [ "$total" -eq 0 ] || [ "$state" = "pending" ]; then
echo "showcase: ${head:0:7}'s checks have not finished; next run looks again"
[ "$FORCE" = "true" ] && echo "commit=$pinned" >> "$GITHUB_OUTPUT"
[ "$FORCE" = "true" ] && echo "commit=$pinned" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "$failed" -gt 0 ]; then
echo "::error::showcase: ${head:0:7} failed its catalog checks; the pin stays at ${pinned:0:7}"
if [ "$state" != "success" ]; then
echo "::error::showcase: ${head:0:7} failed its catalog checks ($state); the pin stays at ${pinned:0:7}"
exit 1
fi
echo "showcase: ${pinned:0:7} -> ${head:0:7}"
@@ -84,11 +82,8 @@ jobs:
with:
tool: ${{ env.WASM_BINDGEN }}
- name: wasm-opt
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release download -R WebAssembly/binaryen -p 'binaryen-*-x86_64-linux.tar.gz' -D "$RUNNER_TEMP"
tar -xzf "$RUNNER_TEMP"/binaryen-*-x86_64-linux.tar.gz -C "$RUNNER_TEMP"
curl -fsSL https://github.com/WebAssembly/binaryen/releases/download/version_132/binaryen-version_132-x86_64-linux.tar.gz | tar -xz -C "$RUNNER_TEMP"
echo "$(ls -d "$RUNNER_TEMP"/binaryen-*/)bin" >> "$GITHUB_PATH"
- uses: pnpm/action-setup@v6
with:
@@ -113,8 +108,8 @@ jobs:
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
- name: Commit the pin
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git config user.name 'gitea-actions'
git config user.email 'actions@git.zacharyzhang.com'
git add frontend/showcase.lock
git diff --cached --quiet && exit 0
git commit -m "Site · Showcase: pin Ely-GPUI-Showcases at ${COMMIT:0:7}"
+2 -1
View File
@@ -17,7 +17,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
- Pictures: `image` 0.25 (MIT OR Apache-2.0), the crate gpui decodes with, default features off; it turns decoded frames and rims map tiles.
- Maps: Natural Earth's 110m countries (public domain). `assets/maps/countries.geojson`, trimmed by `scripts/countries.py` to an ISO code, a name and positions to 0.01°, backs `maps::WorldMap`; the gallery's tiles are cut from the same file, z0 to z3, by `scripts/tiles.py` with Pillow.
- Web: on wasm32, `web-time` 1.1 (MIT OR Apache-2.0) gives the `Instant` gpui's executor returns, std's own natively; jiff takes `js`, rust-embed `debug-embed`, similar `wasm32_web_time`. The gallery's web entry takes `gpui_web`, `wasm-bindgen`, `js-sys` and `web-sys` as wasm-only dev-dependencies, and a Hebrew cut of Noto Sans Hebrew 2.003 (OFL, `examples/gallery/fonts`): gpui_web asks the browser for emoji and CJK alone. The `wasm-bindgen` CLI at Cargo.lock's version and binaryen's `wasm-opt` finish the bundle.
- Gallery: `examples/gallery`. Website: `frontend/` (Vite 8.3, pnpm 11, TypeScript, React 19.3, TanStack Router 1.170 in code-based routes, Lenis 1.3), in serro.ai's language: heavy titles over thin faint text, hairlines, one accent, full-screen sections, isometric line miniatures on a canvas. Pages name a story by its title's first part (`src/data.ts`'s `name`); scroll bars stay hidden; layouts step at 1024 and 768. Each story runs live from the gallery built for wasm32 through gpui_web, in a same-origin iframe, or, where a browser cannot run it, as a native capture. The Docs tab is Markdown in `frontend/src/docs/`, read in its `ORDER` and rendered by `marked` 18 (MIT) inside `vite.config.ts`'s `docs` plugin, so a bad guide fails `pnpm build` and the browser gets HTML alone; a fenced block tagged `example=NAME` shows `examples/docs/NAME.rs`, an example `scripts/check.sh` compiles as `docs_NAME`, so every full Rust sample on the site builds. The Showcase tab lists apps built with Ely from the public repo `ZacharyZhang-NY/Ely-GPUI-Showcases`: manifests, PNG previews and Markdown READMEs, checked by its `scripts/catalog.mjs` (`marked`, `pngjs`, `twitter-text`), its stars refreshed by its CI. The mark is the letter E in iso blocks, its middle arm in the accent: one geometry in `src/iso/mark.ts`, drawn by the engine the miniatures use, worn by the header in the page's iso colors and by the favicon. Below 768px the header shows the mark without its word, which stays the home link's name; below 414px it drops the sound switch. Geist and Geist Mono (OFL, `@fontsource-variable`), Reicon icons (MIT, based on Solar Icons, CC BY 4.0, credited in the footer), simple-icons' GitHub mark (CC0). It deploys to Cloudflare Workers static assets through `npx wrangler` (4.143).
- Gallery: `examples/gallery`. Website: `frontend/` (Vite 8.3, pnpm 11, TypeScript, React 19.3, TanStack Router 1.170 in code-based routes, Lenis 1.3), in serro.ai's language: heavy titles over thin faint text, hairlines, one accent, full-screen sections, isometric line miniatures on a canvas. Pages name a story by its title's first part (`src/data.ts`'s `name`); scroll bars stay hidden; layouts step at 1024 and 768. Each story runs live from the gallery built for wasm32 through gpui_web, in a same-origin iframe, or, where a browser cannot run it, as a native capture. The Docs tab is Markdown in `frontend/src/docs/`, read in its `ORDER` and rendered by `marked` 18 (MIT) inside `vite.config.ts`'s `docs` plugin, so a bad guide fails `pnpm build` and the browser gets HTML alone; a fenced block tagged `example=NAME` shows `examples/docs/NAME.rs`, an example `scripts/check.sh` compiles as `docs_NAME`, so every full Rust sample on the site builds. The Showcase tab lists apps built with Ely from the public repo `ZacharyZhang-NY/Ely-GPUI-Showcases` on git.zacharyzhang.com (Gitea): manifests, PNG previews and Markdown READMEs, checked by its `scripts/catalog.mjs` (`marked`, `pngjs`, `twitter-text`), its stars refreshed by its CI. The mark is the letter E in iso blocks, its middle arm in the accent: one geometry in `src/iso/mark.ts`, drawn by the engine the miniatures use, worn by the header in the page's iso colors and by the favicon. Below 768px the header shows the mark without its word, which stays the home link's name; below 414px it drops the sound switch. Geist and Geist Mono (OFL, `@fontsource-variable`), Reicon icons (MIT, based on Solar Icons, CC BY 4.0, credited in the footer), simple-icons' Gitea mark (CC0). It deploys to Cloudflare Workers static assets through `npx wrangler` (4.143).
## Commands
@@ -265,6 +265,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
- 2026-09-29: the web gallery runs on one thread, since a static site sends no cross-origin isolation, and draws through WebGL2 where WebGPU is missing. Its pictures are served beside the wasm, not embedded: the wasm stays under Cloudflare's 25 MiB, and a story fetches only its own. `wasm-opt -Oz` takes the wasm from 23.0 to 20.0 MB; gzip and brotli stay near 7.9 and 5.5 MB.
- 2026-10-04: the Showcase follows gpui-kit.com/apps: apps live in their own public repo and arrive by pull request. The site pins a commit of it in `frontend/showcase.lock` and moves only when someone bumps the pin, so stars refresh on the site with each bump. READMEs take Markdown and PNG pictures alone, no HTML or video, so the site needs no sanitizer. The catalog started empty.
- 2026-10-05: the pin moves by itself: `.github/workflows/showcase.yml` looks at the catalog's main every 30 minutes and, once that commit's checks pass, builds the gallery and the site, deploys through `CLOUDFLARE_API_TOKEN` (secret) and `CLOUDFLARE_ACCOUNT_ID` (variable), then commits the pin; a run with `deploy` set redeploys at the current pin. A catalog commit that fails its checks keeps the pin. The catalog runs its checks on every pull request without approval, save from accounts new to GitHub; they get no secrets and a read-only token.
- 2026-10-09: the repos moved from GitHub to Gitea at git.zacharyzhang.com; GitHub's copies are gone. The site links there, `pnpm showcase` downloads the catalog's archive from there, and `showcase.yml` runs on Gitea Actions, reading the catalog's head and combined commit status through Gitea's API. The catalog's stars still come from GitHub's API, signed in only with its `STARS_GITHUB_TOKEN` secret, since Gitea's own token means nothing there. TokenLedger, merged on GitHub after the copy was taken, was restored from the site's copy.
- 2026-10-04: chapter 44, Rendering, holds `RenderSurface` alone. gpui at 1a28cff paints `RenderImage`s everywhere, `CVPixelBuffer`s (NV12) on macOS's Metal renderer alone, and shares no device or shader hook, so shader, camera and GPU views are the host's, feeding the surface, and zero-copy or Metal, OpenGL, Vulkan and Direct3D surfaces are blocked (`tasks/ch44.md`). CI tests the crate and builds the gallery on Linux, Windows and macOS, arm64 and x86_64.
- 2026-10-05: an overlay its owner removes without calling `Close` still hands focus back: `take_focus` records each holder and what it took focus from, `give_back` forgets it, and when the focused element leaves the tree the root scope walks back past every gone holder to the focus before them all, else takes it; nested overlays removed together return to what the outer one took focus from. Before, a dialog whose action set its owner's state to closed left focus on the root, and keys reached nothing until a click.
- 2026-10-05: `Select::label` and `TextInput::label` name the control for assistive technology without drawing anything; a text input with neither label nor placeholder had no name, and a select read only its value, so a field named by a description list beside it was anonymous in the AX tree.
+1 -1
View File
@@ -5,7 +5,7 @@ edition = "2024"
rust-version = "1.95"
license = "MIT"
description = "A restrained component library for GPUI, in light and dark."
repository = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Components"
repository = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components"
publish = false
[features]
+1 -1
View File
@@ -11,7 +11,7 @@ Status: early. `TASKS.md` tracks every component, chapter by chapter. To help, s
```toml
[dependencies]
ely-gpui-component = { git = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Components" }
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components" }
gpui = { package = "gpui-pre", version = "=0.3.8" }
gpui_platform = { package = "gpui-pre-platform", version = "=0.3.8", features = ["font-kit"] }
```
+1 -1
View File
@@ -114,7 +114,7 @@ pub fn small_buttons(cx: &App) -> impl IntoElement + use<> {
"share-button",
ShareButton::new("share-page")
.text("Ely, components for GPUI")
.url("https://github.com/ZacharyZhang-NY/Ely-GPUI-Components"),
.url("https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components"),
),
cx,
))
+1 -1
View File
@@ -11,7 +11,7 @@ use crate::{
};
pub fn codes(cx: &mut App) -> impl IntoElement + use<> {
let qr = QrCode::new("https://github.com/ZacharyZhang-NY/Ely-GPUI-Components")
let qr = QrCode::new("https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components")
.expect("a short link fits a QR code");
let label = Barcode::code128("ELY-2419").expect("printable ASCII");
let retail = Barcode::ean13("400638133393").expect("twelve digits");
+2 -2
View File
@@ -26,11 +26,11 @@ fn about() -> AboutDialog {
.description("A component library for GPUI, in light and dark.")
.link(
"Website",
"https://github.com/ZacharyZhang-NY/Ely-GPUI-Components",
"https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components",
)
.link(
"License",
"https://github.com/ZacharyZhang-NY/Ely-GPUI-Components#license",
"https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components#license",
)
.copyright("© 2026 Ely contributors")
}
+6 -4
View File
@@ -1,12 +1,12 @@
// Writes the showcase catalog for the site: the pinned commit, or the checkout ELY_SHOWCASE names.
import { execFileSync } from "node:child_process";
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { Marked } from "marked";
const REPO = "ZacharyZhang-NY/Ely-GPUI-Showcases";
const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Showcases";
const site = fileURLToPath(new URL("..", import.meta.url));
const pub = join(site, "public", "showcase");
const out = join(site, "src", "showcase.json");
@@ -15,12 +15,14 @@ const stamp = join(pub, ".commit");
/** The catalog at `commit`, unpacked with its validator's packages. */
async function fetchCatalog(commit) {
const work = mkdtempSync(join(tmpdir(), "ely-showcase-"));
const url = `https://codeload.github.com/${REPO}/tar.gz/${commit}`;
const url = `${REPO}/archive/${commit}.tar.gz`;
const res = await fetch(url);
if (!res.ok) throw new Error(`showcase: ${url} answered ${res.status}`);
writeFileSync(join(work, "catalog.tar.gz"), Buffer.from(await res.arrayBuffer()));
execFileSync("tar", ["-xzf", "catalog.tar.gz"], { cwd: work });
const root = join(work, `${REPO.split("/")[1]}-${commit}`);
const [top] = readdirSync(work, { withFileTypes: true }).filter((e) => e.isDirectory());
if (!top) throw new Error(`showcase: ${url} held no folder`);
const root = join(work, top.name);
const pnpm = process.env.npm_execpath;
if (!pnpm) throw new Error("showcase: run through pnpm, which installs the catalog's validator");
execFileSync(process.execPath, [pnpm, "install", "--frozen-lockfile", "--ignore-scripts", "--silent"], { cwd: root, stdio: "inherit" });
+1 -1
View File
@@ -1 +1 @@
8b5c36ae18fb3b80bdb7b4c63fef8e9042b14779
697383430c90955ecf9cdd314260b326ac29b773
+2 -2
View File
@@ -36,8 +36,8 @@ function Header() {
<button className="tool" aria-label={dark ? "Light mode" : "Dark mode"} onClick={() => setMode(dark ? "light" : "dark")}>
<Icon name={dark ? "Sun" : "Moon"} />
</button>
<a className="tool" href={REPO} rel="noopener" aria-label="Ely on GitHub">
<Icon name="GitHub" />
<a className="tool" href={REPO} rel="noopener" aria-label="Ely on Gitea">
<Icon name="Gitea" />
</a>
</div>
</header>
+1 -1
View File
@@ -26,7 +26,7 @@ export interface Catalog {
export type Sort = "newest" | "stars";
export const SUBMIT = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Showcases#submit-an-app";
export const SUBMIT = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Showcases#submit-an-app";
/** Newest first, then most stars; or most stars, then newest. */
export function sorted(apps: App[], sort: Sort): App[] {
+1 -1
View File
@@ -37,6 +37,6 @@ export function search(query: string): Chapter[] {
});
}
export const REPO = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Components";
export const REPO = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components";
export const pad = (n: number) => String(n).padStart(2, "0");
+2 -2
View File
@@ -7,7 +7,7 @@ Ely runs beside Longbridge's [GPUI Kit](https://gpui-kit.com) in one app and one
```toml
[dependencies]
gpui-kit = "0.7"
ely-gpui-component = { git = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Components" }
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components" }
```
Kit brings GPUI and puts it at its root, so the app writes `use gpui_kit::*` and lists no `gpui` line of its own. Ely follows Kit's default GPUI.
@@ -43,4 +43,4 @@ In debug builds Kit's `init` installs Kit's inspector. Call `ely_gpui_component:
## A whole app
[`compat/kit/examples/start.rs`](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/compat/kit/examples/start.rs) puts Ely's heading and button beside Kit's field and dialog, and one button turns both themes. From a clone, run it with `cargo run --manifest-path compat/kit/Cargo.toml --example start`. The crate's tests hold each claim on this page.
[`compat/kit/examples/start.rs`](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/compat/kit/examples/start.rs) puts Ely's heading and button beside Kit's field and dialog, and one button turns both themes. From a clone, run it with `cargo run --manifest-path compat/kit/Cargo.toml --example start`. The crate's tests hold each claim on this page.
+1 -1
View File
@@ -48,7 +48,7 @@ Use `Icon::from_path("app-icons/mark.svg")` to draw one of those SVG assets with
Compatible single-color SVGs can come from [Lucide](https://lucide.dev/), [Hugeicons](https://github.com/hugeicons/hugeicons), [Phosphor](https://github.com/phosphor-icons/core), [Remix Icon](https://github.com/Remix-Design/RemixIcon), or [Tabler](https://github.com/tabler/tabler-icons). The app supplies its chosen files and preserves their licenses; Ely does not download or register those catalogs.
The example below includes its asset source. Copy [`examples/assets/mark.svg`](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/examples/assets/mark.svg) with it, or supply your own SVG.
The example below includes its asset source. Copy [`examples/assets/mark.svg`](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/examples/assets/mark.svg) with it, or supply your own SVG.
## A window of icons
+1 -1
View File
@@ -12,7 +12,7 @@ Ely is not on crates.io. Depend on it by git, with GPUI at the snapshot Ely pins
```toml
[dependencies]
ely-gpui-component = { git = "https://github.com/ZacharyZhang-NY/Ely-GPUI-Components" }
ely-gpui-component = { git = "https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components" }
gpui = { package = "gpui-pre", version = "=0.3.8" }
gpui_platform = { package = "gpui-pre-platform", version = "=0.3.8", features = ["font-kit"] }
```
+4 -4
View File
@@ -25,7 +25,7 @@ GPUI's `TestAppContext` serves no assets, so `ely_gpui_component::init` returns
## Tests to read
- [Layers](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/src/primitives/tests.rs): what is raised inside a raise lies over it, and keeps its state.
- [Feedback](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/src/feedback/tests/mod.rs): toasts and alerts, and focus handed to the root when a focused toast leaves.
- [Tables](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/src/tables/tests/mod.rs): clicks, double presses, Tab across a grid.
- [Internationalization](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/src/i18n/tests/mod.rs): catalogs, locales and a mirrored row.
- [Layers](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/src/primitives/tests.rs): what is raised inside a raise lies over it, and keeps its state.
- [Feedback](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/src/feedback/tests/mod.rs): toasts and alerts, and focus handed to the root when a focused toast leaves.
- [Tables](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/src/tables/tests/mod.rs): clicks, double presses, Tab across a grid.
- [Internationalization](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/src/i18n/tests/mod.rs): catalogs, locales and a mirrored row.
+1 -1
View File
@@ -13,7 +13,7 @@ RUSTC_BOOTSTRAP=1 cargo check --lib --target wasm32-unknown-unknown
## Start an app in the browser
The gallery's [web entry](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/examples/gallery/web.rs) shows the steps:
The gallery's [web entry](https://git.zacharyzhang.com/ZacharyZhang-NY/Ely-GPUI-Components/src/branch/main/examples/gallery/web.rs) shows the steps:
| Step | Why |
| --- | --- |
+5 -5
View File
@@ -9,14 +9,14 @@ import VolumeCross from "reicon/icons/VolumeCross";
const set = { ArrowRightUp, Maximize, Minimize, Moon, Refresh, Sound, Sun, VolumeCross };
// simple-icons' GitHub mark (CC0), padded to sit like Reicon's.
const GITHUB =
'<svg viewBox="-3 -3 30 30" width="24" height="24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>';
// simple-icons' Gitea mark (CC0), padded to sit like Reicon's.
const GITEA =
'<svg viewBox="-3 -3 30 30" width="24" height="24" fill="currentColor"><path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/></svg>';
export type IconName = keyof typeof set | "GitHub";
export type IconName = keyof typeof set | "Gitea";
/** An 18px glyph at 1.5px in a 24px box. */
export function Icon({ name }: { name: IconName }) {
const svg = name === "GitHub" ? GITHUB : set[name].toSvg({ size: 24 });
const svg = name === "Gitea" ? GITEA : set[name].toSvg({ size: 24 });
return <span className="icon" aria-hidden="true" dangerouslySetInnerHTML={{ __html: svg }} />;
}