1import type { ProjectIconColor } from "@t3tools/contracts";
2import { projectIconColorClassName } from "../projectIconColors";
3import { cn } from "~/lib/utils";
4
5const monogramSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
6
7export function ProjectMonogram({
8 text,
9 color,
10 className,
11}: {
12 readonly text: string;
13 readonly color: ProjectIconColor;
14 readonly className?: string | undefined;
15}) {
16 // Wrapped like the emoji and Lucide branches so the monogram sits where an
17 // <img> favicon would. Menu items, buttons and the like pull every bare svg
18 // in with [&_svg]:-mx-0.5 to trim the padding stroke icons carry, and this
19 // tile has no such padding.
20 return (
21 <span
22 aria-hidden="true"
23 className={cn("inline-flex size-4 shrink-0 items-center justify-center", className)}
24 >
25 <svg
26 viewBox="0 0 16 16"
27 className={cn(
28 "size-full overflow-hidden rounded-[25%] font-mono select-none",
29 projectIconColorClassName(color),
30 )}
31 style={{
32 backgroundColor: "color-mix(in srgb, currentColor 14%, transparent)",
33 }}
34 >
35 <text
36 x="8"
37 y="10.8"
38 textAnchor="middle"
39 fill="currentColor"
40 className="font-mono"
41 fontSize="8.25"
42 fontWeight="700"
43 textLength={Array.from(monogramSegmenter.segment(text)).length === 1 ? 6 : 12}
44 lengthAdjust="spacingAndGlyphs"
45 textRendering="geometricPrecision"
46 >
47 {text}
48 </text>
49 </svg>
50 </span>
51 );
52}