From 7b3d869bd99ee2cceff9e8b002c5fbc15926e9e7 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Thu, 24 Sep 2026 03:02:34 -0700 Subject: [PATCH] fix(web): appearance classes use theme tokens and scale values Enables shadcn/no-arbitrary-values as an error for apps/web/src outside components/ui, with layout allowed. 479 findings in 112 files -> 0. New theme tokens (index.css): - --text-2xs (11px, line-height 1rem) and --text-3xs (10px, 0.875rem): the two sizes below text-xs that dense UI uses app-wide (metadata rows, badges, counters, kbd hints, diagnostics). 11px/0.6875rem/.7rem map to 2xs; 10px/.65rem/.6rem/9px/8px/7px map to 3xs. Registered with tailwind-merge in cn(), which otherwise reads text-2xs as a colour and drops it next to text-muted-foreground. - --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1), the decelerating curve the composer context controls already shared (6 sites). The two one-off curves, (.2,.8,.2,1) on the composer "new" pop and (0.22,1,0.36,1) on the provider update pill, map to it as well. - Transition property lists stay as written (transition-[width], transition-[opacity,translate], ...): the rule allows the "transition" class group, because which properties an element animates is per-element behaviour like layout, not a design value. Every transition keeps exactly the properties it animated before; none widens to all. - --shadow-composer / --shadow-composer-dark: the composer's elevation, shared by the composer, its context strip and attached banners. - --background-image-composer-seam-below / -above: the dark-mode shade where the context strip and attached banners meet the composer. - --workspace-gutter(-start/-end): the page header and the chat column shared a copied calc(env(safe-area-inset-*)+0.75rem|1.25rem) gutter. - --font-size-prompt-touch: the prompt size on coarse-pointer phones, floored at 16px so iOS does not zoom on focus. Mappings: - 12px -> text-xs; 14px -> text-sm; 13px/0.8125rem -> text-xs for descriptions and text-sm for titles and body; 1.0625rem -> text-base; 1.4rem -> text-2xl. - Uppercase-label tracking (0.08em..0.2em) -> tracking-widest; -0.005em dropped; -0.05em -> tracking-tighter. leading-[1.125rem] -> leading-4.5, leading-[1.45] -> leading-normal. - [transition-duration:var(--x)] -> duration-(--x). - Other bespoke shadows -> shadow-xs/sm/md and inset-shadow-2xs with a colour; rgb/var colour mixes -> Tailwind colour/alpha syntax (bg-(--x)/(--glass-opacity), scrollbar-thumb-border/78, bg-foreground/10). - Radii -> the theme radius scale (22/20/24px -> 3xl, 16px -> 2xl, ...). - Masks -> mask-t/b-from/to utilities. - One-shot keyframe animations (stash count, SnapShot contents, provider pill countdown) -> transitions with starting: styles; keyframes removed. - ComposerControl icons take text-muted-foreground directly instead of a --control-icon-color indirection. - The right panel tab bar reserves the 6rem beside the native window controls with a spacer, not a calc() padding; the empty state pads its list instead of calc()ing the offset. Exemptions (each commented in vite.config.ts): - rounded-[inherit]: overlays follow their frame's corner, set at runtime (floating preview) or by the element they decorate (composer outline). - gap-[0.33em], px-[0.5em], rounded-[0.5em], text-[0.86em]: inline chips size in em so they scale with the prompt font-size preference. - rounded-[25%]: project icons render 14-48px with one proportional corner (the favicon's 37.5% now matches the monogram's 25%). - text-[length:80cqh]: an emoji icon fills its container. - bg-[Highlight]: the platform selection colour on a selected chip. - Brand fills for Cursor, Grok and Claude marks. - AuthSurfaceShell.tsx off: the sign-in masthead is T3 brand artwork. ContextChip's accent mixes with border/foreground (colour-mix of two colours) are now named custom properties on the chip, read with border-(--...) and text-(--...); the colour choices are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) --- apps/web/src/browser/BrowserDeviceToolbar.tsx | 2 +- apps/web/src/browser/HostedBrowserWebview.tsx | 2 +- apps/web/src/components/AgentsPanel.tsx | 24 +++--- apps/web/src/components/BranchToolbar.tsx | 4 +- .../BranchToolbarBranchSelector.tsx | 4 +- .../BranchToolbarEnvModeSelector.tsx | 6 +- .../BranchToolbarEnvironmentSelector.tsx | 6 +- apps/web/src/components/ChatMarkdown.tsx | 6 +- apps/web/src/components/ChatView.tsx | 6 +- .../components/ComposerPromptEditorTiptap.tsx | 4 +- apps/web/src/components/ContextChip.tsx | 6 +- apps/web/src/components/DiffPanel.tsx | 12 +-- apps/web/src/components/DiffPanelShell.tsx | 2 +- apps/web/src/components/LegacySidebar.tsx | 10 +-- apps/web/src/components/ProjectFavicon.tsx | 4 +- .../components/PullRequestContextDetails.tsx | 2 +- apps/web/src/components/RightPanelTabs.tsx | 21 ++--- apps/web/src/components/Sidebar.tsx | 16 ++-- .../SlowRpcRequestToastCoordinator.tsx | 2 +- .../src/components/ThreadStatusIndicators.tsx | 4 +- .../src/components/ThreadTerminalDrawer.tsx | 8 +- .../src/components/WorkspaceBreadcrumb.tsx | 2 +- .../src/components/WorkspacePageHeader.tsx | 4 +- .../src/components/auth/AuthSurfaceShell.tsx | 2 +- .../components/chat/AssistantCitationChip.tsx | 4 +- .../src/components/chat/ChangedFilesTree.tsx | 8 +- apps/web/src/components/chat/ChatComposer.tsx | 16 ++-- apps/web/src/components/chat/ChatHeader.tsx | 4 +- .../src/components/chat/ComposerBanner.tsx | 36 ++++----- .../components/chat/ComposerBannerStack.tsx | 4 +- .../src/components/chat/ComposerControl.tsx | 6 +- .../chat/ComposerPendingApprovalPanel.tsx | 2 +- .../chat/ComposerPendingUserInputPanel.tsx | 8 +- .../chat/ComposerPrimaryActions.tsx | 4 +- .../components/chat/ComposerStashBadge.tsx | 2 +- .../src/components/chat/ComposerSurface.tsx | 20 ++--- .../components/chat/ComposerTasksBadge.tsx | 2 +- .../components/chat/ContextWindowMeter.tsx | 12 +-- .../components/chat/ExpandedImageDialog.tsx | 2 +- .../src/components/chat/MessagesTimeline.tsx | 44 +++++----- apps/web/src/components/chat/ModelListRow.tsx | 2 +- .../components/chat/ModelPickerSidebar.tsx | 8 +- .../components/chat/PanelLayoutControls.tsx | 2 +- .../src/components/chat/ProposedPlanCard.tsx | 2 +- .../components/chat/ProviderInstanceIcon.tsx | 6 +- .../chat/ProviderModelPicker.test.tsx | 2 +- .../components/chat/ProviderModelPicker.tsx | 6 +- .../chat/SnapShotAttachmentDetails.tsx | 8 +- .../src/components/chat/WorktreeSetupCard.tsx | 4 +- .../components/clerk/ClerkUserProfilePage.tsx | 4 +- .../clerk/MobileClientsUserProfilePage.tsx | 10 +-- .../clerk/T3ConnectUserProfilePage.tsx | 14 ++-- .../cloud/ConnectCliAuthSurface.tsx | 4 +- .../composerContextPresentation.tsx | 2 +- apps/web/src/components/contextChipParts.tsx | 8 +- .../components/device/DeviceStreamView.tsx | 2 +- .../components/device/DeviceToolsPanel.tsx | 2 +- .../diffs/DiffCommentAnnotation.tsx | 4 +- .../src/components/files/FilePreviewPanel.tsx | 2 +- .../components/files/fileSurfaceChrome.tsx | 2 +- .../components/onboarding/WelcomeWizard.tsx | 8 +- .../components/preview/AgentBrowserCursor.tsx | 2 +- .../src/components/preview/BrowserMockup.tsx | 6 +- .../components/preview/PreviewPanelShell.tsx | 2 +- .../pullRequest/PullRequestCodeTab.tsx | 4 +- .../pullRequest/PullRequestComposer.tsx | 2 +- .../pullRequest/PullRequestDetailPanel.tsx | 8 +- .../pullRequest/PullRequestLinkPreview.tsx | 2 +- .../pullRequest/PullRequestListRow.tsx | 8 +- .../components/pullRequest/PullRequestRow.tsx | 2 +- .../pullRequest/PullRequestSummaryTab.tsx | 4 +- .../pullRequest/PullRequestTimelineTab.tsx | 18 ++--- .../pullRequest/ThreadPullRequestsPanel.tsx | 2 +- .../pullRequest/pullRequestPresentation.tsx | 2 +- .../search/HighlightedSearchLine.tsx | 2 +- .../search/ProjectContentSearchDialog.tsx | 2 +- .../settings/AddProviderInstanceDialog.tsx | 8 +- .../settings/ConnectionsSettings.tsx | 20 ++--- .../components/settings/CustomModelEditor.tsx | 4 +- .../settings/DiagnosticsSettings.tsx | 20 ++--- .../components/settings/FontFamilyPicker.tsx | 4 +- .../settings/KeybindingsSettings.tsx | 16 ++-- .../settings/OpenSourceLicenses.tsx | 2 +- .../settings/PanelAnimationsPreview.tsx | 2 +- .../settings/ProjectActionsList.tsx | 4 +- .../settings/ProviderInstanceCard.test.ts | 2 +- .../settings/ProviderInstanceCard.tsx | 14 ++-- .../settings/ProviderModelsSection.tsx | 8 +- .../settings/ProviderSettingsForm.tsx | 2 +- .../settings/RedactedSensitiveText.tsx | 4 +- .../settings/ResourceTelemetryDiagnostics.tsx | 70 ++++++++-------- .../components/settings/SettingsPanels.tsx | 8 +- .../settings/SettingsSidebarNav.tsx | 2 +- .../settings/SnapShotSetupDialog.tsx | 8 +- .../settings/SourceControlSettings.tsx | 10 +-- .../components/settings/ThemeColorPicker.tsx | 8 +- .../components/settings/ThemeImportDialog.tsx | 8 +- .../src/components/settings/ThemeSettings.tsx | 10 +-- .../components/settings/ThemeWireframe.tsx | 4 +- .../components/settings/settingsLayout.tsx | 8 +- .../sidebar/SidebarProviderUpdatePill.tsx | 4 +- .../sidebar/SidebarThreadHeader.tsx | 2 +- .../components/sidebar/SidebarUpdatePill.tsx | 2 +- .../components/usage/UsageLimitsPooled.tsx | 10 +-- apps/web/src/components/usage/UsagePage.tsx | 2 +- .../components/usage/UsageProviderChart.tsx | 4 +- apps/web/src/index.css | 80 +++++++++++-------- apps/web/src/lib/utils.ts | 6 +- vite.config.ts | 40 ++++++++++ 109 files changed, 464 insertions(+), 433 deletions(-) diff --git a/apps/web/src/browser/BrowserDeviceToolbar.tsx b/apps/web/src/browser/BrowserDeviceToolbar.tsx index a8c9027f8a16..390c77de4424 100644 --- a/apps/web/src/browser/BrowserDeviceToolbar.tsx +++ b/apps/web/src/browser/BrowserDeviceToolbar.tsx @@ -175,7 +175,7 @@ export function BrowserDeviceToolbar({ }} > {width >= 560 ? ( - + Dimensions ) : null} diff --git a/apps/web/src/browser/HostedBrowserWebview.tsx b/apps/web/src/browser/HostedBrowserWebview.tsx index 6c303afb27e9..35044cd9c169 100644 --- a/apps/web/src/browser/HostedBrowserWebview.tsx +++ b/apps/web/src/browser/HostedBrowserWebview.tsx @@ -352,7 +352,7 @@ export function HostedBrowserWebview(props: { /> {activeDrag ? (
{agent.title} {role ? ( - + {role} ) : null} - + {agent.status === "completed" ? ( @@ -183,7 +183,7 @@ function AgentRow({ agent }: { agent: RuntimeSubagent }) { > {activity ?? statusLabel} - + {metadata.join(" · ")} {statusLabel} @@ -234,7 +234,7 @@ function PhaseRail({ group }: { group: AgentPanelWorkflowGroup }) { > {phase.members.length === 0 ? ( - – + – ) : ( phase.members.map((member) => ) )} @@ -281,7 +281,7 @@ function WorkflowScriptView({
- + {scriptPath.split("/").at(-1)} diff --git a/apps/web/src/components/WorkspaceBreadcrumb.tsx b/apps/web/src/components/WorkspaceBreadcrumb.tsx index 015e381aa251..2d5729cb7d15 100644 --- a/apps/web/src/components/WorkspaceBreadcrumb.tsx +++ b/apps/web/src/components/WorkspaceBreadcrumb.tsx @@ -33,7 +33,7 @@ export function WorkspaceBreadcrumbText({ children, className, ...props }: Compo // Center the capital letters with adjacent icons, not the font's leading. // Padding preserves accents and descenders when a label is truncated. className={cn( - "block min-w-0 truncate [text-box:trim-both_cap_alphabetic] supports-[text-box:trim-both_cap_alphabetic]:py-[0.5em]", + "block min-w-0 truncate [text-box:trim-both_cap_alphabetic] supports-[text-box:trim-both_cap_alphabetic]:py-1.5", className, )} {...props} diff --git a/apps/web/src/components/WorkspacePageHeader.tsx b/apps/web/src/components/WorkspacePageHeader.tsx index 5d98b80760ac..a484b4497539 100644 --- a/apps/web/src/components/WorkspacePageHeader.tsx +++ b/apps/web/src/components/WorkspacePageHeader.tsx @@ -16,9 +16,9 @@ export function WorkspacePageHeader({ return (
-

+

{APP_DISPLAY_NAME}

diff --git a/apps/web/src/components/chat/AssistantCitationChip.tsx b/apps/web/src/components/chat/AssistantCitationChip.tsx index d838c53d27d2..6baf14b18887 100644 --- a/apps/web/src/components/chat/AssistantCitationChip.tsx +++ b/apps/web/src/components/chat/AssistantCitationChip.tsx @@ -110,7 +110,7 @@ export function AssistantCitationChip({ const composerSourceLink = (