- multi-link bookmark cards now span 4/2 (matching the system widget) instead of 3/1, so they're not cramped and line up into an even 3-up row alongside it - the link list scrolls internally instead of stretching the card, so widgets in the same row stay equal height regardless of link count - BrandIcon gains a small "generic icon" escape hatch (currently just `globe`, via phosphor) for widgets that don't have a real brand mark - added a `coder` brand icon (Coder/code-server) for the Code Server link, since simple-icons has no official VS Code mark to use Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpxhtQY3CExQdMs4j7MmJe
58 lines
1.7 KiB
Python
58 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Regenerates lib/brand-icons.ts from the `simple-icons` package.
|
|
|
|
Run from the repo root after `pnpm add simple-icons` has installed it:
|
|
|
|
python3 scripts/extract-brand-icons.py
|
|
|
|
Add a new service by adding a "our key" -> "simple-icons slug" entry below.
|
|
Slugs are the filenames under node_modules/simple-icons/icons/ (without the
|
|
.svg extension).
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ICONS = {
|
|
"traefik": "traefikproxy",
|
|
"coolify": "coolify",
|
|
"gitea": "gitea",
|
|
"docker": "docker",
|
|
"immich": "immich",
|
|
"n8n": "n8n",
|
|
"passbolt": "passbolt",
|
|
"umami": "umami",
|
|
"postgresql": "postgresql",
|
|
"redis": "redis",
|
|
"headscale": "tailscale",
|
|
"coder": "coder",
|
|
}
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
ICONS_DIR = ROOT / "node_modules" / "simple-icons" / "icons"
|
|
OUT_PATH = ROOT / "lib" / "brand-icons.ts"
|
|
|
|
HEADER = """// Path data extracted from the `simple-icons` package (CC0) at build time -
|
|
// see scripts/extract-brand-icons.py. Rendered monochrome (currentColor) to
|
|
// stay consistent with the single-accent design rather than a dozen
|
|
// competing brand colors; the shape alone is enough to be recognizable.
|
|
export const BRAND_ICON_PATHS: Record<string, string> = {
|
|
"""
|
|
|
|
|
|
def main() -> None:
|
|
lines = [HEADER]
|
|
for key, slug in ICONS.items():
|
|
svg = (ICONS_DIR / f"{slug}.svg").read_text()
|
|
d_matches = re.findall(r'<path d="([^"]+)"', svg)
|
|
combined = " ".join(d_matches)
|
|
lines.append(f" {json.dumps(key)}: {json.dumps(combined)},\n")
|
|
lines.append("};\n")
|
|
OUT_PATH.write_text("".join(lines))
|
|
print(f"Wrote {OUT_PATH} ({len(ICONS)} icons)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|