| 1 | import type { JSX } from "react"; |
| 2 | |
| 3 | /** |
| 4 | * The site's one icon system, ported from codewhale-platform/apps/web-next |
| 5 | * (components/icon.tsx): 24×24 Lucide-style round strokes, the same family |
| 6 | * the GPUI rail draws, inlined as currentColor SVG so every glyph takes the |
| 7 | * surrounding ink in both schemes. Add a glyph here when a caller needs it; |
| 8 | * do not inline a one-off SVG in a component. |
| 9 | */ |
| 10 | const GLYPHS = { |
| 11 | github: ( |
| 12 | <> |
| 13 | <path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4" /> |
| 14 | <path d="M9 18c-4.51 2-5-2-7-2" /> |
| 15 | </> |
| 16 | ), |
| 17 | globe: ( |
| 18 | <> |
| 19 | <circle cx="12" cy="12" r="10" /> |
| 20 | <path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" /> |
| 21 | <path d="M2 12h20" /> |
| 22 | </> |
| 23 | ), |
| 24 | monitor: ( |
| 25 | <> |
| 26 | <rect width="20" height="14" x="2" y="3" rx="2" /> |
| 27 | <path d="M8 21h8" /> |
| 28 | <path d="M12 17v4" /> |
| 29 | </> |
| 30 | ), |
| 31 | sun: ( |
| 32 | <> |
| 33 | <circle cx="12" cy="12" r="4" /> |
| 34 | <path d="M12 2v2" /> |
| 35 | <path d="M12 20v2" /> |
| 36 | <path d="m4.93 4.93 1.41 1.41" /> |
| 37 | <path d="m17.66 17.66 1.41 1.41" /> |
| 38 | <path d="M2 12h2" /> |
| 39 | <path d="M20 12h2" /> |
| 40 | <path d="m6.34 17.66-1.41 1.41" /> |
| 41 | <path d="m19.07 4.93-1.41 1.41" /> |
| 42 | </> |
| 43 | ), |
| 44 | moon: <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />, |
| 45 | menu: ( |
| 46 | <> |
| 47 | <path d="M4 6h16" /> |
| 48 | <path d="M4 12h16" /> |
| 49 | <path d="M4 18h16" /> |
| 50 | </> |
| 51 | ), |
| 52 | x: ( |
| 53 | <> |
| 54 | <path d="M18 6 6 18" /> |
| 55 | <path d="m6 6 12 12" /> |
| 56 | </> |
| 57 | ), |
| 58 | "chevron-right": <path d="m9 18 6-6-6-6" />, |
| 59 | "chevron-down": <path d="m6 9 6 6 6-6" />, |
| 60 | "arrow-right": ( |
| 61 | <> |
| 62 | <path d="M5 12h14" /> |
| 63 | <path d="m12 5 7 7-7 7" /> |
| 64 | </> |
| 65 | ), |
| 66 | external: ( |
| 67 | <> |
| 68 | <path d="M15 3h6v6" /> |
| 69 | <path d="M10 14 21 3" /> |
| 70 | <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /> |
| 71 | </> |
| 72 | ), |
| 73 | search: ( |
| 74 | <> |
| 75 | <circle cx="11" cy="11" r="7" /> |
| 76 | <path d="m20 20-3.5-3.5" /> |
| 77 | </> |
| 78 | ), |
| 79 | copy: ( |
| 80 | <> |
| 81 | <rect width="13" height="13" x="8" y="8" rx="2" /> |
| 82 | <path d="M4 16a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2" /> |
| 83 | </> |
| 84 | ), |
| 85 | check: <path d="M20 6 9 17l-5-5" />, |
| 86 | terminal: ( |
| 87 | <> |
| 88 | <path d="m4 17 6-6-6-6" /> |
| 89 | <path d="M12 19h8" /> |
| 90 | </> |
| 91 | ), |
| 92 | package: ( |
| 93 | <> |
| 94 | <path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" /> |
| 95 | <path d="M12 22V12" /> |
| 96 | <path d="m3.3 7 8.7 5 8.7-5" /> |
| 97 | </> |
| 98 | ), |
| 99 | plug: ( |
| 100 | <> |
| 101 | <path d="M12 22v-5" /> |
| 102 | <path d="M9 8V2" /> |
| 103 | <path d="M15 8V2" /> |
| 104 | <path d="M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z" /> |
| 105 | </> |
| 106 | ), |
| 107 | book: ( |
| 108 | <> |
| 109 | <path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20" /> |
| 110 | </> |
| 111 | ), |
| 112 | "git-pull-request": ( |
| 113 | <> |
| 114 | <circle cx="18" cy="18" r="3" /> |
| 115 | <circle cx="6" cy="6" r="3" /> |
| 116 | <path d="M13 6h3a2 2 0 0 1 2 2v7" /> |
| 117 | <path d="M6 9v12" /> |
| 118 | </> |
| 119 | ), |
| 120 | message: <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />, |
| 121 | shield: <path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" />, |
| 122 | cpu: ( |
| 123 | <> |
| 124 | <rect width="16" height="16" x="4" y="4" rx="2" /> |
| 125 | <rect width="6" height="6" x="9" y="9" rx="1" /> |
| 126 | <path d="M15 2v2M15 20v2M2 15h2M2 9h2M20 15h2M20 9h2M9 2v2M9 20v2" /> |
| 127 | </> |
| 128 | ), |
| 129 | repeat: ( |
| 130 | <> |
| 131 | <path d="m17 2 4 4-4 4" /> |
| 132 | <path d="M3 11v-1a4 4 0 0 1 4-4h14" /> |
| 133 | <path d="m7 22-4-4 4-4" /> |
| 134 | <path d="M21 13v1a4 4 0 0 1-4 4H3" /> |
| 135 | </> |
| 136 | ), |
| 137 | layers: ( |
| 138 | <> |
| 139 | <path d="m12 2 10 5-10 5L2 7z" /> |
| 140 | <path d="m2 17 10 5 10-5" /> |
| 141 | <path d="m2 12 10 5 10-5" /> |
| 142 | </> |
| 143 | ), |
| 144 | folder: <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />, |
| 145 | users: ( |
| 146 | <> |
| 147 | <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /> |
| 148 | <circle cx="9" cy="7" r="4" /> |
| 149 | <path d="M22 21v-2a4 4 0 0 0-3-3.87" /> |
| 150 | <path d="M16 3.13a4 4 0 0 1 0 7.75" /> |
| 151 | </> |
| 152 | ), |
| 153 | key: ( |
| 154 | <> |
| 155 | <circle cx="7.5" cy="15.5" r="5.5" /> |
| 156 | <path d="m21 2-9.6 9.6" /> |
| 157 | <path d="m15.5 7.5 3 3L22 7l-3-3" /> |
| 158 | </> |
| 159 | ), |
| 160 | alert: ( |
| 161 | <> |
| 162 | <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /> |
| 163 | <path d="M12 9v4" /> |
| 164 | <path d="M12 17h.01" /> |
| 165 | </> |
| 166 | ), |
| 167 | info: ( |
| 168 | <> |
| 169 | <circle cx="12" cy="12" r="10" /> |
| 170 | <path d="M12 16v-4" /> |
| 171 | <path d="M12 8h.01" /> |
| 172 | </> |
| 173 | ), |
| 174 | /* The sea's small icons (Kare-style, each always beside a word): |
| 175 | sonar = searching, tide = real progress, shell = a receipt, |
| 176 | kelp = a divider. */ |
| 177 | sonar: ( |
| 178 | <> |
| 179 | <circle cx="5.5" cy="12" r="1.8" /> |
| 180 | <path d="M9.5 8.5a5 5 0 0 1 0 7" /> |
| 181 | <path d="M13 5.5a9.2 9.2 0 0 1 0 13" /> |
| 182 | <path d="M16.5 2.5a13.5 13.5 0 0 1 0 19" /> |
| 183 | </> |
| 184 | ), |
| 185 | tide: ( |
| 186 | <> |
| 187 | <path d="M2 7c1.7-1.6 3.3-1.6 5 0s3.3 1.6 5 0 3.3-1.6 5 0 3.3 1.6 5 0" /> |
| 188 | <path d="M2 12c1.7-1.6 3.3-1.6 5 0s3.3 1.6 5 0 3.3-1.6 5 0 3.3 1.6 5 0" /> |
| 189 | <path d="M2 17c1.7-1.6 3.3-1.6 5 0s3.3 1.6 5 0 3.3-1.6 5 0 3.3 1.6 5 0" /> |
| 190 | </> |
| 191 | ), |
| 192 | shell: ( |
| 193 | <> |
| 194 | <path d="M12 4C7 4 3 7.6 3 12.2c0 1.6.6 3 1.6 4.3L7 20h10l2.4-3.5c1-1.3 1.6-2.7 1.6-4.3C21 7.6 17 4 12 4Z" /> |
| 195 | <path d="M12 20V6" /> |
| 196 | <path d="m9 20-2.4-12" /> |
| 197 | <path d="m15 20 2.4-12" /> |
| 198 | <path d="M9 20v1.5h6V20" /> |
| 199 | </> |
| 200 | ), |
| 201 | kelp: ( |
| 202 | <> |
| 203 | <path d="M12 22c0-4 3-5.5 3-9.5S12 7 12 3" /> |
| 204 | <path d="M12 22c0-3-3.5-4-3.5-7.5 0-2 1.2-3.2 2-4.5" /> |
| 205 | </> |
| 206 | ), |
| 207 | } satisfies Record<string, JSX.Element>; |
| 208 | |
| 209 | export type IconName = keyof typeof GLYPHS; |
| 210 | |
| 211 | export function Icon({ name, className = "icon" }: { name: IconName; className?: string }) { |
| 212 | return ( |
| 213 | <svg |
| 214 | className={className} |
| 215 | width="24" |
| 216 | height="24" |
| 217 | viewBox="0 0 24 24" |
| 218 | fill="none" |
| 219 | stroke="currentColor" |
| 220 | strokeWidth={1.7} |
| 221 | strokeLinecap="round" |
| 222 | strokeLinejoin="round" |
| 223 | aria-hidden="true" |
| 224 | > |
| 225 | {GLYPHS[name]} |
| 226 | </svg> |
| 227 | ); |
| 228 | } |
| 229 |