Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 1 | import { Bot, User } from "lucide-react"; |
| 2 | import { type ReactNode, useState } from "react"; | |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 3 | import { useRouteLoaderData } from "react-router"; |
| 4 | ||
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 5 | import type { AgentLook } from "@g1t/contracts"; |
| 6 | import { lookFromSeed } from "@g1t/contracts/agent-look"; | |
| 7 | ||
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 8 | import { usercontentFrom } from "../../lib/addresses"; |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 9 | import { AgentFace, type FaceState, faceColorCss } from "../agent-face"; |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 10 | import { Mark } from "../logo"; |
| 11 | ||
| 12 | // shadcn/ui's avatar, as g1t draws one: an uploaded picture, or a letter | |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 13 | // whose colour is stable for a given name; an agent's bot face, with the |
| 14 | // agent marker in its corner. It is one element rather than Radix's | |
| 15 | // root/image/fallback so the server renders the letter at once and | |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 16 | // nothing jumps; an image that fails to load falls back to the letter. |
| 17 | ||
| 18 | const AVATAR_HUES = [82, 200, 262, 28, 330, 160]; | |
| 19 | ||
| 20 | /** | |
| 21 | * g1t itself: its agent, as reviewer, assignee and commit author, and the | |
| 22 | * system, as the author of security updates, the issues it opens and merges | |
| 23 | * from the queue. One name, `g1t`. | |
| 24 | */ | |
| 25 | export function isSystemName(name: string | null | undefined): boolean { | |
| 26 | return name === "g1t"; | |
| 27 | } | |
| 28 | ||
| 29 | /** | |
| 30 | * Where an uploaded avatar is served, from the hash it is stored by: the | |
| 31 | * usercontent origin, or the site's own address (which redirects there) | |
| 32 | * when it is not known. | |
| 33 | */ | |
| 34 | export function avatarUrl(avatar: string, usercontent = ""): string { | |
| 35 | return `${usercontent}/avatars/${avatar}`; | |
| 36 | } | |
| 37 | ||
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 38 | /** What an agent's avatar is drawn from: its chosen face, else its seed's. */ |
| 39 | export type AvatarAgent = { | |
| 40 | look?: AgentLook | null; | |
| 41 | /** What draws the face when there is no look, and times its blink; the name when left out. */ | |
| 42 | seed?: string | null; | |
| 43 | /** What the face is doing (components/agent-face.tsx). */ | |
| 44 | state?: FaceState; | |
| 45 | }; | |
| 46 | ||
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 47 | /** |
| 48 | * An uploaded avatar if there is one, else a letter avatar whose colour is | |
| 49 | * stable for a given name. People are round; a workspace is `square`. An | |
| 50 | * image that fails to load falls back to the letter. | |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 51 | * |
| 52 | * With `agent`, it is an agent's: its uploaded picture, g1t's own mark, or | |
| 53 | * its bot face (components/agent-face.tsx), on a squircle tile so it reads | |
| 54 | * apart from people's round letters at any size, and from 16 px up the | |
| 55 | * agent marker in its corner. It then names itself to a screen reader, | |
| 56 | * "Margo, agent", where a person's avatar is decoration beside their name. | |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 57 | */ |
| 58 | export function Avatar({ | |
| 59 | name, | |
| 60 | size = 20, | |
| 61 | square, | |
| 62 | image, | |
| 63 | system, | |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 64 | agent, |
| 65 | ring, | |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 66 | }: { |
| 67 | name: string; | |
| 68 | size?: number; | |
| 69 | square?: boolean; | |
| 70 | /** The uploaded avatar's hash, as identity returns it. */ | |
| 71 | image?: string | null; | |
| 72 | /** g1t itself (a user of kind `system`), whatever the name. */ | |
| 73 | system?: boolean; | |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 74 | /** An agent's avatar: `true` draws the face its name seeds, an object the look or seed it has. */ |
| 75 | agent?: boolean | AvatarAgent; | |
| 76 | /** The colour behind the avatar, for the agent marker's ring; the page's by default. */ | |
| 77 | ring?: string; | |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 78 | }) { |
| 79 | const [failed, setFailed] = useState<string | null>(null); | |
| 80 | const usercontent = usercontentFrom(useRouteLoaderData("root")); | |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 81 | const g1t = system || isSystemName(name); |
| 82 | if (agent) { | |
| 83 | const own = typeof agent === "object" ? agent : {}; | |
| 84 | const seed = own.seed || name || "agent"; | |
| 85 | const radius = Math.round(size * 0.26); | |
| 86 | const face = g1t ? ( | |
| 87 | <span | |
| 88 | className="inline-flex shrink-0 items-center justify-center bg-[#0b0b0d] text-fg ring-1 ring-line-strong ring-inset scheme-dark" | |
| 89 | style={{ width: size, height: size, borderRadius: radius }} | |
| 90 | > | |
| 91 | <Mark className="size-full" /> | |
| 92 | </span> | |
| 93 | ) : image && failed !== image ? ( | |
| 94 | <img | |
| 95 | src={avatarUrl(image, usercontent)} | |
| 96 | alt="" | |
| 97 | width={size} | |
| 98 | height={size} | |
| 99 | loading="lazy" | |
| 100 | decoding="async" | |
| 101 | onError={() => setFailed(image)} | |
| 102 | className="inline-block shrink-0 bg-raised object-cover" | |
| 103 | style={{ width: size, height: size, borderRadius: radius }} | |
| 104 | /> | |
| 105 | ) : ( | |
| 106 | <AgentTile size={size} radius={radius} color={faceColorCss((own.look ?? lookFromSeed(seed)).color)}> | |
| 107 | <AgentFace look={own.look ?? null} seed={seed} size={size} state={own.state} /> | |
| 108 | </AgentTile> | |
| 109 | ); | |
| 110 | return ( | |
| 111 | <span role="img" aria-label={`${name}, agent`} className="relative inline-flex shrink-0 align-middle"> | |
| 112 | {face} | |
| 113 | {size >= 16 && <AgentMarker size={size} ring={ring} />} | |
| 114 | </span> | |
| 115 | ); | |
| 116 | } | |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 117 | // g1t itself wears its own mark: the pixel 1 on a dark square. |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 118 | if (g1t) { |
| The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after. | 119 | return ( |
| 120 | <span | |
| 121 | aria-hidden="true" | |
| 122 | className="inline-flex shrink-0 items-center justify-center bg-[#0b0b0d] text-fg ring-1 ring-line-strong ring-inset scheme-dark" | |
| 123 | style={{ width: size, height: size, borderRadius: size * 0.24 }} | |
| 124 | > | |
| 125 | <Mark className="size-full" /> | |
| 126 | </span> | |
| 127 | ); | |
| 128 | } | |
| 129 | // ghost stands in for deleted accounts: a plain silhouette, as for | |
| 130 | // anyone on a commit who has no account. | |
| 131 | if (name === "ghost" && !image) { | |
| 132 | return ( | |
| 133 | <span | |
| 134 | aria-hidden="true" | |
| 135 | className="inline-flex shrink-0 items-center justify-center rounded-full bg-line text-faint" | |
| 136 | style={{ width: size, height: size }} | |
| 137 | > | |
| 138 | <User size={Math.round(size * 0.62)} strokeWidth={2.25} /> | |
| 139 | </span> | |
| 140 | ); | |
| 141 | } | |
| 142 | if (image && failed !== image) { | |
| 143 | return ( | |
| 144 | <img | |
| 145 | src={avatarUrl(image, usercontent)} | |
| 146 | alt="" | |
| 147 | aria-hidden="true" | |
| 148 | width={size} | |
| 149 | height={size} | |
| 150 | loading="lazy" | |
| 151 | decoding="async" | |
| 152 | onError={() => setFailed(image)} | |
| 153 | className="inline-block shrink-0 bg-raised object-cover" | |
| 154 | style={{ width: size, height: size, borderRadius: square ? size * 0.24 : size }} | |
| 155 | /> | |
| 156 | ); | |
| 157 | } | |
| 158 | let hash = 0; | |
| 159 | for (const char of name) hash = (hash * 31 + char.charCodeAt(0)) | 0; | |
| 160 | const hue = AVATAR_HUES[Math.abs(hash) % AVATAR_HUES.length]; | |
| 161 | return ( | |
| 162 | <span | |
| 163 | aria-hidden="true" | |
| 164 | className="inline-flex shrink-0 items-center justify-center font-mono font-semibold uppercase" | |
| 165 | style={{ | |
| 166 | width: size, | |
| 167 | height: size, | |
| 168 | borderRadius: square ? size * 0.24 : size, | |
| 169 | fontSize: size * 0.5, | |
| 170 | background: `oklch(0.4 0.09 ${hue})`, | |
| 171 | color: `oklch(0.93 0.08 ${hue})`, | |
| 172 | }} | |
| 173 | > | |
| 174 | {name[0]} | |
| 175 | </span> | |
| 176 | ); | |
| 177 | } | |
| Agents have faces, and are never mistaken for people. Every agent wears a little bot face drawn from a look it owns, shape, colour, eyes, mouth, antenna, accessory and pattern, chosen in its builder and on its Profile tab with a live preview, Shuffle and a way back to the face its seed gives it; the face blinks on its own time, breathes, narrows its eyes while the agent works, shuts them asleep and bounces when it finishes, all of it still for anyone who asked for less motion. Wherever an agent shows, in chat, in a list, on a mention, on a review or a commit, its avatar carries an agent marker, and the people reading it are told so. In Chat, direct messages are two lists: People, and Agents, which also holds the agents you haven't talked to yet; a conversation with both a person and an agent in it is marked in the list, named in the conversation's header, spelled out by the composer and explained once the first time it opens. Agents keep their look in the agents service, which every service passes along. The chat and agents guides say so, and CONTRIBUTING makes the shared avatar the only way to draw an agent. | 178 | |
| 179 | /** | |
| 180 | * The tile an agent's face sits on: a squircle in a wash of the face's own | |
| 181 | * colour, so a round-headed bot still reads as an agent beside a person's | |
| 182 | * round letter. | |
| 183 | */ | |
| 184 | function AgentTile({ size, radius, color, children }: { size: number; radius: number; color: string; children: ReactNode }) { | |
| 185 | return ( | |
| 186 | <span | |
| 187 | className="inline-flex shrink-0 items-center justify-center overflow-visible" | |
| 188 | style={{ | |
| 189 | width: size, | |
| 190 | height: size, | |
| 191 | borderRadius: radius, | |
| 192 | background: `color-mix(in oklab, ${color} 20%, transparent)`, | |
| 193 | boxShadow: `inset 0 0 0 1px color-mix(in oklab, ${color} 40%, transparent)`, | |
| 194 | }} | |
| 195 | > | |
| 196 | {children} | |
| 197 | </span> | |
| 198 | ); | |
| 199 | } | |
| 200 | ||
| 201 | /** | |
| 202 | * The agent marker: a small bot on an accent disc, ringed in the colour | |
| 203 | * behind it, in the corner of every agent's avatar from 16 px up (under | |
| 204 | * that the squircle tile alone says it). The same mark everywhere, so | |
| 205 | * nobody has to read a name to know they are looking at an agent. | |
| 206 | */ | |
| 207 | export function AgentMarker({ size, ring = "var(--color-bg)", className }: { size: number; ring?: string; className?: string }) { | |
| 208 | const disc = Math.max(9, Math.min(22, Math.round(size * 0.4))); | |
| 209 | const icon = Math.max(6, Math.round(disc * 0.66)); | |
| 210 | const inset = Math.round(disc * 0.28); | |
| 211 | return ( | |
| 212 | <span | |
| 213 | aria-hidden="true" | |
| 214 | className={`absolute flex items-center justify-center rounded-full bg-accent text-bg ${className ?? ""}`} | |
| 215 | style={{ width: disc, height: disc, right: -inset, bottom: -inset, boxShadow: `0 0 0 ${size >= 28 ? 2 : 1.5}px ${ring}` }} | |
| 216 | > | |
| 217 | <Bot size={icon} strokeWidth={2.6} absoluteStrokeWidth={false} /> | |
| 218 | </span> | |
| 219 | ); | |
| 220 | } |