From 6c27bf1a03d2d3c716ea1f8e5ad2e524a4ebc9e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Jul 2026 08:46:49 +0000 Subject: [PATCH] Extract ActivityCard model colors to lib/constants/model-colors.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure refactor per the ROADMAP "Model colors outside design system" item — same colors, same match order, no behavior change. --- apps/web/components/app/feed/ActivityCard.tsx | 20 ++++++++---------- apps/web/lib/constants/model-colors.ts | 21 +++++++++++++++++++ docs/CHANGELOG.md | 4 ++++ docs/ROADMAP.md | 3 --- 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 apps/web/lib/constants/model-colors.ts diff --git a/apps/web/components/app/feed/ActivityCard.tsx b/apps/web/components/app/feed/ActivityCard.tsx index 97cb6062..165eae34 100644 --- a/apps/web/components/app/feed/ActivityCard.tsx +++ b/apps/web/components/app/feed/ActivityCard.tsx @@ -13,6 +13,10 @@ export { prettifyModel } from "@straude/shared/models"; import { cn } from "@/lib/utils/cn"; import { formatCurrency, formatTokens } from "@/lib/utils/format"; import { mentionsToMarkdownLinks } from "@/lib/utils/mentions"; +import { + MODEL_COLOR_FALLBACK_PALETTE, + MODEL_COLOR_PATTERNS, +} from "@/lib/constants/model-colors"; import type { Post, ModelBreakdownEntry } from "@/types"; import dynamic from "next/dynamic"; import { useState } from "react"; @@ -166,17 +170,11 @@ function hashString(input: string): number { } function modelColor(name: string): string { - if (/Claude Fable/.test(name)) return "#C2410C"; - if (/Claude Opus/.test(name)) return "#DF561F"; - if (/Claude Sonnet/.test(name)) return "#F08A5D"; - if (/Claude Haiku/.test(name)) return "#F7B267"; - if (/GPT-5/.test(name)) return "#2A9D8F"; - if (/GPT-4o/.test(name)) return "#4C78A8"; - if (/^o3/i.test(name)) return "#3B82F6"; - if (/^o4/i.test(name)) return "#6366F1"; - - const palette = ["#EF4444", "#F59E0B", "#10B981", "#06B6D4", "#8B5CF6", "#EC4899"]; - return palette[hashString(name) % palette.length]!; + for (const [pattern, color] of MODEL_COLOR_PATTERNS) { + if (pattern.test(name)) return color; + } + + return MODEL_COLOR_FALLBACK_PALETTE[hashString(name) % MODEL_COLOR_FALLBACK_PALETTE.length]!; } function ModelUsageBar({ segments }: { segments: ModelUsageSegment[] }) { diff --git a/apps/web/lib/constants/model-colors.ts b/apps/web/lib/constants/model-colors.ts new file mode 100644 index 00000000..a5bc13b1 --- /dev/null +++ b/apps/web/lib/constants/model-colors.ts @@ -0,0 +1,21 @@ +/** Fallback palette for models that don't match a known name pattern. */ +export const MODEL_COLOR_FALLBACK_PALETTE = [ + "#EF4444", + "#F59E0B", + "#10B981", + "#06B6D4", + "#8B5CF6", + "#EC4899", +]; + +/** Ordered [pattern, color] pairs for known model families. First match wins. */ +export const MODEL_COLOR_PATTERNS: [RegExp, string][] = [ + [/Claude Fable/, "#C2410C"], + [/Claude Opus/, "#DF561F"], + [/Claude Sonnet/, "#F08A5D"], + [/Claude Haiku/, "#F7B267"], + [/GPT-5/, "#2A9D8F"], + [/GPT-4o/, "#4C78A8"], + [/^o3/i, "#3B82F6"], + [/^o4/i, "#6366F1"], +]; diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 90e37c14..edfa1f0d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Changed + +- **Extracted `ActivityCard`'s hardcoded model chip colors** into `apps/web/lib/constants/model-colors.ts` (`MODEL_COLOR_PATTERNS`, `MODEL_COLOR_FALLBACK_PALETTE`). No visual change — same colors, same matching order — just moved out of the component per the design-system-consistency roadmap item. + ### Added - **Daily `/api/cron/refresh-open-stats` cron** (Vercel cron, 05:00 UTC) that runs the live open-stats aggregation and persists a durable snapshot. Closes the gap left by the activation performance work, where `/open` and the landing ticker were switched to snapshot-only reads but nothing refreshed the snapshot. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 3d20f45c..ee1ac1a6 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -124,9 +124,6 @@ Extension of Team/Org Workspaces with premium features: private team leaderboard ### Client-side email validation before OTP send Login form uses `type="email"` + `required` but no check for common mistakes (missing TLD, etc.) before the network request. Low effort, low impact. -### Model colors outside design system -`ActivityCard.tsx:147-158` uses hardcoded hex colors for model chips. Should be extracted to `lib/constants/model-colors.ts` for consistency. - ### Typing indicators in DMs No typing indicators in direct messages. Would require Supabase Realtime presence channels.