authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-24 10:49:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-24 10:49:04-07:00
log315fcca10a826d8aa1cbdffc3ef5b5eb5a1e2f9d
tree76aa7388fe5aa248af8f42146799f7ac0225f30c
parent80fc23ac32cd8fe5011a94420cff1f469367f1fc
signature Signed by PGP key B5690EEEBB952194

fix(web): web colors come from theme tokens (#13371)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

28 files changed, 173 insertions(+), 172 deletions(-)

apps/web/src/components/ChatMarkdown.tsx+1-1
......@@ -308,7 +308,7 @@ function CodexArtifactTemplateCard(props: {
308308 <div className="flex min-w-0 flex-1 items-center gap-3">
309309 <span className="relative flex size-9 shrink-0 items-center justify-center rounded-lg border border-border/70 bg-background text-muted-foreground shadow-xs">
310310 <Icon aria-hidden className="size-5" />
311 <span className="absolute -right-1 -bottom-1 flex size-4 items-center justify-center rounded-full border border-background bg-fuchsia-500 text-white shadow-xs">
311 <span className="absolute -right-1 -bottom-1 flex size-4 items-center justify-center rounded-full border border-background bg-primary text-primary-foreground shadow-xs">
312312 <SparklesIcon aria-hidden className="size-2.5" />
313313 </span>
314314 </span>
apps/web/src/components/Icons.tsx+85
......@@ -781,3 +781,88 @@ export const ForgejoIcon: Icon = (props) => (
781781 </g>
782782 </svg>
783783);
784
785// macOS System Settings > Privacy & Security pane marks, so the SnapShot setup
786// step points at the same icon the user is about to look for.
787export const MacScreenRecordingIcon: Icon = (props) => {
788 const gradientId = useId();
789 return (
790 <svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
791 <defs>
792 <linearGradient id={gradientId} x2="0" y2="1">
793 <stop stopColor="#ff6972" />
794 <stop offset="1" stopColor="#ff2938" />
795 </linearGradient>
796 </defs>
797 <rect
798 x="0.5"
799 y="0.5"
800 width="31"
801 height="31"
802 rx="7"
803 fill={`url(#${gradientId})`}
804 stroke="#ffffff40"
805 />
806 <circle cx="16" cy="16" r="10" fill="none" stroke="#fff" strokeWidth="2" />
807 <circle cx="16" cy="16" r="4.5" fill="#fff" />
808 </svg>
809 );
810};
811
812export const MacAccessibilityIcon: Icon = (props) => {
813 const gradientId = useId();
814 return (
815 <svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
816 <defs>
817 <linearGradient id={gradientId} x2="0" y2="1">
818 <stop stopColor="#48b6ff" />
819 <stop offset="1" stopColor="#0085ff" />
820 </linearGradient>
821 </defs>
822 <rect
823 x="0.5"
824 y="0.5"
825 width="31"
826 height="31"
827 rx="7"
828 fill={`url(#${gradientId})`}
829 stroke="#ffffff40"
830 />
831 <circle cx="16" cy="16" r="10" fill="none" stroke="#fff" strokeWidth="1.75" />
832 <circle cx="16" cy="10" r="1.6" fill="#fff" />
833 <path
834 d="m10 13 6 1 6-1M16 14v4m0 0-2.5 6m2.5-6 2.5 6"
835 fill="none"
836 stroke="#fff"
837 strokeWidth="1.6"
838 strokeLinecap="round"
839 strokeLinejoin="round"
840 />
841 </svg>
842 );
843};
844
845// Codex's Computer Use app mark, shown on computer-use rows in the work log.
846export const ComputerUseAppIcon: Icon = (props) => {
847 const gradientId = `${useId().replaceAll(":", "")}-computer-use-app-gradient`;
848 return (
849 <svg viewBox="0 0 24 24" aria-hidden="true" {...props}>
850 <defs>
851 <linearGradient id={gradientId} x1="2" y1="2" x2="22" y2="22">
852 <stop offset="0" stopColor="#00dff0" />
853 <stop offset="0.42" stopColor="#3b9cff" />
854 <stop offset="0.72" stopColor="#b044f5" />
855 <stop offset="1" stopColor="#ff78b6" />
856 </linearGradient>
857 </defs>
858 <rect x="1" y="1" width="22" height="22" rx="5" fill={`url(#${gradientId})`} />
859 <path
860 d="m7.2 6.2 10.5 4.1-4.2 2.1-2 4.7z"
861 fill="white"
862 stroke="#315cff"
863 strokeWidth="1.1"
864 strokeLinejoin="round"
865 />
866 </svg>
867 );
868};
apps/web/src/components/LegacySidebar.tsx+1-1
......@@ -806,7 +806,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
806806 <button
807807 type="button"
808808 aria-label={`Open localhost:${discoveredPorts[0]?.port ?? ""}`}
809 className="inline-flex cursor-pointer items-center justify-center text-emerald-600 outline-hidden focus-visible:ring-1 focus-visible:ring-ring dark:text-emerald-400"
809 className="inline-flex cursor-pointer items-center justify-center text-success-foreground outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
810810 onClick={handleOpenDiscoveredPort}
811811 />
812812 }
apps/web/src/components/QuitHoldOverlay.tsx+1-1
......@@ -48,7 +48,7 @@ export function QuitHoldOverlay() {
4848 role="status"
4949 className="pointer-events-none fixed inset-x-0 top-[22%] z-100 flex justify-center"
5050 >
51 <div className="rounded-full bg-neutral-700/95 px-8 py-4 text-2xl font-bold text-white shadow-xl">
51 <div className="rounded-full bg-foreground/95 px-8 py-4 text-2xl font-bold text-background shadow-xl">
5252 {message}
5353 </div>
5454 </div>
apps/web/src/components/Sidebar.tsx+9-9
......@@ -414,7 +414,7 @@ function SidebarThreadTooltip({
414414 </div>
415415 ) : null}
416416 {thread.session?.lastError ? (
417 <div className="flex min-w-0 items-center gap-2 text-red-600 dark:text-red-400">
417 <div className="flex min-w-0 items-center gap-2 text-destructive-foreground">
418418 <CircleAlertIcon className="size-3 shrink-0 stroke-current" />
419419 <div className="min-w-0 truncate">Error occurred</div>
420420 </div>
......@@ -529,8 +529,8 @@ function SortableThreadRow(props: {
529529
530530// Unsent work shares one look: the new-thread draft rows and thread rows
531531// with unsent composer text both use this tint and pen so they read alike.
532const draftSurfaceClassName = "bg-amber-400/[0.04] hover:bg-amber-400/[0.08]";
533const draftPenClassName = "size-3 shrink-0 text-amber-600 dark:text-amber-300/80";
532const draftSurfaceClassName = "bg-warning/4 hover:bg-warning/8";
533const draftPenClassName = "size-3 shrink-0 text-warning-foreground";
534534
535535// Structural list items — the section headers and the
536536// empty-section placeholders — take part in the sortable list so they shift
......@@ -647,7 +647,7 @@ function SidebarSectionHeader(props: {
647647 const snoozed = props.marker === "snoozed-header";
648648 const className = cn(
649649 "flex h-full w-full items-center gap-2 px-2 text-left text-xs font-medium",
650 snoozed ? "text-blue-600 dark:text-blue-400" : "text-sidebar-muted-foreground/60",
650 snoozed ? "text-info-foreground" : "text-sidebar-muted-foreground/60",
651651 props.dragging && "text-sidebar-foreground/80",
652652 props.isDropTarget && "text-primary",
653653 );
......@@ -658,7 +658,7 @@ function SidebarSectionHeader(props: {
658658 aria-hidden
659659 className={cn(
660660 "h-px min-w-2 flex-1",
661 snoozed ? "bg-blue-500/20 dark:bg-blue-400/15" : "bg-sidebar-border/60",
661 snoozed ? "bg-info/20" : "bg-sidebar-border/60",
662662 props.dragging && "bg-sidebar-foreground/25",
663663 props.isDropTarget && "bg-primary/50",
664664 )}
......@@ -1143,7 +1143,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
11431143 ? {
11441144 label: "Approval",
11451145 icon: "approval" as const,
1146 className: "text-amber-700 dark:text-amber-300",
1146 className: "text-warning-foreground",
11471147 }
11481148 : status === "input"
11491149 ? {
......@@ -1161,7 +1161,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
11611161 ? {
11621162 label: "Woke",
11631163 icon: "woke" as const,
1164 className: "text-amber-700 dark:text-amber-300",
1164 className: "text-warning-foreground",
11651165 }
11661166 : isUnread
11671167 ? {
......@@ -1629,7 +1629,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
16291629 {variantAction === "unsnooze" && props.snoozeWakeLabelText !== null ? (
16301630 // Snoozed rows show when they come BACK, not when they were
16311631 // last touched — the return ticket is the row's whole story.
1632 <span className="text-xs text-blue-600 tabular-nums dark:text-blue-400">
1632 <span className="text-xs text-info-foreground tabular-nums">
16331633 {props.snoozeWakeLabelText}
16341634 </span>
16351635 ) : isWoke ? (
......@@ -1642,7 +1642,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
16421642 type="button"
16431643 aria-label="Dismiss Woke notification"
16441644 onClick={handleAcknowledgeWokeClick}
1645 className="inline-flex cursor-pointer items-center gap-1 rounded-sm text-xs font-medium text-amber-700 outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring dark:text-amber-300"
1645 className="inline-flex cursor-pointer items-center gap-1 rounded-sm text-xs font-medium text-warning-foreground outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring"
16461646 >
16471647 <AlarmClockIcon aria-hidden className="size-3" />
16481648 <span role="status">Woke</span>
apps/web/src/components/ThreadNotificationCoordinator.tsx+4-13
......@@ -164,22 +164,13 @@ function EnvironmentNotifications({
164164 hideCopyButton: true,
165165 leadingIcon:
166166 kind === "completion" ? (
167 <CircleCheckIcon
168 aria-hidden
169 className="size-4 text-emerald-700 dark:text-emerald-300"
170 />
167 <CircleCheckIcon aria-hidden className="size-4 text-success-foreground" />
171168 ) : status === "approval" ? (
172 <ShieldQuestionIcon
173 aria-hidden
174 className="size-4 text-amber-700 dark:text-amber-300"
175 />
169 <ShieldQuestionIcon aria-hidden className="size-4 text-warning-foreground" />
176170 ) : status === "failed" ? (
177 <CircleAlertIcon aria-hidden className="size-4 text-red-700 dark:text-red-300" />
171 <CircleAlertIcon aria-hidden className="size-4 text-destructive-foreground" />
178172 ) : (
179 <MessageCircleQuestionIcon
180 aria-hidden
181 className="size-4 text-indigo-600 dark:text-indigo-300"
182 />
173 <MessageCircleQuestionIcon aria-hidden className="size-4 text-info-foreground" />
183174 ),
184175 },
185176 actionProps: {
apps/web/src/components/ThreadSearchMatch.tsx+1-1
......@@ -57,7 +57,7 @@ export function ThreadSearchMatchExcerpt(props: {
5757 const isUser = props.match.source === "user";
5858 return (
5959 <span className="truncate text-xs text-muted-foreground/85">
60 <span className={isUser ? "text-blue-400" : "text-emerald-400"}>
60 <span className={isUser ? "text-info-foreground" : "text-success-foreground"}>
6161 {isUser ? "You:" : "Agent:"}
6262 </span>{" "}
6363 <HighlightedSearchText text={props.match.snippet} query={props.match.query} />
apps/web/src/components/chat/ChatComposer.tsx+1-1
......@@ -6559,7 +6559,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
65596559 <span
65606560 role="img"
65616561 aria-label="Draft attachment may not persist"
6562 className="absolute left-1 top-1 inline-flex items-center justify-center rounded bg-background/85 p-0.5 text-amber-600"
6562 className="absolute left-1 top-1 inline-flex items-center justify-center rounded bg-background/85 p-0.5 text-warning-foreground"
65636563 >
65646564 <CircleAlertIcon className="size-3" />
65656565 </span>
apps/web/src/components/chat/ContextWindowMeter.tsx+1-1
......@@ -63,7 +63,7 @@ export function ContextWindowMeter(props: {
6363 cy="12"
6464 r={radius}
6565 fill="none"
66 stroke="color-mix(in oklab, var(--color-muted-foreground) 24%, transparent)"
66 className="stroke-muted-foreground/24"
6767 strokeWidth="3"
6868 />
6969 <circle
apps/web/src/components/chat/MessagesTimeline.tsx+1-25
......@@ -63,7 +63,6 @@ import {
6363 use,
6464 useCallback,
6565 useEffect,
66 useId,
6766 useLayoutEffect,
6867 useMemo,
6968 useRef,
......@@ -256,6 +255,7 @@ import {
256255 type ReviewCommentContext,
257256} from "../../reviewCommentContext";
258257import { PullRequestGlyph } from "~/components/pullRequest/pullRequestIcons";
258import { ComputerUseAppIcon } from "~/components/Icons";
259259
260260// ---------------------------------------------------------------------------
261261// Context — shared state consumed by every row component via Context.
......@@ -4146,30 +4146,6 @@ function BrowserAppIcon({ className }: { className: string }) {
41464146 );
41474147}
41484148
4149function ComputerUseAppIcon({ className }: { className: string }) {
4150 const gradientId = `${useId().replaceAll(":", "")}-computer-use-app-gradient`;
4151 return (
4152 <svg viewBox="0 0 24 24" className={className} aria-hidden>
4153 <defs>
4154 <linearGradient id={gradientId} x1="2" y1="2" x2="22" y2="22">
4155 <stop offset="0" stopColor="#00dff0" />
4156 <stop offset="0.42" stopColor="#3b9cff" />
4157 <stop offset="0.72" stopColor="#b044f5" />
4158 <stop offset="1" stopColor="#ff78b6" />
4159 </linearGradient>
4160 </defs>
4161 <rect x="1" y="1" width="22" height="22" rx="5" fill={`url(#${gradientId})`} />
4162 <path
4163 d="m7.2 6.2 10.5 4.1-4.2 2.1-2 4.7z"
4164 fill="white"
4165 stroke="#315cff"
4166 strokeWidth="1.1"
4167 strokeLinejoin="round"
4168 />
4169 </svg>
4170 );
4171}
4172
41734149function ToolActivityIconView(props: {
41744150 icon: ToolActivityIcon | undefined;
41754151 fallbackName: WorkEntryIconName;
apps/web/src/components/chat/ModelListRow.tsx+1-1
......@@ -117,7 +117,7 @@ export const ModelListRow = memo(function ModelListRow(props: {
117117 <StarIcon
118118 className={cn(
119119 "size-3.5 sm:size-3",
120 props.isFavorite && "fill-current text-yellow-500",
120 props.isFavorite && "fill-current text-warning",
121121 )}
122122 />
123123 </Button>
apps/web/src/components/chat/TerminalContextInlineChip.tsx+1-1
......@@ -26,7 +26,7 @@ export function TerminalContextInlineChip(props: TerminalContextInlineChipProps)
2626 >
2727 <div className="overflow-hidden rounded-md border border-border/70 bg-background/80">
2828 <div className="flex items-center gap-2 border-b border-border/70 px-3 py-2">
29 <TerminalIcon className="size-4 shrink-0 text-emerald-500" aria-hidden />
29 <TerminalIcon className="size-4 shrink-0 text-success" aria-hidden />
3030 <span className="min-w-0 truncate text-sm font-medium text-foreground">
3131 {terminalLabel}
3232 </span>
apps/web/src/components/cloud/ConnectCliAuthSurface.tsx+1-1
......@@ -23,7 +23,7 @@ function ConnectCliAuthMessage({
2323 return (
2424 <>
2525 {eyebrow ? (
26 <p className="text-[10px] font-semibold tracking-[0.18em] text-blue-600 uppercase dark:text-blue-400">
26 <p className="text-[10px] font-semibold tracking-[0.18em] text-primary uppercase">
2727 {eyebrow}
2828 </p>
2929 ) : null}
apps/web/src/components/device/DeviceStreamView.tsx+2-2
......@@ -395,7 +395,7 @@ export function DeviceStreamView(props: {
395395 {axElements.map((element) => (
396396 <div
397397 key={element.id}
398 className="absolute border border-sky-400/80 bg-sky-400/10"
398 className="absolute border border-info/80 bg-info/10"
399399 style={{
400400 left: `${element.x * 100}%`,
401401 top: `${element.y * 100}%`,
......@@ -404,7 +404,7 @@ export function DeviceStreamView(props: {
404404 }}
405405 >
406406 {element.label ? (
407 <span className="absolute -top-3.5 left-0 max-w-full truncate rounded-sm bg-sky-500 px-1 text-[9px] leading-3.5 text-white">
407 <span className="absolute -top-3.5 left-0 max-w-full truncate rounded-sm bg-info px-1 text-[9px] leading-3.5 text-white">
408408 {element.label}
409409 </span>
410410 ) : null}
apps/web/src/components/preview/ThreadPreviewMiniPlayer.tsx+4-2
......@@ -462,7 +462,9 @@ function MiniPlayerShell({
462462 <span
463463 className={cn(
464464 "block size-2 rounded-full shadow-sm ring-1 ring-background/70",
465 recording ? "bg-red-500 motion-safe:animate-status-pulse" : "bg-foreground/25",
465 recording
466 ? "bg-destructive motion-safe:animate-status-pulse"
467 : "bg-foreground/25",
466468 )}
467469 />
468470 </div>
......@@ -475,7 +477,7 @@ function MiniPlayerShell({
475477 >
476478 {recording ? (
477479 <span aria-hidden className="flex size-6 shrink-0 items-center justify-center">
478 <span className="size-2 rounded-full bg-red-500 motion-safe:animate-status-pulse" />
480 <span className="size-2 rounded-full bg-destructive motion-safe:animate-status-pulse" />
479481 </span>
480482 ) : null}
481483 <Tooltip>
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+4-4
......@@ -852,7 +852,7 @@ function PullRequestCodeTab({
852852 />
853853 {stale ? (
854854 <Tooltip>
855 <TooltipTrigger render={<span className="text-amber-600 dark:text-amber-500" />}>
855 <TooltipTrigger render={<span className="text-warning-foreground" />}>
856856 Changed
857857 </TooltipTrigger>
858858 <TooltipPopup side="bottom">
......@@ -1157,7 +1157,7 @@ function PullRequestCodeTab({
11571157 <TooltipTrigger render={<span className="flex shrink-0 items-center" />}>
11581158 <TriangleAlertIcon
11591159 aria-label="Your ticks could not be read"
1160 className="size-3.5 text-amber-600 dark:text-amber-500"
1160 className="size-3.5 text-warning-foreground"
11611161 />
11621162 </TooltipTrigger>
11631163 <TooltipPopup side="bottom">
......@@ -1171,7 +1171,7 @@ function PullRequestCodeTab({
11711171 <TooltipTrigger render={<span className="flex shrink-0 items-center" />}>
11721172 <TriangleAlertIcon
11731173 aria-label="This count covers only part of the change"
1174 className="size-3.5 text-amber-600 dark:text-amber-500"
1174 className="size-3.5 text-warning-foreground"
11751175 />
11761176 </TooltipTrigger>
11771177 <TooltipPopup side="bottom">
......@@ -1187,7 +1187,7 @@ function PullRequestCodeTab({
11871187 <TooltipTrigger render={<span className="flex shrink-0 items-center" />}>
11881188 <TriangleAlertIcon
11891189 aria-label="Some of this diff was not shown"
1190 className="size-3.5 text-amber-600 dark:text-amber-500"
1190 className="size-3.5 text-warning-foreground"
11911191 />
11921192 </TooltipTrigger>
11931193 <TooltipPopup side="bottom">
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+1-1
......@@ -379,7 +379,7 @@ function PullRequestBaseFreshnessWarning({
379379 type="button"
380380 aria-label={summary}
381381 className={cn(
382 "inline-flex min-w-0 shrink-0 cursor-help items-center gap-1 rounded-sm text-amber-600 outline-none focus-visible:ring-2 focus-visible:ring-ring dark:text-amber-400/90",
382 "inline-flex min-w-0 shrink-0 cursor-help items-center gap-1 rounded-sm text-warning-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring",
383383 className,
384384 )}
385385 />
apps/web/src/components/pullRequest/PullRequestReviewAnnotation.tsx+1-1
......@@ -220,7 +220,7 @@ export function ReviewThreadCard({
220220 >
221221 <div className="flex items-center gap-2 text-xs text-muted-foreground">
222222 {thread.isResolved ? (
223 <CheckCircle2Icon className="size-3.5 text-emerald-600 dark:text-emerald-500" />
223 <CheckCircle2Icon className="size-3.5 text-success-foreground" />
224224 ) : (
225225 <CircleIcon className="size-3.5" />
226226 )}
apps/web/src/components/pullRequest/PullRequestSummaryTab.tsx+1-1
......@@ -943,7 +943,7 @@ export function PullRequestSummaryTab({
943943 ) : (
944944 <>
945945 {detail.commentsTruncated ? (
946 <p className="mb-2 rounded-md border border-amber-500/30 bg-amber-500/5 px-2 py-1.5 text-xs">
946 <p className="mb-2 rounded-md border border-warning/30 bg-warning-surface px-2 py-1.5 text-xs">
947947 This conversation is longer than this page reads in one go. The most recent{" "}
948948 {detail.comments.length} are here; open it on the host to read the rest.
949949 </p>
apps/web/src/components/settings/AddProviderInstanceDialog.tsx+1-1
......@@ -259,7 +259,7 @@ export function AddProviderInstanceDialog({
259259 <RadioPrimitive.Root
260260 key={option.value}
261261 value={option.value}
262 className="relative flex cursor-pointer items-center gap-3 rounded-lg bg-card px-3 py-3 text-left text-muted-foreground outline-none ring-1 ring-black/5 hover:bg-zinc-50 focus-visible:ring-2 focus-visible:ring-ring data-checked:bg-primary/8 data-checked:text-foreground data-checked:ring-2 data-checked:ring-primary data-checked:hover:bg-primary/8 dark:bg-white/3 dark:ring-white/5 dark:hover:bg-white/5 dark:data-checked:bg-primary/15 dark:data-checked:ring-primary dark:data-checked:hover:bg-primary/15"
262 className="relative flex cursor-pointer items-center gap-3 rounded-lg bg-card px-3 py-3 text-left text-muted-foreground outline-none ring-1 ring-black/5 hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring data-checked:bg-primary/8 data-checked:text-foreground data-checked:ring-2 data-checked:ring-primary data-checked:hover:bg-primary/8 dark:bg-white/3 dark:ring-white/5 dark:hover:bg-white/5 dark:data-checked:bg-primary/15 dark:data-checked:ring-primary dark:data-checked:hover:bg-primary/15"
263263 >
264264 <IconComponent className="size-4 shrink-0" aria-hidden />
265265 <span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
apps/web/src/components/settings/ConnectionsSettings.tsx+1-1
......@@ -756,7 +756,7 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
756756 <div className="flex min-h-5 items-center gap-1.5">
757757 <ConnectionStatusDot
758758 tooltipText={`Link created at ${formatAccessTimestamp(pairingLink.createdAt)}`}
759 dotClassName="bg-amber-400"
759 dotClassName="bg-warning"
760760 />
761761 <h3 className="text-sm font-medium text-foreground">{primaryLabel}</h3>
762762 </div>
apps/web/src/components/settings/DiagnosticsSettings.tsx+4-6
......@@ -116,7 +116,7 @@ function StatBlock({
116116 <div
117117 className={cn(
118118 "mt-1 truncate font-mono text-lg font-semibold tabular-nums text-foreground",
119 tone === "warning" && "text-amber-600 dark:text-amber-400",
119 tone === "warning" && "text-warning-foreground",
120120 tone === "danger" && "text-destructive",
121121 )}
122122 >
......@@ -287,7 +287,7 @@ function ProcessNameCell({
287287 ) : (
288288 <span className="size-5 shrink-0" aria-hidden="true" />
289289 )}
290 <span className="size-1.5 shrink-0 rounded-full bg-emerald-500/80" />
290 <span className="size-1.5 shrink-0 rounded-full bg-success/80" />
291291 <Tooltip>
292292 <TooltipTrigger
293293 render={<span className="min-w-0 truncate font-medium text-foreground">{name}</span>}
......@@ -465,7 +465,7 @@ function ResourceHistoryProcessNameCell({
465465 <span
466466 className={cn(
467467 "size-1.5 shrink-0 rounded-full",
468 process.isServerRoot ? "bg-amber-500/90" : "bg-emerald-500/80",
468 process.isServerRoot ? "bg-warning/90" : "bg-success/80",
469469 )}
470470 />
471471 <Tooltip>
......@@ -1100,9 +1100,7 @@ export function DiagnosticsSettingsPanel() {
11001100 <div
11011101 className={cn(
11021102 "flex items-start gap-2",
1103 traceDiagnosticsPartialFailure
1104 ? "text-amber-600 dark:text-amber-400"
1105 : "text-destructive",
1103 traceDiagnosticsPartialFailure ? "text-warning-foreground" : "text-destructive",
11061104 )}
11071105 >
11081106 <AlertTriangleIcon className="mt-0.5 size-3.5 shrink-0" />
apps/web/src/components/settings/ResourceTelemetryDiagnostics.tsx+23-25
......@@ -142,10 +142,10 @@ function categoryLabel(category: ResourceTelemetryProcessCategory): string {
142142}
143143
144144function categoryDotClass(category: ResourceTelemetryProcessCategory): string {
145 if (category === "resource-monitor") return "bg-amber-500";
146 if (category.startsWith("electron-")) return "bg-sky-500";
145 if (category === "resource-monitor") return "bg-warning";
146 if (category.startsWith("electron-")) return "bg-info";
147147 if (category === "server") return "bg-violet-500";
148 return "bg-emerald-500";
148 return "bg-success";
149149}
150150
151151function ioSemanticsLabel(semantics: ResourceTelemetryIoSemantics): string {
......@@ -196,10 +196,8 @@ function SourceStatusBadge({
196196 className={cn(
197197 "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.08em]",
198198 tone === "neutral" && "border-border/70 bg-muted/45 text-muted-foreground",
199 tone === "default" &&
200 "border-emerald-500/25 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
201 tone === "warning" &&
202 "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300",
199 tone === "default" && "border-success/25 bg-success/10 text-success-foreground",
200 tone === "warning" && "border-warning/30 bg-warning/10 text-warning-foreground",
203201 tone === "danger" && "border-destructive/30 bg-destructive/10 text-destructive",
204202 )}
205203 >
......@@ -207,8 +205,8 @@ function SourceStatusBadge({
207205 className={cn(
208206 "size-1.5 rounded-full",
209207 tone === "neutral" && "bg-muted-foreground/55",
210 tone === "default" && "bg-emerald-500",
211 tone === "warning" && "bg-amber-500",
208 tone === "default" && "bg-success",
209 tone === "warning" && "bg-warning",
212210 tone === "danger" && "bg-destructive",
213211 )}
214212 />
......@@ -258,7 +256,7 @@ function IconStat({
258256 <div
259257 className={cn(
260258 "mt-2.5 truncate font-mono text-2xl font-semibold tracking-[-0.05em] tabular-nums text-foreground",
261 tone === "warning" && "text-amber-600 dark:text-amber-300",
259 tone === "warning" && "text-warning-foreground",
262260 tone === "danger" && "text-destructive",
263261 )}
264262 >
......@@ -412,10 +410,10 @@ function ResourceHistoryChart({
412410 <span className="h-1.5 w-3 rounded-full bg-foreground/70" /> CPU average
413411 </span>
414412 <span className="inline-flex items-center gap-1.5">
415 <span className="h-1.5 w-3 rounded-full bg-sky-500/70" /> I/O reads
413 <span className="h-1.5 w-3 rounded-full bg-info/70" /> I/O reads
416414 </span>
417415 <span className="inline-flex items-center gap-1.5">
418 <span className="h-1.5 w-3 rounded-full bg-amber-500/80" /> I/O writes
416 <span className="h-1.5 w-3 rounded-full bg-warning/80" /> I/O writes
419417 </span>
420418 </div>
421419 <div className="flex h-32 items-end gap-1 overflow-hidden rounded-lg border border-border/40 bg-muted/8 px-2 pt-3 pb-2">
......@@ -445,11 +443,11 @@ function ResourceHistoryChart({
445443 style={{ height: `${cpuHeight}%` }}
446444 />
447445 <span
448 className="block rounded-t-sm bg-sky-500/70"
446 className="block rounded-t-sm bg-info/70"
449447 style={{ height: `${readHeight}%` }}
450448 />
451449 <span
452 className="block rounded-t-sm bg-amber-500/80"
450 className="block rounded-t-sm bg-warning/80"
453451 style={{ height: `${writeHeight}%` }}
454452 />
455453 </div>
......@@ -632,10 +630,10 @@ function ProcessTable({
632630 <td className="px-3 py-2 text-right font-mono tabular-nums">
633631 {formatBytes(process.residentBytes)}
634632 </td>
635 <td className="px-3 py-2 text-right font-mono tabular-nums text-sky-700 dark:text-sky-300">
633 <td className="px-3 py-2 text-right font-mono tabular-nums text-info-foreground">
636634 {formatRate(process.ioReadBytesPerSecond)}
637635 </td>
638 <td className="px-3 py-2 text-right font-mono tabular-nums text-amber-700 dark:text-amber-300">
636 <td className="px-3 py-2 text-right font-mono tabular-nums text-warning-foreground">
639637 {formatRate(process.ioWriteBytesPerSecond)}
640638 </td>
641639 <td className="px-3 py-2 text-right font-mono tabular-nums text-muted-foreground">
......@@ -740,10 +738,10 @@ function HistoryProcessTable({
740738 <td className="px-3 py-2 text-right font-mono tabular-nums">
741739 {formatBytes(process.peakRssBytes)}
742740 </td>
743 <td className="px-3 py-2 text-right font-mono tabular-nums text-sky-700 dark:text-sky-300">
741 <td className="px-3 py-2 text-right font-mono tabular-nums text-info-foreground">
744742 {formatBytes(process.ioReadBytes)}
745743 </td>
746 <td className="px-3 py-2 text-right font-mono tabular-nums text-amber-700 dark:text-amber-300">
744 <td className="px-3 py-2 text-right font-mono tabular-nums text-warning-foreground">
747745 {formatBytes(process.ioWriteBytes)}
748746 </td>
749747 <td className="px-3 py-2 text-right font-mono tabular-nums text-muted-foreground">
......@@ -797,10 +795,10 @@ function AttributionTable({ entries }: { entries: ReadonlyArray<ResourceAttribut
797795 {entry.component}
798796 </td>
799797 <td className="truncate px-3 py-2 text-muted-foreground">{entry.operation}</td>
800 <td className="px-3 py-2 text-right font-mono tabular-nums text-sky-700 dark:text-sky-300">
798 <td className="px-3 py-2 text-right font-mono tabular-nums text-info-foreground">
801799 {formatBytes(entry.logicalReadBytes)}
802800 </td>
803 <td className="px-3 py-2 text-right font-mono tabular-nums text-amber-700 dark:text-amber-300">
801 <td className="px-3 py-2 text-right font-mono tabular-nums text-warning-foreground">
804802 {formatBytes(entry.logicalWriteBytes)}
805803 </td>
806804 <td className="px-3 py-2 text-right font-mono tabular-nums">{entry.count}</td>
......@@ -997,7 +995,7 @@ export function ResourceTelemetryDiagnostics({
997995 </p>
998996 </div>
999997 <div className="flex items-center gap-2 text-[10px] text-muted-foreground/65">
1000 <span className="size-1.5 rounded-full bg-emerald-500" />
998 <span className="size-1.5 rounded-full bg-success" />
1001999 Sampling every {snapshot ? formatSampleInterval(snapshot.sampleIntervalMs) : "..."}
10021000 </div>
10031001 </div>
......@@ -1063,17 +1061,17 @@ export function ResourceTelemetryDiagnostics({
10631061 <div className="grid border-t border-border/60 bg-muted/10 md:grid-cols-3">
10641062 <AggregateCard
10651063 label="Backend + agents"
1066 accentClass="bg-emerald-500/80"
1064 accentClass="bg-success/80"
10671065 aggregate={snapshot.groups.backend}
10681066 />
10691067 <AggregateCard
10701068 label="Desktop"
1071 accentClass="bg-sky-500/80"
1069 accentClass="bg-info/80"
10721070 aggregate={snapshot.groups.electron}
10731071 />
10741072 <AggregateCard
10751073 label="Monitor overhead"
1076 accentClass="bg-amber-500/80"
1074 accentClass="bg-warning/80"
10771075 aggregate={snapshot.groups.monitor}
10781076 />
10791077 </div>
......@@ -1186,7 +1184,7 @@ export function ResourceTelemetryDiagnostics({
11861184 value={String(snapshot.health.inaccessibleProcessCount)}
11871185 valueClassName={
11881186 snapshot.health.inaccessibleProcessCount > 0
1189 ? "text-amber-600 dark:text-amber-300"
1187 ? "text-warning-foreground"
11901188 : undefined
11911189 }
11921190 />
apps/web/src/components/settings/SnapShotSetupDialog.tsx+8-69
......@@ -5,7 +5,8 @@ import {
55 type DesktopSnapShotSetupAction,
66 type DesktopSnapShotState,
77} from "@t3tools/contracts";
8import { useId, useState, type ReactNode } from "react";
8import { useState, type ReactNode } from "react";
9import { MacAccessibilityIcon, MacScreenRecordingIcon } from "../Icons";
910import { CaptureShortcutConfig } from "./CaptureShortcutConfig";
1011import { Button } from "../ui/button";
1112import { Dialog, DialogDescription } from "../ui/dialog";
......@@ -61,72 +62,6 @@ const GNOME_ACCESS_COPY = {
6162 },
6263};
6364
64function ScreenRecordingIcon() {
65 const gradientId = useId();
66 return (
67 <svg
68 viewBox="0 0 32 32"
69 className="size-8 shrink-0 drop-shadow-[0_1px_1px_#0005]"
70 aria-hidden="true"
71 >
72 <defs>
73 <linearGradient id={gradientId} x2="0" y2="1">
74 <stop stopColor="#ff6972" />
75 <stop offset="1" stopColor="#ff2938" />
76 </linearGradient>
77 </defs>
78 <rect
79 x="0.5"
80 y="0.5"
81 width="31"
82 height="31"
83 rx="7"
84 fill={`url(#${gradientId})`}
85 stroke="#ffffff40"
86 />
87 <circle cx="16" cy="16" r="10" fill="none" stroke="#fff" strokeWidth="2" />
88 <circle cx="16" cy="16" r="4.5" fill="#fff" />
89 </svg>
90 );
91}
92
93function AccessibilityPermissionIcon() {
94 const gradientId = useId();
95 return (
96 <svg
97 viewBox="0 0 32 32"
98 className="size-8 shrink-0 drop-shadow-[0_1px_1px_#0005]"
99 aria-hidden="true"
100 >
101 <defs>
102 <linearGradient id={gradientId} x2="0" y2="1">
103 <stop stopColor="#48b6ff" />
104 <stop offset="1" stopColor="#0085ff" />
105 </linearGradient>
106 </defs>
107 <rect
108 x="0.5"
109 y="0.5"
110 width="31"
111 height="31"
112 rx="7"
113 fill={`url(#${gradientId})`}
114 stroke="#ffffff40"
115 />
116 <circle cx="16" cy="16" r="10" fill="none" stroke="#fff" strokeWidth="1.75" />
117 <circle cx="16" cy="10" r="1.6" fill="#fff" />
118 <path
119 d="m10 13 6 1 6-1M16 14v4m0 0-2.5 6m2.5-6 2.5 6"
120 fill="none"
121 stroke="#fff"
122 strokeWidth="1.6"
123 strokeLinecap="round"
124 strokeLinejoin="round"
125 />
126 </svg>
127 );
128}
129
13065export function SnapShotSetupDialog({
13166 state,
13267 initialStep,
......@@ -333,7 +268,9 @@ export function SnapShotSetupDialog({
333268 permissions={[
334269 {
335270 id: "screenRecording",
336 icon: <ScreenRecordingIcon />,
271 icon: (
272 <MacScreenRecordingIcon className="size-8 shrink-0 drop-shadow-[0_1px_1px_#0005]" />
273 ),
337274 title: "Screen Recording",
338275 description: "Capture the window you're using.",
339276 granted: macPermissions.screenRecording,
......@@ -341,7 +278,9 @@ export function SnapShotSetupDialog({
341278 },
342279 {
343280 id: "accessibility",
344 icon: <AccessibilityPermissionIcon />,
281 icon: (
282 <MacAccessibilityIcon className="size-8 shrink-0 drop-shadow-[0_1px_1px_#0005]" />
283 ),
345284 title: "Accessibility",
346285 description: includeAccessibility
347286 ? "Include text and controls from the captured app."
apps/web/src/components/sidebar/DesktopUpdateStatusIcon.tsx+1-1
......@@ -67,7 +67,7 @@ function DesktopUpdateDownloadingIcon({ percent }: { readonly percent: number |
6767 cy="16"
6868 r={DOWNLOAD_PROGRESS_RADIUS}
6969 fill="none"
70 stroke="color-mix(in srgb, currentColor 22%, transparent)"
70 className="stroke-current/22"
7171 strokeWidth="1.5"
7272 />
7373 <circle
apps/web/src/components/usage/UsagePage.tsx+1-1
......@@ -753,7 +753,7 @@ function UsageEnvironmentFilter({
753753 </>
754754 ) : showUsageStatus && hasIssue ? (
755755 <CircleAlertIcon
756 className="size-3.5 text-amber-600 dark:text-amber-400"
756 className="size-3.5 text-warning-foreground"
757757 aria-label="Some environments could not report usage"
758758 />
759759 ) : (
apps/web/src/routes/_chat.pull-requests.tsx+1-1
......@@ -1819,7 +1819,7 @@ function PullRequestsRouteView() {
18191819 )}
18201820
18211821 {listQuery.error && shownCount > 0 ? (
1822 <div className="flex items-center justify-between gap-3 rounded-lg border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-xs">
1822 <div className="flex items-center justify-between gap-3 rounded-lg border border-warning/30 bg-warning-surface px-3 py-2 text-xs">
18231823 <span>{listQuery.error} Showing the last pull requests loaded.</span>
18241824 <Button size="xs" variant="outline" onClick={() => listQuery.refresh()}>
18251825 Retry
vite.config.ts+12
......@@ -203,6 +203,18 @@ export default defineConfig({
203203 files: ["apps/web/src/**"],
204204 rules: { "shadcn/no-unknown-classes": "error" },
205205 },
206 {
207 // Colors come from theme tokens so status tones follow custom themes. components/ui
208 // has no findings and stays covered too.
209 files: ["apps/web/src/**"],
210 rules: { "shadcn/no-raw-colors": "error" },
211 },
212 {
213 // Third-party marks (brand logos, the macOS permission panes, Codex's Computer Use
214 // mark) must keep their exact colors, so the files that hold them are exempt.
215 files: ["apps/web/src/components/Icons.tsx", "apps/web/src/components/JetBrainsIcons.tsx"],
216 rules: { "shadcn/no-raw-colors": "off" },
217 },
206218 {
207219 // components/ui exports own their look. App code picks a variant or size instead
208220 // of restyling with className; layout classes (width, flex, margin, position) stay