Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 35f88e34e939a041d77ae4d4f5bb86fb1d96959f
parent d61befb94644de5118e0e2645ebf8742949a6db0
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Fri, 25 Sep 2026 21:30:59 -0400

common: BrandMark and Wordmark components (brand S1)

BrandMark draws the inline mark from lib/brand.ts's MARK list — the same
shapes markSvg writes into the icon files — aria-hidden and not focusable,
with colours in style so a slot can be a var() expression. Wordmark splits
through splitWordmark: the lead at 720 in the foreground, the suffix at 380
muted, Archivo at font-stretch 118%, two adjacent inline spans so the link's
name is the title exactly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Acommon/components/BrandMark.tsx | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommon/components/Wordmark.tsx | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 113 insertions(+), 0 deletions(-)

diff --git a/common/components/BrandMark.tsx b/common/components/BrandMark.tsx @@ -0,0 +1,60 @@ +import type { CSSProperties } from "react"; +import { MARK, MARK_VIEWBOX, type MarkTone } from "../lib/brand"; + +// A palette whose slots are any CSS colour — a hex, or a `var()` expression +// such as the export header's `var(--brand-mark, var(--brand))`, which is why +// this is not lib/brand.ts's hex-only IconPalette. +export type BrandMarkPalette = Readonly<Record<MarkTone, string>>; + +// The Found-line mark, inline — drawn from the same MARK shape list as +// markSvg (the icon files), so the two cannot drift. Decorative: the text +// beside it names the link. Colours go through `style`, not a `fill="var()"` +// attribute, because a presentation attribute does not resolve custom +// properties everywhere a style declaration does. Size it with `className` +// (e.g. `size-7`) or `size`. +export function BrandMark({ + palette, + size, + className, + style, +}: { + palette: BrandMarkPalette; + size?: number; + className?: string; + style?: CSSProperties; +}) { + return ( + <svg + viewBox={`0 0 ${MARK_VIEWBOX} ${MARK_VIEWBOX}`} + width={size} + height={size} + aria-hidden="true" + focusable="false" + className={className} + style={style} + data-brand-mark="" + > + {MARK.map((s) => + s.kind === "rect" ? ( + <rect + key={s.part} + x={s.x || undefined} + y={s.y || undefined} + width={s.width} + height={s.height} + rx={s.rx} + data-tone={s.tone} + style={{ fill: palette[s.tone] }} + /> + ) : ( + <polygon + key={s.part} + points={s.points.map(([x, y]) => `${x},${y}`).join(" ")} + data-tone={s.tone} + style={{ fill: palette[s.tone] }} + /> + ), + )} + </svg> + ); +} diff --git a/common/components/Wordmark.tsx b/common/components/Wordmark.tsx @@ -0,0 +1,53 @@ +import { splitWordmark } from "../lib/brand"; + +// The two-weight wordmark: Archivo at `font-stretch: 118%`, the lead (the +// SUBJECT's name — "Jer", "Rekieta", "Archi") heavy in the foreground, the +// suffix light and muted. The split is configured (site.json `wordmarkLead`, +// PROJECT_WORDMARK_LEAD), never guessed; with no usable lead the whole title +// is the lead. +// +// The two spans are adjacent with NO whitespace between them and stay inline, +// so the enclosing link's accessible name is the title exactly ("Jeralyzer", +// not "Jer alyzer"). Do not make this element `flex`: that would blockify the +// spans and the browser would put a space between them in the name. +// +// Size, leading and truncation come from `className`. The face is Archivo +// wherever it is loaded: `--font-grotesk` names it until the themes slice makes +// Archivo the display face everywhere, after which the fallback is the same +// face and the first term can go. +export function Wordmark({ + title, + lead, + className, +}: { + title: string; + lead?: string; + className?: string; +}) { + const parts = splitWordmark(title, lead); + return ( + <span + className={className} + data-wordmark="" + style={{ + fontFamily: "var(--font-grotesk, var(--font-display))", + fontStretch: "118%", + }} + > + <span + data-wordmark-lead="" + style={{ fontWeight: 720, color: "var(--foreground)" }} + > + {parts.lead} + </span> + {parts.suffix ? ( + <span + data-wordmark-suffix="" + style={{ fontWeight: 380, color: "var(--muted-foreground)" }} + > + {parts.suffix} + </span> + ) : null} + </span> + ); +}