authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-22 12:22:10-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-22 12:22:10-07:00
log1a81ea8c153214ddc74b7046062a8957c2612e8d
tree178b0d82c8e5c09c92912643ed4f364f8d3a3769
parentc0490e9d0eb057218bfa5df3f25a7c26c37145a5
signature Signed by PGP key B5690EEEBB952194

refactor(web): fold repeated overrides into ui defaults (#13021)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

14 files changed, 23 insertions(+), 31 deletions(-)

apps/web/src/components/NoActiveThreadState.tsx+2-2
......@@ -22,8 +22,8 @@ export function NoActiveThreadState() {
2222 <Empty className="flex-1">
2323 <div className="w-full max-w-lg px-8 py-12">
2424 <EmptyHeader className="max-w-none">
25 <EmptyTitle className="text-foreground">Pick a thread to continue</EmptyTitle>
26 <EmptyDescription className="mt-2 text-muted-foreground/78">
25 <EmptyTitle>Pick a thread to continue</EmptyTitle>
26 <EmptyDescription>
2727 Select an existing thread or create a new one to get started.
2828 </EmptyDescription>
2929 </EmptyHeader>
apps/web/src/components/NoProjectsHero.tsx+2-6
......@@ -15,12 +15,8 @@ export function NoProjectsHero() {
1515 <Empty className="flex-1">
1616 <div className="w-full max-w-lg px-8 py-12">
1717 <EmptyHeader className="max-w-none">
18 <EmptyTitle className="text-foreground text-2xl sm:text-3xl">
19 What should we work on?
20 </EmptyTitle>
21 <EmptyDescription className="mt-2 text-muted-foreground/78">
22 Add a project to start your first thread.
23 </EmptyDescription>
18 <EmptyTitle className="text-2xl sm:text-3xl">What should we work on?</EmptyTitle>
19 <EmptyDescription>Add a project to start your first thread.</EmptyDescription>
2420 <div className="mt-6 flex justify-center">
2521 <Button size="sm" onClick={openAddProject}>
2622 <PlusIcon className="size-4" />
apps/web/src/components/ProjectScriptsControl.tsx+3-3
......@@ -157,7 +157,7 @@ export default function ProjectScriptsControl({
157157 onClick={() => void importFileScript(fileScript)}
158158 >
159159 <ScriptIcon icon={fileScript.icon ?? "play"} className="size-4" />
160 <MenuItemLabel className="truncate">{fileScript.name}</MenuItemLabel>
160 <MenuItemLabel>{fileScript.name}</MenuItemLabel>
161161 <MenuShortcut>
162162 <DownloadIcon className="size-3.5" aria-label="Import" />
163163 </MenuShortcut>
......@@ -182,7 +182,7 @@ export default function ProjectScriptsControl({
182182 onClick={() => onRunScript(script)}
183183 >
184184 <ScriptIcon icon={script.icon} className="size-4" />
185 <MenuItemLabel className="truncate">
185 <MenuItemLabel>
186186 {script.runOnWorktreeCreate ? `${script.name} (setup)` : script.name}
187187 </MenuItemLabel>
188188 <span className="relative ms-auto flex h-6 min-w-6 items-center justify-end">
......@@ -241,7 +241,7 @@ export default function ProjectScriptsControl({
241241 onClick={() => onRunScript(primaryScript)}
242242 >
243243 <ScriptIcon icon={primaryScript.icon} className="size-4" />
244 <MenuItemLabel className="truncate">Run {primaryScript.name}</MenuItemLabel>
244 <MenuItemLabel>Run {primaryScript.name}</MenuItemLabel>
245245 <MenuShortcut>
246246 {shortcutLabelForCommand(keybindings, commandForProjectScript(primaryScript.id))}
247247 </MenuShortcut>
apps/web/src/components/chat/OpenInPicker.tsx+1-1
......@@ -332,7 +332,7 @@ export const OpenInPicker = memo(function OpenInPicker({
332332 onClick={() => openInEditor(preferredEditor)}
333333 >
334334 <primaryOption.Icon className={cn("size-4", getOpenInIconClass(primaryOption.kind))} />
335 <MenuItemLabel className="truncate">Open in {primaryOption.label}</MenuItemLabel>
335 <MenuItemLabel>Open in {primaryOption.label}</MenuItemLabel>
336336 {openFavoriteEditorShortcutLabel && (
337337 <MenuShortcut>{openFavoriteEditorShortcutLabel}</MenuShortcut>
338338 )}
apps/web/src/components/chat/SnapShotAttachmentDetails.tsx+1-1
......@@ -170,7 +170,7 @@ export function SnapShotContentsButton({
170170 viewportClassName="max-h-[min(28rem,70vh)]"
171171 >
172172 <div className="space-y-2">
173 <PopoverTitle className="text-sm leading-5">Accessibility data</PopoverTitle>
173 <PopoverTitle>Accessibility data</PopoverTitle>
174174 {accessibilityDetails ? (
175175 <SnapShotAccessibilityData
176176 details={accessibilityDetails}
apps/web/src/components/device/DeviceToolVersions.tsx+1-1
......@@ -45,7 +45,7 @@ export function DeviceToolVersions({
4545 : "Versions"}
4646 </PopoverTrigger>
4747 <PopoverPopup align="end" className="w-80">
48 <PopoverTitle className="text-sm">{kind ? label : "Device tools"}</PopoverTitle>
48 <PopoverTitle>{kind ? label : "Device tools"}</PopoverTitle>
4949 {tools ? (
5050 <div className="mt-4 divide-y divide-border/50">
5151 {(
apps/web/src/components/pullRequest/PullRequestComposer.tsx+1-1
......@@ -131,7 +131,7 @@ export function PullRequestComposer({
131131 </Toggle>
132132 </ToggleGroup>
133133 ) : (
134 <PopoverTitle className="text-sm">
134 <PopoverTitle>
135135 {mode === "review" ? "Review pull request" : "Comment on pull request"}
136136 </PopoverTitle>
137137 )}
apps/web/src/components/pullRequest/PullRequestListFilters.tsx-1
......@@ -359,7 +359,6 @@ function PullRequestLabelFilter({
359359 return (
360360 <MenuCheckboxItem
361361 key={key}
362 className="grid-cols-[1rem_minmax(0,1fr)]"
363362 checked={checked}
364363 onCheckedChange={(next) =>
365364 onChange(
apps/web/src/components/ui/empty.tsx+1-1
......@@ -89,7 +89,7 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
8989 return (
9090 <div
9191 className={cn(
92 "text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
92 "text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1 [[data-slot=empty-description]+&]:mt-1",
9393 className,
9494 )}
9595 data-slot="empty-description"
apps/web/src/components/ui/menu.tsx+4-2
......@@ -117,7 +117,7 @@ function MenuItemLabel({ className, ...props }: React.ComponentProps<"span">) {
117117 <span
118118 data-slot="menu-item-label"
119119 className={cn(
120 "min-w-0 in-data-[density=touch]:[text-box:trim-both_cap_alphabetic] supports-[text-box:trim-both_cap_alphabetic]:in-data-[density=touch]:py-[0.5em]",
120 "min-w-0 truncate in-data-[density=touch]:[text-box:trim-both_cap_alphabetic] supports-[text-box:trim-both_cap_alphabetic]:in-data-[density=touch]:py-[0.5em]",
121121 className,
122122 )}
123123 {...props}
......@@ -139,7 +139,9 @@ function MenuCheckboxItem({
139139 checked={checked}
140140 className={cn(
141141 "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-pointer items-center gap-2 rounded-sm py-1 ps-2 text-base text-foreground outline-none data-disabled:pointer-events-none data-disabled:cursor-not-allowed data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
142 variant === "switch" ? "grid-cols-[1fr_auto] gap-4 pe-1.5" : "grid-cols-[1rem_1fr] pe-4",
142 variant === "switch"
143 ? "grid-cols-[1fr_auto] gap-4 pe-1.5"
144 : "grid-cols-[1rem_minmax(0,1fr)] pe-4",
143145 className,
144146 )}
145147 data-slot="menu-checkbox-item"
apps/web/src/components/ui/popover.tsx+1-1
......@@ -89,7 +89,7 @@ function PopoverClose({ ...props }: PopoverPrimitive.Close.Props) {
8989function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
9090 return (
9191 <PopoverPrimitive.Title
92 className={cn("font-semibold text-lg leading-none", className)}
92 className={cn("font-semibold text-sm leading-none", className)}
9393 data-slot="popover-title"
9494 {...props}
9595 />
apps/web/src/components/usage/UsagePage.tsx-1
......@@ -794,7 +794,6 @@ function UsageEnvironmentFilter({
794794 key={environment.environmentId}
795795 checked={checked}
796796 closeOnClick={false}
797 className="grid-cols-[1rem_minmax(0,1fr)]"
798797 onCheckedChange={(nextChecked) => {
799798 const next = new Set(selectedEnvironments.map((entry) => entry.environmentId));
800799 if (nextChecked) next.add(environment.environmentId);
apps/web/src/routes/_chat.index.tsx+5-9
......@@ -93,8 +93,8 @@ function DraftStartError({ onRetry }: { readonly onRetry: () => void }) {
9393 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none">
9494 <Empty className="flex-1">
9595 <EmptyHeader className="max-w-md">
96 <EmptyTitle className="text-foreground">Couldn’t start a new thread</EmptyTitle>
97 <EmptyDescription className="mt-2 text-muted-foreground/78">
96 <EmptyTitle>Couldn’t start a new thread</EmptyTitle>
97 <EmptyDescription>
9898 The project is still available. Try opening the draft again.
9999 </EmptyDescription>
100100 <div className="mt-5 flex justify-center">
......@@ -139,16 +139,12 @@ function HostedStaticOnboardingState() {
139139 <div className="mx-auto mb-5 flex size-11 items-center justify-center rounded-xl border border-border/70 bg-background/70 text-muted-foreground">
140140 <LinkIcon className="size-5" />
141141 </div>
142 <EmptyTitle className="text-foreground">
143 Connect to a computer running T3 Code
144 </EmptyTitle>
145 <EmptyDescription className="mt-2 leading-relaxed text-muted-foreground/78">
142 <EmptyTitle>Connect to a computer running T3 Code</EmptyTitle>
143 <EmptyDescription>
146144 This app connects to T3 Code running on your computer or a server. Start the T3 Code
147145 desktop app or command-line server on that machine and keep it running.
148146 </EmptyDescription>
149 <EmptyDescription className="mt-2 leading-relaxed text-muted-foreground/78">
150 {description}
151 </EmptyDescription>
147 <EmptyDescription>{description}</EmptyDescription>
152148 <div className="mt-6 flex justify-center">
153149 <Button render={<Link to="/settings/connections" />} size="sm">
154150 <PlusIcon className="size-4" />
scripts/lint-restyle-ceiling.ts+1-1
......@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";
88// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the
99// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you
1010// migrate a file, and delete this script when the rule becomes an error.
11export const RESTYLE_CEILING = 1184;
11export const RESTYLE_CEILING = 1165;
1212
1313const RULE = "shadcn(no-restyle)";
1414