pr_01m47d24b0e6n91zwymwxg0vpx/apps/web/app/components/logo.tsx

66 lines2,243 bytesCodeBlame
1/**
2 * g1t's logo: G1T in 5×7 pixel capitals, the 1 in lavender. Each pixel is
3 * its own square, 0.8 of its cell. The icon is the 1 alone. The same
4 * shapes as the favicon and the brand files in .g1t/brand and public/brand.
5 * The product name stays "g1t" in text; only the artwork is capitals.
6 */
7
8const G = [".###.", "#...#", "#....", "#.###", "#...#", "#...#", ".###."];
9const ONE = ["..#..", ".##..", "#.#..", "..#..", "..#..", "..#..", "#####"];
10const T = ["#####", "..#..", "..#..", "..#..", "..#..", "..#..", "..#.."];
11
12type Pixel = { x: number; y: number; one: boolean };
13
14function pixels(rows: string[], dx: number, one: boolean): Pixel[] {
15 return rows.flatMap((row, y) => [...row].flatMap((c, x) => (c === "#" ? [{ x: dx + x, y, one }] : [])));
16}
17
18/** G at 0, the 1 at 6, the T at 10: its bar tucks in over the 1's foot. */
19const WORD = [...pixels(G, 0, false), ...pixels(ONE, 6, true), ...pixels(T, 10, false)];
20const ICON = pixels(ONE, 0, true);
21
22/** Cells of 10 units, squares of 8, centred. */
23function Pixels({ of }: { of: Pixel[] }) {
24 return of.map((p) => (
25 <rect
26 key={`${p.x}.${p.y}`}
27 x={p.x * 10 + 1}
28 y={p.y * 10 + 1}
29 width="8"
30 height="8"
31 fill={p.one ? "var(--g1t-merged)" : "currentColor"}
32 />
33 ));
34}
35
36/**
37 * The icon: the pixel 1, centred in a square. `tight` crops to the ink, for
38 * setting it beside type, where it must stand on the baseline.
39 */
40export function Mark({ className, tight = false }: { className?: string; tight?: boolean }) {
41 return (
42 <svg viewBox={tight ? "1 1 48 68" : "-15 -5 80 80"} className={className} aria-hidden="true">
43 <Pixels of={ICON} />
44 </svg>
45 );
46}
47
48/**
49 * The wordmark as one picture, sized by its font size: a cell is 0.125em,
50 * so the letters stand 0.85em tall on the baseline, about the height of
51 * the type around them.
52 */
53export function Logo({ className = "text-[1.5rem]" }: { className?: string }) {
54 return (
55 <span className={`inline-flex items-baseline leading-none text-fg ${className}`}>
56 <svg
57 viewBox="1 1 148 68"
58 role="img"
59 aria-label="g1t"
60 className="h-[0.85em] w-auto shrink-0 self-baseline"
61 >
62 <Pixels of={WORD} />
63 </svg>
64 </span>
65 );
66}