* fix(ci): restore browser preview module and onboarding e2e The web bundle imported a browser-preview store that was never added, so production builds and every Playwright signup failed before the shell rendered. Mobile check failed because Expo packages were a patch behind the SDK. Restore the store, type the optional desktop bridge, and walk whichever onboarding step scripted CI actually opens. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(ci): stop the blank web client and the send 500 The core barrel pulled git checkout into the browser, so node:child_process crashed the page before sign-up. Serve that module from a node export instead. Add the missing run tool-call budget columns that threads/send writes. Guard an indexed shell flag for typecheck, and expect the files key the desktop preload already exposes. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(ci): isolate pnpm setup and the takeover membership The Team Computer takeover journey inserted a space member the default-space trigger had already created, so shared Postgres rejected the unique pair. Self-hosted jobs now keep a per-job pnpm home and store, and artifact uploads no longer fail a job that already passed. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(ci): clear typecheck, lint, and unit failures Inbound channel rosters can mark a participant list as authoritative. Answered channel asks stay off the group, and clearing a thread waits until delegated returns land. Lint, unit, and web e2e contracts follow the current shell, composer, and settings. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): align e2e with the shipped shell and onboarding Web E2E still expected older focus buttons, nested project rows, and settings that never opened MCP. Persist the signed-in space, list non-default spaces under Projekte, and keep the quote control on screen. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): open group reply from a revealed hover rail The first user row covered its Reply control until the rail accepted pointer events. The group transcript now reveals that rail, then replies. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): stop the shell render loop and settle computer and mention UI A working bot rewrote preview state on every render, the computer menu never stayed still, and the mention picker did not expose its expanded state or option name. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(ci): stop idle probes hanging and accept a follow-up send Background probes walked every process fd and timed out on the shared runner. Linux now tracks the marker with flock and /proc/locks. A new composer draft can send while an earlier send is still refreshing, and group members stay mentionable. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(adapters): detect background work when flock ids are padded The idle probe compared /proc/locks with an unpadded device key, so majors or minors under 16 never matched. It deleted the live marker and reported idle while the command still held the lock. Probe by taking the lock, and print the cancel key the way the kernel does. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(adapters): stabilize background-work probe tests on self-hosted CI Clear stale marker files before each probe scenario and allow longer polling so launch can acquire flock on busy persistent runners. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): do not block onboarding on spaces list Render the first onboarding step from me and integration setup alone. Resolve the optional skip-to-app redirect after that so Playwright signups are not stuck on the loading shell when spaces.list is slow. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(ci): restore green gates after second main rebase Re-apply biome formatting on Shell/SortableGroup and strict TypeScript assertions in computer-idle tests dropped when skipping the duplicate conflict-resolution commit. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): wait for onboarding bootstrap before E2E proceeds Expose data-onboarding-step on the onboarding shell and have Playwright wait until loading finishes. Ignore ad-hoc screenshot scripts on self-hosted runners so they do not fail lint. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): fall back when onboarding bootstrap stalls Race me/integration setup against a timeout and promote loading to the emoji step after 20s so Playwright is not blocked on a hung RPC. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): render onboarding immediately for E2E signups Start on the emoji step instead of a loading shell that waits on RPC. Bootstrap can still redirect once me and integration setup resolve. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(ci): stabilize web e2e on self-hosted runners Per-job pnpm stores broke node_modules symlinks when setup-node restored cached installs, so Vite could not resolve react during dependency optimization. Keep a runner-scoped store, clear stale Vite caches, and pin Playwright to one worker in CI to reduce onboarding RPC contention. Add Vite resolve aliases for react/react-dom, wait for an interactive onboarding step in E2E helpers, and include the React hook smoke spec from main. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): resolve React aliases through pnpm package layout Root node_modules/react does not exist under pnpm, so Vite aliases pointed at missing paths and broke production builds and the Playwright webServer. Resolve react and react-dom from the web package and map jsx-runtime to the actual entry files. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(core): type the lazy child_process spawn cache Main's lazy require left spawn typed as null after assignment, which broke Typecheck on the rebased branch. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(db): mock git-checkout export path in unit tests Vitest resolves vi.mock against package exports; the .js suffix is not declared for @rakazo/core/git-checkout. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): stabilize E2E after main sidebar and onboarding changes Use first() for duplicate transcript lines, wait for interactive onboarding before model-required assertions, and allow project sidebar to settle after create. Extend the Playwright job timeout so the single-worker suite can finish. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): restore Projekte sidebar and integrations MCP entry Use the default space for Unterhaltungen/Projekte separation instead of the active space header, persist the bootstrapped space in localStorage, wire SettingsOverlay to MCP management, and compare hover tones on inactive rows. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): satisfy biome format on homeSpaceId line Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): align sidebar E2E with nested Projekte shell layout Scope Unterhaltungen assertions to conversation rows only, target project-space Chief actions under .sidebar-projekte, and stabilize hover-tone polling. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix: satisfy lint after main merge (format and unused var) Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): show project-space 1:1 bots in Projekte sidebar Include lone bots in projectSidebarGroups, render bot rows in Projekte, and stabilize E2E for nested sidebar layout and duplicate group entries. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): disambiguate duplicate group sidebar buttons in E2E Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): align spaces and group-chats E2E with Projekte sidebar IA Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): dedupe Projekte sidebar rows and stabilize E2E specs - Deduplicate project space and group-chat entries in projectSidebarGroups - Scope group-chats/spaces E2E clicks to first Projekte match after IA split - Wait for shell ready before mention-picker keyboard test; restore main locators - Fix PrivacySettingsOverlay lint and align biome schema with CLI 2.5.13 Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): restrict project drag handle and stabilize space E2E - Move SortableGroup drag listeners to ProjectDragGrip only so sidebar clicks work - Scope space delete actions to project-space rows; wait for menu in E2E - Switch group settings E2E via direct navigation after unsaved draft check - Merge main (DataTrustPanel) and fix Shell import order for CI lint Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): stabilize message hover Escape assertion in E2E Assert the More menu closes and the hover rail stays visible instead of requiring focus restoration, which is flaky across Chromium builds. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * chore: format apps/api/src/app.ts after main merge Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(web): stabilize team-computer E2E send after bot switch Wait for shell ready and use the Send button instead of Enter after switching bots and closing the computer overlay. The prior run timed out on threads/send with only an apps/api format commit in between. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
470 lines
30 KiB
TypeScript
470 lines
30 KiB
TypeScript
import { ACTIVE_RUN_STATUSES } from "@rakazo/core";
|
|
import { memo, useId, useMemo } from "react";
|
|
import { EvooMascot } from "./evoo-brand.js";
|
|
import { resolveEvooPose } from "./evoo-character/pose-map.js";
|
|
import type { EvooPose } from "./evoo-character/types.js";
|
|
import { cn } from "./lib/utils.js";
|
|
import "./styles.css";
|
|
|
|
const _VIEWBOX = "-15 -15 259 259";
|
|
const _CENTER = 114.2705;
|
|
|
|
export const GROK_SHAPES: Record<string, string> = {
|
|
blob: "M228.541 114.228C228.541 130.133 225.184 145.994 218.738 160.534C212.674 174.217 203.904 186.669 193.065 196.988C155.933 232.34 99.497 238.596 55.5255 212.24C45.097 205.99 35.6851 198.072 27.7451 188.866C19.1926 178.953 12.3686 167.569 7.65781 155.351C2.60712 142.264 0 128.257 0 114.228C0 98.3219 3.35751 82.4611 9.80315 67.9215C15.8672 54.2382 24.6377 41.7862 35.4767 31.4668C72.6081 -3.88483 129.044 -10.1413 173.016 16.2153C183.444 22.4653 192.856 30.3829 200.796 39.5896C209.349 49.5018 216.173 60.8859 220.883 73.1037C225.934 86.1906 228.541 100.198 228.541 114.228Z",
|
|
pebble:
|
|
"M228.11 115.24C228.26 117.02 228.36 118.81 228.42 120.6C228.49 122.4 228.51 124.19 228.48 126C228.46 127.8 228.39 129.6 228.27 131.41C228.16 133.22 228 135.02 227.78 136.83C227.58 138.64 227.32 140.45 227.01 142.24C226.71 144.04 226.34 145.84 225.93 147.62C225.53 149.41 225.07 151.19 224.56 152.95C224.05 154.72 223.49 156.47 222.87 158.21C222.26 159.95 221.59 161.67 220.87 163.38C220.15 165.08 219.38 166.77 218.56 168.43C217.72 170.09 216.85 171.73 215.92 173.34C214.99 174.95 214.01 176.53 212.98 178.08C211.95 179.63 210.87 181.15 209.73 182.63C208.61 184.12 207.43 185.57 206.2 186.98C204.98 188.38 203.71 189.75 202.39 191.08C201.08 192.41 199.72 193.69 198.33 194.93C196.93 196.17 195.49 197.36 194.02 198.51C192.55 199.65 191.04 200.75 189.5 201.8C187.96 202.84 186.38 203.84 184.78 204.78C183.18 205.73 181.54 206.62 179.9 207.46C178.24 208.31 176.56 209.1 174.86 209.84C173.17 210.57 171.45 211.25 169.73 211.89C167.99 212.52 166.25 213.1 164.5 213.63C162.74 214.15 160.98 214.63 159.2 215.06C157.43 215.48 155.65 215.86 153.87 216.18C152.08 216.52 150.3 216.79 148.52 217.03C146.74 217.26 144.95 217.45 143.17 217.59C141.4 217.75 139.62 217.85 137.85 217.91C136.09 217.97 134.32 217.99 132.56 217.98C130.81 217.96 129.06 217.91 127.33 217.82C125.58 217.74 123.85 217.61 122.14 217.46C120.42 217.31 118.71 217.12 117.01 216.91C115.32 216.7 113.63 216.46 111.96 216.18C110.27 215.92 108.61 215.63 106.95 215.31C105.3 215 103.65 214.65 102.02 214.29C100.38 213.92 98.76 213.53 97.15 213.13C95.52 212.72 93.92 212.3 92.32 211.85C90.72 211.4 89.13 210.94 87.54 210.45C85.96 209.96 84.38 209.45 82.8 208.93C81.24 208.4 79.67 207.85 78.11 207.29C76.55 206.72 75 206.13 73.44 205.52C71.89 204.92 70.35 204.29 68.8 203.63C67.26 202.98 65.73 202.3 64.2 201.6C62.66 200.9 61.14 200.16 59.63 199.41C58.11 198.66 56.59 197.88 55.09 197.07C53.58 196.26 52.09 195.42 50.59 194.55C49.1 193.69 47.62 192.78 46.16 191.85C44.7 190.92 43.23 189.95 41.79 188.96C40.35 187.95 38.92 186.92 37.52 185.85C36.11 184.78 34.72 183.67 33.35 182.53C31.99 181.39 30.64 180.2 29.32 178.98C28 177.76 26.7 176.5 25.44 175.2C24.17 173.91 22.93 172.57 21.73 171.2C20.54 169.83 19.37 168.42 18.25 166.97C17.12 165.53 16.04 164.05 14.99 162.52C13.96 161.01 12.95 159.45 12.01 157.86C11.05 156.28 10.15 154.66 9.3 153.01C8.46 151.36 7.65 149.68 6.91 147.97C6.17 146.26 5.48 144.53 4.85 142.77C4.22 141.01 3.64 139.24 3.14 137.44C2.63 135.64 2.18 133.82 1.8 131.99C1.41 130.16 1.09 128.3 0.83 126.46C0.57 124.6 0.38 122.73 0.24 120.86C0.12 119 0.05 117.12 0.05 115.24C0.05 113.36 0.12 111.48 0.24 109.62C0.38 107.75 0.57 105.88 0.82 104.02C1.08 102.18 1.39 100.32 1.78 98.49C2.15 96.65 2.59 94.84 3.09 93.03C3.58 91.23 4.14 89.45 4.75 87.68C5.36 85.92 6.02 84.18 6.74 82.46C7.45 80.74 8.22 79.04 9.03 77.38C9.86 75.71 10.72 74.08 11.63 72.46C12.54 70.85 13.49 69.27 14.49 67.72C15.48 66.17 16.52 64.65 17.58 63.15C18.66 61.67 19.76 60.21 20.91 58.79C22.05 57.37 23.23 55.98 24.43 54.62C25.63 53.26 26.87 51.94 28.13 50.64C29.39 49.35 30.68 48.09 31.99 46.86C33.31 45.63 34.64 44.44 36 43.28C37.35 42.11 38.73 40.98 40.12 39.89C41.52 38.79 42.93 37.72 44.36 36.68C45.79 35.64 47.24 34.64 48.71 33.66C50.17 32.69 51.64 31.75 53.13 30.83C54.62 29.92 56.14 29.03 57.65 28.17C59.17 27.32 60.7 26.49 62.25 25.7C63.79 24.89 65.34 24.12 66.92 23.38C68.48 22.64 70.06 21.93 71.66 21.25C73.24 20.57 74.84 19.92 76.46 19.29C78.07 18.67 79.7 18.08 81.33 17.51C82.97 16.96 84.62 16.43 86.27 15.93C87.93 15.42 89.59 14.96 91.27 14.52C92.94 14.09 94.63 13.69 96.32 13.32C98.02 12.96 99.73 12.62 101.43 12.32C103.15 12.02 104.86 11.76 106.59 11.54C108.31 11.31 110.05 11.12 111.78 10.98C113.52 10.82 115.27 10.71 117.01 10.64C118.76 10.58 120.51 10.55 122.26 10.56C124.01 10.57 125.76 10.63 127.52 10.72C129.27 10.82 131.02 10.97 132.77 11.15C134.51 11.33 136.26 11.57 138.01 11.83C139.74 12.1 141.48 12.43 143.2 12.78C144.93 13.15 146.64 13.56 148.35 14.01C150.05 14.46 151.75 14.96 153.42 15.49C155.11 16.04 156.77 16.63 158.43 17.26C160.07 17.89 161.71 18.56 163.32 19.28C164.94 19.99 166.54 20.75 168.11 21.55C169.68 22.36 171.24 23.21 172.76 24.09C174.29 24.98 175.8 25.9 177.27 26.85C178.75 27.82 180.2 28.82 181.62 29.86C183.06 30.89 184.46 31.97 185.82 33.08C187.19 34.18 188.53 35.33 189.84 36.5C191.15 37.67 192.43 38.88 193.67 40.11C194.92 41.35 196.14 42.62 197.32 43.91C198.51 45.21 199.65 46.53 200.78 47.87C201.9 49.22 202.98 50.59 204.04 51.99C205.09 53.38 206.12 54.8 207.1 56.24C208.1 57.68 209.05 59.15 209.98 60.64C210.9 62.12 211.79 63.62 212.65 65.14C213.51 66.67 214.33 68.21 215.12 69.76C215.92 71.33 216.68 72.9 217.4 74.49C218.13 76.08 218.82 77.69 219.48 79.31C220.14 80.93 220.76 82.57 221.35 84.22C221.95 85.87 222.49 87.54 223.02 89.22C223.54 90.9 224.03 92.59 224.48 94.29C224.93 95.99 225.35 97.71 225.72 99.43C226.11 101.16 226.45 102.91 226.76 104.65C227.06 106.4 227.33 108.15 227.55 109.92C227.77 111.69 227.97 113.46 228.11 115.24Z",
|
|
squircle:
|
|
"M228.49 114.27C228.49 123.33 228.47 135.16 228.43 141.46C228.38 147.76 228.32 148.96 228.22 152.06C228.14 155.17 228.03 157.62 227.9 160.07C227.76 162.51 227.62 164.66 227.44 166.73C227.26 168.8 227.07 170.68 226.85 172.5C226.63 174.33 226.39 176.01 226.12 177.65C225.85 179.28 225.57 180.82 225.27 182.31C224.96 183.8 224.62 185.2 224.26 186.56C223.91 187.93 223.54 189.23 223.13 190.49C222.73 191.74 222.31 192.94 221.86 194.11C221.41 195.27 220.93 196.39 220.44 197.48C219.95 198.56 219.43 199.59 218.88 200.61C218.34 201.61 217.76 202.58 217.18 203.52C216.58 204.46 215.96 205.36 215.31 206.23C214.67 207.11 213.99 207.95 213.29 208.76C212.6 209.57 211.87 210.35 211.11 211.11C210.35 211.87 209.57 212.6 208.76 213.29C207.95 213.99 207.11 214.67 206.23 215.31C205.36 215.96 204.46 216.58 203.52 217.18C202.58 217.76 201.61 218.34 200.61 218.88C199.59 219.43 198.56 219.95 197.48 220.44C196.39 220.93 195.27 221.41 194.11 221.86C192.94 222.31 191.74 222.73 190.49 223.13C189.23 223.54 187.93 223.91 186.56 224.26C185.2 224.62 183.8 224.96 182.31 225.27C180.82 225.57 179.28 225.85 177.65 226.12C176.01 226.39 174.33 226.63 172.5 226.85C170.68 227.07 168.8 227.26 166.73 227.44C164.66 227.62 162.51 227.76 160.07 227.9C157.62 228.03 155.17 228.14 152.06 228.22C148.96 228.32 147.76 228.38 141.46 228.43C135.16 228.47 123.33 228.49 114.27 228.49C105.21 228.49 93.39 228.47 87.08 228.43C80.78 228.38 79.58 228.32 76.48 228.22C73.38 228.14 70.92 228.03 68.48 227.9C66.03 227.76 63.9 227.62 61.81 227.44C59.74 227.26 57.87 227.07 56.04 226.85C54.21 226.63 52.53 226.39 50.89 226.12C49.26 225.85 47.72 225.57 46.24 225.27C44.75 224.96 43.34 224.62 41.98 224.26C40.61 223.91 39.31 223.54 38.06 223.13C36.8 222.73 35.6 222.31 34.43 221.86C33.27 221.41 32.15 220.93 31.07 220.44C29.98 219.95 28.95 219.43 27.93 218.88C26.93 218.34 25.96 217.76 25.02 217.18C24.08 216.58 23.18 215.96 22.31 215.31C21.43 214.67 20.59 213.99 19.78 213.29C18.97 212.6 18.19 211.87 17.43 211.11C16.67 210.35 15.95 209.57 15.25 208.76C14.55 207.95 13.87 207.11 13.23 206.23C12.58 205.36 11.96 204.46 11.37 203.52C10.78 202.58 10.2 201.61 9.66 200.61C9.11 199.59 8.6 198.56 8.1 197.48C7.61 196.39 7.13 195.27 6.69 194.11C6.24 192.94 5.81 191.74 5.41 190.49C5.01 189.23 4.63 187.93 4.28 186.56C3.93 185.2 3.59 183.8 3.28 182.31C2.98 180.82 2.69 179.28 2.42 177.65C2.15 176.01 1.92 174.33 1.69 172.5C1.47 170.68 1.28 168.8 1.1 166.73C0.93 164.66 0.78 162.51 0.64 160.07C0.51 157.62 0.4 155.17 0.32 152.06C0.22 148.96 0.16 147.76 0.11 141.46C0.07 135.16 0.05 123.33 0.05 114.27C0.05 105.21 0.07 93.39 0.11 87.08C0.16 80.78 0.22 79.58 0.32 76.48C0.4 73.38 0.51 70.92 0.64 68.48C0.78 66.03 0.93 63.9 1.1 61.81C1.28 59.74 1.47 57.87 1.69 56.04C1.92 54.21 2.15 52.53 2.42 50.89C2.69 49.26 2.98 47.72 3.28 46.24C3.59 44.75 3.93 43.34 4.28 41.98C4.63 40.61 5.01 39.31 5.41 38.06C5.81 36.8 6.24 35.6 6.69 34.43C7.13 33.27 7.61 32.15 8.1 31.07C8.6 29.98 9.11 28.95 9.66 27.93C10.2 26.93 10.78 25.96 11.37 25.02C11.96 24.08 12.58 23.18 13.23 22.31C13.87 21.43 14.55 20.59 15.25 19.78C15.95 18.97 16.67 18.19 17.43 17.43C18.19 16.67 18.97 15.95 19.78 15.25C20.59 14.55 21.43 13.87 22.31 13.23C23.18 12.58 24.08 11.96 25.02 11.37C25.96 10.78 26.93 10.2 27.93 9.66C28.95 9.11 29.98 8.6 31.07 8.1C32.15 7.61 33.27 7.13 34.43 6.69C35.6 6.24 36.8 5.81 38.06 5.41C39.31 5.01 40.61 4.63 41.98 4.28C43.34 3.93 44.75 3.59 46.24 3.28C47.72 2.98 49.26 2.69 50.89 2.42C52.53 2.15 54.21 1.92 56.04 1.69C57.87 1.47 59.74 1.28 61.81 1.1C63.9 0.93 66.03 0.78 68.48 0.64C70.92 0.51 73.38 0.4 76.48 0.32C79.58 0.22 80.78 0.16 87.08 0.11C93.39 0.07 105.21 0.05 114.27 0.05C123.33 0.05 135.16 0.07 141.46 0.11C147.76 0.16 148.96 0.22 152.06 0.32C155.17 0.4 157.62 0.51 160.07 0.64C162.51 0.78 164.66 0.93 166.73 1.1C168.8 1.28 170.68 1.47 172.5 1.69C174.33 1.92 176.01 2.15 177.65 2.42C179.28 2.69 180.82 2.98 182.31 3.28C183.8 3.59 185.2 3.93 186.56 4.28C187.93 4.63 189.23 5.01 190.49 5.41C191.74 5.81 192.94 6.24 194.11 6.69C195.27 7.13 196.39 7.61 197.48 8.1C198.56 8.6 199.59 9.11 200.61 9.66C201.61 10.2 202.58 10.78 203.52 11.37C204.46 11.96 205.36 12.58 206.23 13.23C207.11 13.87 207.95 14.55 208.76 15.25C209.57 15.95 210.35 16.67 211.11 17.43C211.87 18.19 212.6 18.97 213.29 19.78C213.99 20.59 214.67 21.43 215.31 22.31C215.96 23.18 216.58 24.08 217.18 25.02C217.76 25.96 218.34 26.93 218.88 27.93C219.43 28.95 219.95 29.98 220.44 31.07C220.93 32.15 221.41 33.27 221.86 34.43C222.31 35.6 222.73 36.8 223.13 38.06C223.54 39.31 223.91 40.61 224.26 41.98C224.62 43.34 224.96 44.75 225.27 46.24C225.57 47.72 225.85 49.26 226.12 50.89C226.39 52.53 226.63 54.21 226.85 56.04C227.07 57.87 227.26 59.74 227.44 61.81C227.62 63.9 227.76 66.03 227.9 68.48C228.03 70.92 228.14 73.38 228.22 76.48C228.32 79.58 228.38 80.78 228.43 87.08C228.47 93.39 228.49 105.21 228.49 114.27Z",
|
|
tablet:
|
|
"M74.27 40.27L154.27 40.27C195.14 40.27 228.27 73.4 228.27 114.27C228.27 155.14 195.14 188.27 154.27 188.27L74.27 188.27C33.4 188.27 0.27 155.14 0.27 114.27C0.27 73.4 33.4 40.27 74.27 40.27Z",
|
|
wedge:
|
|
"M77.26 42.06Q114.27 -22.05 151.28 42.06L216.15 154.43Q253.17 218.53 179.14 218.53L49.4 218.53Q-24.62 218.53 12.39 154.43Z",
|
|
hex: "M217.73 153.04Q217.73 174 199.58 184.48L132.42 223.25Q114.27 233.73 96.12 223.25L28.96 184.48Q10.81 174 10.81 153.04L10.81 75.5Q10.81 54.54 28.96 44.06L96.12 5.29Q114.27 -5.19 132.42 5.29L199.58 44.06Q217.73 54.54 217.73 75.5Z",
|
|
cloud:
|
|
"M221.98 112.32C222.74 113.71 223.45 115.15 224.08 116.59C224.71 118.05 225.28 119.52 225.79 121.02C226.29 122.51 226.72 124.03 227.08 125.56C227.44 127.08 227.73 128.62 227.96 130.17C228.18 131.72 228.33 133.28 228.41 134.83C228.5 136.38 228.51 137.94 228.46 139.5C228.41 141.05 228.29 142.6 228.1 144.14C227.91 145.69 227.65 147.22 227.32 148.73C227 150.25 226.61 151.76 226.15 153.23C225.7 154.72 225.17 156.18 224.59 157.61C224 159.04 223.36 160.46 222.65 161.83C221.94 163.21 221.17 164.56 220.34 165.87C219.51 167.17 218.62 168.45 217.69 169.68C216.74 170.91 215.74 172.11 214.7 173.26C213.64 174.41 212.54 175.51 211.4 176.56C210.25 177.62 209.05 178.62 207.81 179.57C206.57 180.52 205.29 181.42 203.96 182.26C202.63 183.09 201.27 183.88 199.87 184.59C198.47 185.31 197.03 185.97 195.56 186.56C194.1 187.16 192.6 187.68 191.08 188.15C189.56 188.61 188.01 189 186.44 189.32C184.86 189.66 183.27 189.91 181.67 190.09C180.06 190.27 178.44 190.38 176.81 190.41C175.18 190.44 173.53 190.4 171.89 190.27C170.24 190.15 168.58 189.95 166.93 189.68C165.28 189.39 163.49 188.79 161.98 188.58C160.48 188.38 159 188.07 157.89 188.47C156.78 188.86 156.18 190.11 155.28 190.91C154.4 191.69 153.48 192.46 152.53 193.19C151.59 193.93 150.62 194.64 149.63 195.33C148.65 196.01 147.63 196.67 146.6 197.29C145.56 197.92 144.51 198.51 143.43 199.08C142.37 199.63 141.28 200.17 140.16 200.67C139.06 201.17 137.94 201.63 136.79 202.07C135.66 202.5 134.5 202.9 133.34 203.27C132.18 203.64 131 203.97 129.81 204.26C128.62 204.55 127.42 204.82 126.22 205.03C125.02 205.26 123.81 205.44 122.59 205.59C121.37 205.73 120.15 205.85 118.93 205.93C117.7 206 116.48 206.04 115.25 206.04C114.02 206.04 112.8 206 111.57 205.93C110.35 205.85 109.13 205.73 107.91 205.59C106.7 205.44 105.48 205.26 104.28 205.03C103.07 204.82 101.87 204.55 100.68 204.26C99.5 203.97 98.32 203.64 97.16 203.27C96 202.9 94.84 202.5 93.7 202.07C92.56 201.63 91.44 201.17 90.33 200.67C89.22 200.17 88.13 199.63 87.06 199.08C85.99 198.51 84.94 197.92 83.9 197.29C82.87 196.67 81.86 196.01 80.87 195.33C79.88 194.64 78.91 193.93 77.97 193.19C77.02 192.46 76.21 191.5 75.21 190.91C74.21 190.3 73.34 189.57 71.98 189.58C70.62 189.59 68.7 190.57 67.06 190.96C65.41 191.35 63.75 191.65 62.09 191.87C60.44 192.1 58.77 192.24 57.12 192.32C55.47 192.39 53.82 192.39 52.18 192.31C50.55 192.23 48.92 192.09 47.31 191.86C45.7 191.65 44.1 191.35 42.53 190.99C40.95 190.63 39.39 190.2 37.86 189.7C36.33 189.21 34.83 188.65 33.35 188.03C31.88 187.4 30.43 186.71 29.03 185.96C27.62 185.2 26.24 184.39 24.92 183.54C23.59 182.67 22.29 181.74 21.04 180.76C19.79 179.79 18.59 178.75 17.43 177.68C16.28 176.6 15.16 175.47 14.11 174.3C13.06 173.13 12.04 171.91 11.09 170.65C10.15 169.39 9.25 168.09 8.41 166.75C7.58 165.43 6.8 164.05 6.08 162.64C5.36 161.25 4.7 159.81 4.1 158.36C3.51 156.9 2.98 155.41 2.51 153.91C2.04 152.4 1.64 150.88 1.3 149.34C0.97 147.8 0.7 146.24 0.5 144.68C0.3 143.12 0.17 141.54 0.1 139.97C0.03 138.38 0.03 136.8 0.11 135.22C0.18 133.64 0.33 132.06 0.53 130.49C0.74 128.91 1.02 127.35 1.36 125.8C1.71 124.25 2.12 122.71 2.61 121.18C3.09 119.66 3.64 118.16 4.26 116.68C4.87 115.2 5.56 113.74 6.3 112.32C7.05 110.89 7.86 109.5 8.74 108.13C9.61 106.77 10.56 105.45 11.55 104.16C12.55 102.87 13.61 101.62 14.73 100.42C15.86 99.23 17.04 98.06 18.27 96.96C19.51 95.86 20.8 94.79 22.14 93.8C23.49 92.8 24.89 91.86 26.34 90.98C27.8 90.09 30.02 89.5 30.85 88.52C31.68 87.53 31.25 86.24 31.33 85.05C31.4 83.86 31.28 82.59 31.31 81.35C31.35 80.12 31.42 78.88 31.54 77.64C31.64 76.4 31.79 75.16 31.98 73.93C32.17 72.69 32.39 71.46 32.66 70.24C32.92 69.01 33.22 67.79 33.58 66.58C33.92 65.36 34.3 64.16 34.72 62.97C35.14 61.78 35.59 60.59 36.08 59.43C36.58 58.25 37.11 57.1 37.69 55.96C38.25 54.83 38.86 53.7 39.5 52.6C40.14 51.5 40.82 50.41 41.52 49.35C42.24 48.3 42.99 47.25 43.76 46.24C44.54 45.22 45.35 44.22 46.19 43.26C47.03 42.29 47.91 41.35 48.81 40.45C49.71 39.53 50.64 38.65 51.6 37.8C52.56 36.94 53.55 36.12 54.56 35.33C55.57 34.54 56.61 33.79 57.67 33.06C58.72 32.33 59.81 31.65 60.91 31C62.01 30.33 63.14 29.72 64.28 29.13C65.41 28.56 66.57 28.01 67.74 27.49C68.92 26.98 70.11 26.52 71.31 26.09C72.51 25.66 73.73 25.26 74.95 24.91C76.17 24.54 77.41 24.23 78.65 23.96C79.89 23.68 81.14 23.44 82.39 23.25C83.64 23.05 84.9 22.88 86.16 22.77C87.41 22.65 88.68 22.57 89.92 22.53C91.18 22.49 92.44 22.49 93.69 22.53C94.94 22.57 96.19 22.65 97.43 22.77C98.67 22.88 99.91 23.03 101.14 23.23C102.36 23.42 103.58 23.65 104.78 23.91C105.99 24.17 107.18 24.48 108.37 24.81C109.54 25.14 110.71 25.51 111.85 25.92C113 26.32 114.14 26.76 115.25 27.22C116.36 27.69 117.45 28.2 118.54 28.72C119.61 29.25 120.67 29.81 121.7 30.39C122.73 30.98 123.74 31.59 124.73 32.24C125.71 32.87 126.68 33.54 127.62 34.23C128.55 34.91 129.44 35.75 130.36 36.36C131.28 36.96 132.09 37.8 133.12 37.85C134.17 37.89 135.43 36.99 136.6 36.63C137.77 36.26 138.96 35.93 140.16 35.64C141.36 35.36 142.58 35.12 143.8 34.91C145.02 34.72 146.26 34.56 147.5 34.44C148.74 34.33 149.99 34.26 151.25 34.23C152.5 34.21 153.75 34.22 155.01 34.29C156.26 34.35 157.52 34.46 158.77 34.61C160.02 34.77 161.27 34.96 162.5 35.2C163.74 35.45 164.98 35.74 166.2 36.07C167.42 36.41 168.63 36.78 169.82 37.21C171.02 37.63 172.2 38.08 173.37 38.59C174.54 39.1 175.69 39.65 176.81 40.24C177.93 40.83 179.05 41.46 180.13 42.14C181.21 42.8 182.27 43.51 183.3 44.26C184.34 45.02 185.34 45.81 186.32 46.63C187.3 47.45 188.24 48.31 189.15 49.19C190.07 50.09 190.96 51.02 191.8 51.97C192.65 52.92 193.47 53.92 194.24 54.93C195.01 55.95 195.75 56.99 196.45 58.06C197.16 59.13 197.81 60.23 198.43 61.34C199.05 62.46 199.64 63.6 200.17 64.76C200.71 65.92 201.21 67.1 201.66 68.29C202.11 69.48 202.52 70.7 202.88 71.92C203.25 73.14 203.56 74.38 203.83 75.62C204.11 76.87 204.34 78.13 204.52 79.39C204.7 80.65 204.84 81.91 204.93 83.18C205.02 84.45 205.06 85.72 205.06 86.98C205.06 88.25 204.81 89.57 204.93 90.79C205.03 92.01 204.94 93.22 205.73 94.32C206.53 95.42 208.44 96.29 209.71 97.36C210.98 98.43 212.19 99.55 213.33 100.71C214.48 101.87 215.57 103.09 216.59 104.34C217.62 105.59 218.58 106.89 219.48 108.23C220.38 109.56 221.21 110.92 221.98 112.32Z",
|
|
teardrop:
|
|
"M125.97 7.2Q114.27 -7.28 102.57 7.2L43.49 80.31C13.46 117.46 17.28 171.51 52.23 204.08C87.17 236.65 141.37 236.65 176.32 204.08C211.26 171.51 215.08 117.46 185.05 80.31Z",
|
|
};
|
|
|
|
export const SHIPPED_SHAPE_KEYS = [
|
|
"hex",
|
|
"wedge",
|
|
"squircle",
|
|
"tablet",
|
|
"pebble",
|
|
"blob",
|
|
"teardrop",
|
|
"cloud",
|
|
] as const;
|
|
|
|
export interface GrokColorDef {
|
|
id: string;
|
|
name: string;
|
|
light: string;
|
|
dark: string;
|
|
eyeColor: string;
|
|
hex: string;
|
|
}
|
|
|
|
export const GROK_COLOR_LIST: GrokColorDef[] = [
|
|
{
|
|
id: "white",
|
|
name: "Staff White",
|
|
light: "#FFFFFF",
|
|
dark: "#CBD5E1",
|
|
eyeColor: "#141414",
|
|
hex: "#FFFFFF",
|
|
},
|
|
{
|
|
id: "violet",
|
|
name: "Executive Violet",
|
|
light: "#A97EFE",
|
|
dark: "#7C3AED",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#8B5CF6",
|
|
},
|
|
{
|
|
id: "green",
|
|
name: "Emerald",
|
|
light: "#00C972",
|
|
dark: "#059669",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#10B981",
|
|
},
|
|
{
|
|
id: "orange",
|
|
name: "Forge Orange",
|
|
light: "#FF781C",
|
|
dark: "#EA580C",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#F97316",
|
|
},
|
|
{
|
|
id: "cyan",
|
|
name: "Cyber Cyan",
|
|
light: "#1CC3B0",
|
|
dark: "#0284C7",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#06B6D4",
|
|
},
|
|
{
|
|
id: "blue",
|
|
name: "Cobalt Blue",
|
|
light: "#2A92FE",
|
|
dark: "#1D4ED8",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#3B82F6",
|
|
},
|
|
{
|
|
id: "yellow",
|
|
name: "Amber Gold",
|
|
light: "#FFAF38",
|
|
dark: "#D97706",
|
|
eyeColor: "#141414",
|
|
hex: "#EAB308",
|
|
},
|
|
{
|
|
id: "brown",
|
|
name: "Caramel Bronze",
|
|
light: "#A27952",
|
|
dark: "#78350F",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#8D6E63",
|
|
},
|
|
{
|
|
id: "red",
|
|
name: "Crimson Red",
|
|
light: "#FF3E51",
|
|
dark: "#BE123C",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#EF4444",
|
|
},
|
|
{
|
|
id: "magenta",
|
|
name: "Neon Pink",
|
|
light: "#FF5EB1",
|
|
dark: "#BE185D",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#EC4899",
|
|
},
|
|
{
|
|
id: "gray",
|
|
name: "Slate Silver",
|
|
light: "#94A3B8",
|
|
dark: "#475569",
|
|
eyeColor: "#FFFFFF",
|
|
hex: "#64748B",
|
|
},
|
|
];
|
|
|
|
export const GROK_BOT_COLORS = GROK_COLOR_LIST.map((c) => c.hex);
|
|
|
|
/** Shared identity color for Avatar Studio reset/fallback (Executive Violet). */
|
|
export const DEFAULT_GROK_BOT_COLOR = GROK_COLOR_LIST.find((color) => color.id === "violet")!.hex;
|
|
|
|
export const GROK_MASCOT_SHAPES = SHIPPED_SHAPE_KEYS.map(
|
|
(k) => GROK_SHAPES[k] ?? FALLBACK_SHAPE_PATH,
|
|
);
|
|
|
|
function shippedHash(value: string): number {
|
|
let hash = 2166136261;
|
|
for (let index = 0; index < value.length; index += 1) {
|
|
hash = Math.imul(hash ^ value.charCodeAt(index), 16777619);
|
|
}
|
|
return hash >>> 0;
|
|
}
|
|
|
|
function shippedRandom(seed: number): () => number {
|
|
let value = seed >>> 0;
|
|
return () => {
|
|
value = (value + 1831565813) | 0;
|
|
let next = Math.imul(value ^ (value >>> 15), 1 | value);
|
|
next = (next + Math.imul(next ^ (next >>> 7), 61 | next)) ^ next;
|
|
return ((next ^ (next >>> 14)) >>> 0) / 4294967296;
|
|
};
|
|
}
|
|
|
|
export function resolvePersonaColorDef(
|
|
identity: string,
|
|
explicitColor?: string | null,
|
|
): GrokColorDef {
|
|
if (explicitColor) {
|
|
const clean = explicitColor.toLowerCase();
|
|
const foundById = GROK_COLOR_LIST.find((c) => c.id === clean || c.name.toLowerCase() === clean);
|
|
if (foundById) return foundById;
|
|
const foundByHex = GROK_COLOR_LIST.find((c) => c.hex.toLowerCase() === clean);
|
|
if (foundByHex) return foundByHex;
|
|
// If custom hex, synthesize gradient
|
|
if (/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(explicitColor)) {
|
|
const isBright = isColorBright(explicitColor);
|
|
return {
|
|
id: "custom",
|
|
name: "Custom",
|
|
light: explicitColor,
|
|
dark: darkenHex(explicitColor, 20),
|
|
eyeColor: isBright ? "#141414" : "#FFFFFF",
|
|
hex: explicitColor,
|
|
};
|
|
}
|
|
}
|
|
const seed = (shippedHash(identity) ^ Math.imul(1, 2654435769)) >>> 0;
|
|
const index = Math.floor(shippedRandom((seed ^ 2654435769) >>> 0)() * GROK_COLOR_LIST.length);
|
|
return GROK_COLOR_LIST[index % GROK_COLOR_LIST.length] ?? GROK_COLOR_LIST[0]!;
|
|
}
|
|
|
|
const FALLBACK_SHAPE_PATH = GROK_SHAPES.hex ?? "";
|
|
|
|
export function resolvePersonaShape(identity: string, explicitShape?: string | null): string {
|
|
if (explicitShape) {
|
|
const explicit = GROK_SHAPES[explicitShape];
|
|
if (explicit) return explicit;
|
|
}
|
|
let hash = shippedHash(identity);
|
|
hash = Math.imul(hash ^ (hash >>> 16), 73244475);
|
|
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
|
|
const shapeIndex = ((hash ^ (hash >>> 16)) >>> 0) % SHIPPED_SHAPE_KEYS.length;
|
|
const key = SHIPPED_SHAPE_KEYS[shapeIndex] ?? "hex";
|
|
return GROK_SHAPES[key] ?? FALLBACK_SHAPE_PATH;
|
|
}
|
|
|
|
function expandHex(hex: string): string {
|
|
const c = hex.replace("#", "");
|
|
if (c.length === 3) {
|
|
const r = c[0] ?? "0";
|
|
const g = c[1] ?? "0";
|
|
const b = c[2] ?? "0";
|
|
return `${r}${r}${g}${g}${b}${b}`;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
function isColorBright(hex: string): boolean {
|
|
const c = expandHex(hex);
|
|
const r = Number.parseInt(c.substring(0, 2), 16) || 0;
|
|
const g = Number.parseInt(c.substring(2, 4), 16) || 0;
|
|
const b = Number.parseInt(c.substring(4, 6), 16) || 0;
|
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
return brightness > 180;
|
|
}
|
|
|
|
function darkenHex(hex: string, percent: number): string {
|
|
const num = Number.parseInt(expandHex(hex), 16);
|
|
const factor = 1 - percent / 100;
|
|
const r = Math.max(0, Math.floor(((num >> 16) & 255) * factor));
|
|
const g = Math.max(0, Math.floor(((num >> 8) & 255) * factor));
|
|
const b = Math.max(0, Math.floor((num & 255) * factor));
|
|
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
}
|
|
|
|
export function parseBotAvatar(
|
|
rawColor: string,
|
|
_identity?: string,
|
|
): {
|
|
color: string;
|
|
shapeIndex?: number;
|
|
isImage: boolean;
|
|
imageUrl?: string;
|
|
} {
|
|
if (!rawColor) return { color: "#F97316", isImage: false };
|
|
// Only data: image URLs are rendered. Arbitrary http(s)/blob values in `color`
|
|
// must not become <img src> (SSRF / tracking when other members view the bot).
|
|
if (rawColor.startsWith("data:image/")) {
|
|
return { color: "#F97316", isImage: true, imageUrl: rawColor };
|
|
}
|
|
if (rawColor.includes("::shape_")) {
|
|
const parts = rawColor.split("::shape_");
|
|
const rawShapeIdx = parts[1] ?? "0";
|
|
const parsedShapeIdx = /^\d+$/.test(rawShapeIdx) ? Number(rawShapeIdx) : 0;
|
|
const shapeIdx = Number.isSafeInteger(parsedShapeIdx) ? parsedShapeIdx : 0;
|
|
return {
|
|
color: parts[0] || "#F97316",
|
|
shapeIndex: shapeIdx % SHIPPED_SHAPE_KEYS.length,
|
|
isImage: false,
|
|
};
|
|
}
|
|
return { color: rawColor, isImage: false };
|
|
}
|
|
|
|
export interface BotAvatarProps {
|
|
color: string;
|
|
size?: number;
|
|
status?: string;
|
|
identity?: string;
|
|
/** Explicit mascot pose; when omitted, derived from `status`. */
|
|
pose?: EvooPose;
|
|
className?: string;
|
|
variant?: unknown;
|
|
}
|
|
|
|
export const BotAvatar = memo(function BotAvatar({
|
|
color,
|
|
size = 36,
|
|
status,
|
|
identity = "",
|
|
pose,
|
|
className,
|
|
}: BotAvatarProps) {
|
|
const id = useId().replace(/[^a-zA-Z0-9-_]/g, "");
|
|
const isWorking = ACTIVE_RUN_STATUSES.some((s) => s === status);
|
|
const mascotPose = resolveEvooPose({ pose, status, streaming: isWorking });
|
|
const mascotSize = Math.max(20, Math.round(size * 0.82));
|
|
|
|
const parsed = useMemo(() => parseBotAvatar(color, identity), [color, identity]);
|
|
const effectiveId = identity || parsed.color || "agent";
|
|
|
|
const colorDef = useMemo(
|
|
() => resolvePersonaColorDef(effectiveId, parsed.color),
|
|
[effectiveId, parsed.color],
|
|
);
|
|
|
|
const shapePath = useMemo(() => {
|
|
if (parsed.shapeIndex !== undefined) {
|
|
const key = SHIPPED_SHAPE_KEYS[parsed.shapeIndex % SHIPPED_SHAPE_KEYS.length] ?? "hex";
|
|
return GROK_SHAPES[key] ?? FALLBACK_SHAPE_PATH;
|
|
}
|
|
return resolvePersonaShape(effectiveId);
|
|
}, [parsed.shapeIndex, effectiveId]);
|
|
|
|
if (parsed.isImage && parsed.imageUrl) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"rakazo-bot-avatar relative overflow-hidden rounded-full flex items-center justify-center select-none bg-secondary shrink-0 border border-border",
|
|
className,
|
|
)}
|
|
data-working={isWorking}
|
|
style={{
|
|
width: size,
|
|
height: size,
|
|
boxShadow: isWorking
|
|
? "0 0 0 2px #3B82F6, 0 0 10px rgba(59,130,246,0.6)"
|
|
: "0 2px 5px rgba(0,0,0,0.5)",
|
|
}}
|
|
>
|
|
{isWorking ? (
|
|
<svg
|
|
className="rakazo-bot-avatar-ring absolute pointer-events-none"
|
|
style={{
|
|
inset: -4,
|
|
width: size + 8,
|
|
height: size + 8,
|
|
}}
|
|
viewBox="0 0 48 48"
|
|
fill="none"
|
|
aria-hidden="true"
|
|
>
|
|
<circle
|
|
cx="24"
|
|
cy="24"
|
|
r="22"
|
|
stroke="#3B82F6"
|
|
strokeWidth="3.2"
|
|
strokeLinecap="round"
|
|
strokeDasharray="45 80"
|
|
/>
|
|
</svg>
|
|
) : null}
|
|
<img src={parsed.imageUrl} alt="" className="h-full w-full object-cover" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"rakazo-bot-avatar grok-avatar-container relative inline-flex items-center justify-center shrink-0 select-none",
|
|
className,
|
|
)}
|
|
style={{
|
|
width: size,
|
|
height: size,
|
|
}}
|
|
data-working={isWorking}
|
|
>
|
|
<svg
|
|
className="rakazo-bot-avatar-ring absolute pointer-events-none"
|
|
style={{
|
|
inset: -4,
|
|
width: size + 8,
|
|
height: size + 8,
|
|
filter: `drop-shadow(0 0 6px ${colorDef.light}) drop-shadow(0 0 10px #ffffff)`,
|
|
}}
|
|
viewBox="0 0 48 48"
|
|
fill="none"
|
|
aria-hidden="true"
|
|
>
|
|
<circle
|
|
cx="24"
|
|
cy="24"
|
|
r="22"
|
|
stroke={`url(#${id}-ring)`}
|
|
strokeWidth="3.2"
|
|
strokeLinecap="round"
|
|
strokeDasharray="45 80"
|
|
/>
|
|
<circle cx="43" cy="24" r="2.8" fill="#ffffff" />
|
|
<defs>
|
|
<linearGradient id={`${id}-ring`} x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" stopColor="#ffffff" stopOpacity="1" />
|
|
<stop offset="60%" stopColor={colorDef.light} stopOpacity="0.9" />
|
|
<stop offset="100%" stopColor={colorDef.light} stopOpacity="0" />
|
|
</linearGradient>
|
|
</defs>
|
|
</svg>
|
|
<div
|
|
className={cn(
|
|
"relative flex items-center justify-center transition-transform duration-300",
|
|
isWorking
|
|
? "animate-pulse scale-[1.04] motion-reduce:animate-none"
|
|
: "hover:scale-[1.03] motion-reduce:hover:scale-100",
|
|
)}
|
|
style={{
|
|
width: size,
|
|
height: size,
|
|
filter: isWorking
|
|
? `drop-shadow(0 0 8px ${colorDef.light}) drop-shadow(0 0 2px #ffffff)`
|
|
: "drop-shadow(0 2px 4px rgba(0,0,0,0.45))",
|
|
}}
|
|
>
|
|
<svg
|
|
viewBox="-15 -15 259 259"
|
|
width={size}
|
|
height={size}
|
|
aria-hidden="true"
|
|
className="absolute inset-0 overflow-visible"
|
|
>
|
|
<defs>
|
|
<linearGradient id={`evoo-body-${id}`} x1="0" y1="0" x2="1" y2="1">
|
|
<stop offset="0%" stopColor={colorDef.light} />
|
|
<stop offset="100%" stopColor={colorDef.dark} />
|
|
</linearGradient>
|
|
<radialGradient id={`evoo-shine-${id}`} cx="0.3" cy="0.25" r="0.6">
|
|
<stop offset="0%" stopColor="#ffffff" stopOpacity="0.5" />
|
|
<stop offset="100%" stopColor="#ffffff" stopOpacity="0" />
|
|
</radialGradient>
|
|
</defs>
|
|
<path fill={`url(#evoo-body-${id})`} d={shapePath} />
|
|
<path fill={`url(#evoo-shine-${id})`} d={shapePath} opacity="0.85" />
|
|
</svg>
|
|
<EvooMascot
|
|
pose={mascotPose}
|
|
size={mascotSize}
|
|
trackPointer="none"
|
|
className="relative z-[1]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|
|
|
|
export function GrokShapePreview({
|
|
shapeIndex: _shapeIndex,
|
|
color,
|
|
selected,
|
|
onClick,
|
|
}: {
|
|
shapeIndex: number;
|
|
color: string;
|
|
selected?: boolean;
|
|
onClick?: () => void;
|
|
}) {
|
|
const colorDef = resolvePersonaColorDef("preview", color);
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
aria-label="EvOo"
|
|
aria-pressed={selected ?? false}
|
|
className={cn(
|
|
"relative flex size-11 items-center justify-center rounded-xl transition-transform hover:scale-105 active:scale-95 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover",
|
|
selected
|
|
? "ring-2 ring-primary ring-offset-2 ring-offset-popover bg-white/10"
|
|
: "hover:bg-white/5",
|
|
)}
|
|
>
|
|
<EvooMascot pose="idle" size={32} trackPointer="none" />
|
|
</button>
|
|
);
|
|
}
|