authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-22 21:33:02-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-22 21:33:02-07:00
log71c9b693137c070b4887b365c68659f1a2fb7aed
treedec1bc67aab13caf78a8a3b757aeb262401aa4bf
parentf46522777372be1705e3b7a1ab08756f236db5d2
signature Signed by PGP key B5690EEEBB952194

refactor(web): Button consumers outside the composer stop restyling it (#13208)

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

38 files changed, 156 insertions(+), 220 deletions(-)

apps/web/src/browser/BrowserDeviceToolbar.tsx+18-23
......@@ -242,10 +242,7 @@ export function BrowserDeviceToolbar({
242242 onChange={(event) => updateCustomDimension("width", event.target.value)}
243243 aria-label="Viewport width"
244244 aria-invalid={!customValid}
245 className={cn(
246 "text-center [&_[data-slot=input]::-webkit-inner-spin-button]:appearance-none [&_[data-slot=input]]:[appearance:textfield]",
247 width >= 360 ? "w-14" : "w-13",
248 )}
245 className={width >= 360 ? "w-14" : "w-13"}
249246 />
250247 <span className="text-xs text-muted-foreground">×</span>
251248 <Input
......@@ -270,10 +267,7 @@ export function BrowserDeviceToolbar({
270267 onChange={(event) => updateCustomDimension("height", event.target.value)}
271268 aria-label="Viewport height"
272269 aria-invalid={!customValid}
273 className={cn(
274 "text-center [&_[data-slot=input]::-webkit-inner-spin-button]:appearance-none [&_[data-slot=input]]:[appearance:textfield]",
275 width >= 360 ? "w-14" : "w-13",
276 )}
270 className={width >= 360 ? "w-14" : "w-13"}
277271 />
278272 </form>
279273
......@@ -281,14 +275,13 @@ export function BrowserDeviceToolbar({
281275 <TooltipTrigger
282276 render={
283277 <Button
284 variant="ghost"
278 variant={aspectRatio === null ? "ghost" : "secondary"}
285279 size="icon-xs"
286280 type="button"
287281 aria-label={
288282 aspectRatio === null ? "Lock viewport aspect ratio" : "Unlock viewport aspect ratio"
289283 }
290284 aria-pressed={aspectRatio !== null}
291 className={cn(aspectRatio !== null && "bg-accent text-foreground")}
292285 disabled={pending || !customValid}
293286 onPointerDown={(event) => event.preventDefault()}
294287 onClick={toggleAspectRatio}
......@@ -315,19 +308,21 @@ export function BrowserDeviceToolbar({
315308 >
316309 <ScreenRotationIcon />
317310 </Button>
318 <Button
319 variant="ghost"
320 size="icon-xs"
321 type="button"
322 aria-label="Close device toolbar"
323 className="sticky right-0 ml-auto bg-background/95"
324 disabled={pending}
325 onClick={() => {
326 apply({ _tag: "fill" }, null);
327 }}
328 >
329 <X />
330 </Button>
311 {/* Sticky backing so scrolled controls do not show through the close action. */}
312 <span className="sticky right-0 ml-auto flex bg-background/95">
313 <Button
314 variant="ghost"
315 size="icon-xs"
316 type="button"
317 aria-label="Close device toolbar"
318 disabled={pending}
319 onClick={() => {
320 apply({ _tag: "fill" }, null);
321 }}
322 >
323 <X />
324 </Button>
325 </span>
331326 </div>
332327 );
333328}
apps/web/src/components/ChatMarkdown.tsx+4-8
......@@ -784,9 +784,8 @@ function MarkdownTable({ children, ...props }: React.ComponentProps<"table">) {
784784 render={
785785 <Button
786786 type="button"
787 variant="ghost"
787 variant={expanded ? "secondary" : "ghost-muted"}
788788 size="icon-xs"
789 className="chat-markdown-chrome-action"
790789 aria-pressed={expanded}
791790 onClick={toggleExpanded}
792791 aria-label={expandLabel}
......@@ -805,9 +804,8 @@ function MarkdownTable({ children, ...props }: React.ComponentProps<"table">) {
805804 render={
806805 <Button
807806 type="button"
808 variant="ghost"
807 variant="ghost-muted"
809808 size="icon-xs"
810 className="chat-markdown-chrome-action"
811809 aria-label={copyLabel}
812810 />
813811 }
......@@ -993,9 +991,8 @@ function MarkdownCodeBlock({
993991 render={
994992 <Button
995993 type="button"
996 variant="ghost"
994 variant={wrapped ? "secondary" : "ghost-muted"}
997995 size="icon-xs"
998 className="chat-markdown-chrome-action"
999996 aria-pressed={wrapped}
1000997 onClick={() => setWrapped((value) => !value)}
1001998 aria-label={wrapLabel}
......@@ -1011,9 +1008,8 @@ function MarkdownCodeBlock({
10111008 render={
10121009 <Button
10131010 type="button"
1014 variant="ghost"
1011 variant="ghost-muted"
10151012 size="icon-xs"
1016 className="chat-markdown-chrome-action"
10171013 onClick={handleCopy}
10181014 aria-label={copyLabel}
10191015 />
apps/web/src/components/ChatView.tsx+1-1
......@@ -9991,7 +9991,7 @@ export default function ChatView(props: ChatViewProps) {
99919991 composerRef.current?.restoreAfterTimelineReachedEnd();
99929992 scrollToEnd(true);
99939993 }}
9994 className="pointer-events-auto gap-1.5 rounded-full px-3 text-muted-foreground hover:text-foreground"
9994 className="pointer-events-auto"
99959995 size="xs"
99969996 variant="glass"
99979997 >
apps/web/src/components/CommandPalette.tsx+4-8
......@@ -1528,9 +1528,8 @@ function OpenCommandPaletteDialog(props: {
15281528 <TooltipTrigger
15291529 render={
15301530 <Button
1531 variant="outline"
1532 size="xs"
1533 className="h-5 rounded-[.25rem] px-1.5 text-[10px] text-warning-foreground"
1531 variant="warning-outline"
1532 size="micro"
15341533 onClick={() => {
15351534 openSourceControlSettings();
15361535 }}
......@@ -2861,7 +2860,7 @@ function OpenCommandPaletteDialog(props: {
28612860 variant="outline"
28622861 size="xs"
28632862 tabIndex={-1}
2864 className="absolute inset-e-2.5 top-1/2 gap-1.5 pe-1 ps-2 -translate-y-1/2"
2863 className="absolute inset-e-2.5 top-1/2 -translate-y-1/2"
28652864 aria-label={`${remoteProjectButtonLabel ?? "Continue"} (Enter)`}
28662865 disabled={!canSubmitRemoteProjectFlow}
28672866 onMouseDown={(event) => {
......@@ -2888,10 +2887,7 @@ function OpenCommandPaletteDialog(props: {
28882887 variant="outline"
28892888 size="xs"
28902889 tabIndex={-1}
2891 className={cn(
2892 "absolute inset-e-2.5 top-1/2 pe-1 ps-2 -translate-y-1/2",
2893 hasHighlightedBrowseItem ? "gap-1" : "gap-1.5",
2894 )}
2890 className="absolute inset-e-2.5 top-1/2 -translate-y-1/2"
28952891 aria-label={`${submitActionLabel} (${addShortcutLabel})`}
28962892 disabled={
28972893 !canCreateProjectInEnvironment(browseEnvironment?.connection.phase) ||
apps/web/src/components/CustomSnoozeDialog.tsx+1-1
......@@ -119,7 +119,7 @@ function CustomSnoozeDialog() {
119119 <Button
120120 id={`${id}-date`}
121121 variant="outline"
122 className="w-full justify-between font-normal"
122 className="w-full justify-between"
123123 />
124124 }
125125 >
apps/web/src/components/DiffPanel.tsx+7-6
......@@ -1125,10 +1125,7 @@ export default function DiffPanel({
11251125 <Button
11261126 size="icon-micro"
11271127 variant="ghost"
1128 className={cn(
1129 "-ms-0.5 [--control-icon-color:currentColor] bg-transparent hover:bg-foreground/10",
1130 getDiffCollapseIconClassName(fileDiff),
1131 )}
1128 className="-ms-0.5"
11321129 aria-label={
11331130 collapsed ? `Expand ${filePath}` : `Collapse ${filePath}`
11341131 }
......@@ -1142,9 +1139,13 @@ export default function DiffPanel({
11421139 }
11431140 >
11441141 {collapsed ? (
1145 <ChevronRightIcon className="size-4" />
1142 <ChevronRightIcon
1143 className={cn("size-4", getDiffCollapseIconClassName(fileDiff))}
1144 />
11461145 ) : (
1147 <ChevronDownIcon className="size-4" />
1146 <ChevronDownIcon
1147 className={cn("size-4", getDiffCollapseIconClassName(fileDiff))}
1148 />
11481149 )}
11491150 </TooltipTrigger>
11501151 <TooltipPopup side="top">
apps/web/src/components/GitActionsControl.tsx+7-16
......@@ -646,9 +646,8 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) {
646646 <TooltipTrigger
647647 render={
648648 <Button
649 variant="outline"
650 size="xs"
651 className="h-5 rounded-[.25rem] px-1.5 text-[10px] text-warning-foreground"
649 variant="warning-outline"
650 size="micro"
652651 onClick={(event) => {
653652 event.preventDefault();
654653 event.stopPropagation();
......@@ -1799,14 +1798,7 @@ export default function GitActionsControl({
17991798 <Popover>
18001799 <PopoverTrigger
18011800 openOnHover
1802 render={
1803 <Button
1804 aria-disabled="true"
1805 className="cursor-not-allowed rounded-e-none border-e-0 ps-[8.5px] opacity-64 before:rounded-e-none"
1806 size="xs"
1807 variant="outline"
1808 />
1809 }
1801 render={<Button aria-disabled="true" size="xs" variant="outline" />}
18101802 >
18111803 <GitQuickActionIcon
18121804 quickAction={quickAction}
......@@ -1824,7 +1816,6 @@ export default function GitActionsControl({
18241816 <Button
18251817 variant="outline"
18261818 size="xs"
1827 className="ps-[8.5px]"
18281819 disabled={isGitActionRunning || quickAction.disabled}
18291820 onClick={runQuickAction}
18301821 >
......@@ -2056,16 +2047,16 @@ export default function GitActionsControl({
20562047 Abort
20572048 </Button>
20582049 <Button
2059 className="min-h-8 w-full max-w-full whitespace-normal py-1.5 leading-snug sm:min-h-7 sm:w-auto"
2050 className="w-full max-w-full sm:w-auto"
20602051 variant="outline"
2061 size="sm"
2052 size="sm-multiline"
20622053 onClick={continuePendingDefaultBranchAction}
20632054 >
20642055 {pendingDefaultBranchActionCopy?.continueLabel ?? "Continue"}
20652056 </Button>
20662057 <Button
2067 className="min-h-8 w-full max-w-full whitespace-normal py-1.5 leading-snug sm:min-h-7 sm:w-auto"
2068 size="sm"
2058 className="w-full max-w-full sm:w-auto"
2059 size="sm-multiline"
20692060 onClick={checkoutFeatureBranchAndContinuePendingAction}
20702061 >
20712062 Check out feature branch & continue
apps/web/src/components/ProjectScriptsControl.tsx+23-19
......@@ -192,24 +192,28 @@ export default function ProjectScriptsControl({
192192 <MenuShortcut className="ms-0">{shortcutLabel}</MenuShortcut>
193193 </span>
194194 ))}
195 <Button
196 type="button"
197 variant="ghost"
198 size="icon-xs"
199 className={`absolute right-0 top-1/2 size-6 -translate-y-1/2 ${presentation === "menu" ? "" : "opacity-0 pointer-events-none transition-opacity group-hover:opacity-100 group-hover:pointer-events-auto group-focus-visible:opacity-100 group-focus-visible:pointer-events-auto"}`}
200 aria-label={`Edit ${script.name}`}
201 onPointerDown={(event) => {
202 event.preventDefault();
203 event.stopPropagation();
204 }}
205 onClick={(event) => {
206 event.preventDefault();
207 event.stopPropagation();
208 openEditDialog(script);
209 }}
195 <span
196 className={`absolute right-0 top-1/2 flex -translate-y-1/2 ${presentation === "menu" ? "" : "opacity-0 pointer-events-none transition-opacity group-hover:opacity-100 group-hover:pointer-events-auto group-focus-visible:opacity-100 group-focus-visible:pointer-events-auto"}`}
210197 >
211 <SettingsIcon className="size-3.5" />
212 </Button>
198 <Button
199 type="button"
200 variant="ghost"
201 size="icon-xs"
202 className="size-6"
203 aria-label={`Edit ${script.name}`}
204 onPointerDown={(event) => {
205 event.preventDefault();
206 event.stopPropagation();
207 }}
208 onClick={(event) => {
209 event.preventDefault();
210 event.stopPropagation();
211 openEditDialog(script);
212 }}
213 >
214 <SettingsIcon className="size-3.5" />
215 </Button>
216 </span>
213217 </span>
214218 </MenuItem>
215219 );
......@@ -269,7 +273,7 @@ export default function ProjectScriptsControl({
269273 <Button
270274 size="xs"
271275 variant="outline"
272 className="w-7 px-0 sm:w-6 @3xl/header-actions:w-auto! @3xl/header-actions:px-[calc(--spacing(2)-1px)]"
276 className="w-7 sm:w-6 @3xl/header-actions:w-auto!"
273277 aria-label={`Run ${primaryScript.name}`}
274278 // The tooltip wrapper replaces data-slot="button", so themed
275279 // toolbar styling needs its own hook.
......@@ -329,7 +333,7 @@ export default function ProjectScriptsControl({
329333 <Button
330334 size="xs"
331335 variant="outline"
332 className="w-7 px-0 sm:w-6 @3xl/header-actions:w-auto! @3xl/header-actions:px-[calc(--spacing(2)-1px)]"
336 className="w-7 sm:w-6 @3xl/header-actions:w-auto!"
333337 aria-label="Add action"
334338 // The tooltip wrapper replaces data-slot="button", so themed
335339 // toolbar styling needs its own hook.
apps/web/src/components/ServerUpdateAction.tsx+2-2
......@@ -270,8 +270,8 @@ export function ServerUpdateAction({
270270 render={
271271 <Button
272272 size="icon-xs"
273 variant="ghost"
274 className={className ?? "text-muted-foreground hover:text-foreground"}
273 variant="ghost-muted"
274 className={className}
275275 aria-label={`${actionLabel} for ${serverLabel}`}
276276 onClick={onClick}
277277 />
apps/web/src/components/Sidebar.tsx+1-1
......@@ -4500,7 +4500,7 @@ export default function Sidebar() {
45004500 tabIndex={-1}
45014501 aria-hidden="true"
45024502 title={`Project settings for ${project.displayName}`}
4503 className="ml-auto focus-visible:bg-accent focus-visible:text-foreground"
4503 className="ml-auto"
45044504 onPointerDown={(event) => event.stopPropagation()}
45054505 onClick={(event) => {
45064506 void handleProjectSettings(event, project);
apps/web/src/components/chat/AssistantSelectionToolbar.tsx+1-1
......@@ -134,7 +134,7 @@ export function AssistantSelectionToolbar({
134134 variant="glass"
135135 disabled={tooLong}
136136 aria-label={tooLong ? "Selection is too long to cite" : "Cite selection in composer"}
137 className="fixed z-50 max-w-[calc(100vw-1rem)] rounded-full px-2.5"
137 className="fixed z-50 max-w-[calc(100vw-1rem)]"
138138 style={{ left: selection.position.x, top: selection.position.y }}
139139 onPointerDown={(event) => event.preventDefault()}
140140 onClick={cite}
apps/web/src/components/chat/ContextWindowMeter.tsx+1-1
......@@ -45,7 +45,7 @@ export function ContextWindowMeter(props: {
4545 <Button
4646 size="icon-sm"
4747 variant="ghost-muted"
48 className="size-7 rounded-full hover:text-muted-foreground data-pressed:text-muted-foreground"
48 className="size-7"
4949 aria-label={
5050 usage.maxTokens !== null && usedPercentage
5151 ? `Context window ${usedPercentage} used`
apps/web/src/components/chat/ExpandedImageDialog.tsx+4-9
......@@ -193,7 +193,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
193193 type="button"
194194 size="icon"
195195 variant="media-navigation"
196 className="left-0 top-auto -bottom-12 translate-y-0 rounded-full bg-white/10 sm:top-1/2 sm:bottom-auto sm:-translate-y-1/2"
196 className="left-0 top-auto -bottom-12 translate-y-0 sm:top-1/2 sm:bottom-auto sm:-translate-y-1/2"
197197 aria-label="Previous media"
198198 onClick={() => navigateImage(-1)}
199199 >
......@@ -252,12 +252,11 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
252252 <Button
253253 aria-label={contentsLabel}
254254 aria-pressed={showingAccessibilityDetails}
255 className="[--control-icon-color:currentColor] hover:bg-white/10 hover:text-white"
256255 onClick={() =>
257256 setAccessibilityDetailsSrc(showingAccessibilityDetails ? null : item.src)
258257 }
259258 size="icon-micro"
260 variant="ghost-muted"
259 variant="overlay"
261260 />
262261 }
263262 >
......@@ -266,11 +265,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
266265 <TooltipPopup side="top">{contentsLabel}</TooltipPopup>
267266 </Tooltip>
268267 ) : item.source ? (
269 <SnapShotContentsButton
270 source={item.source}
271 side="top"
272 className="hover:bg-white/10 hover:text-white"
273 />
268 <SnapShotContentsButton source={item.source} side="top" />
274269 ) : null}
275270 </div>
276271 </div>
......@@ -280,7 +275,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
280275 type="button"
281276 size="icon"
282277 variant="media-navigation"
283 className="right-0 top-auto -bottom-12 translate-y-0 rounded-full bg-white/10 sm:top-1/2 sm:bottom-auto sm:-translate-y-1/2"
278 className="right-0 top-auto -bottom-12 translate-y-0 sm:top-1/2 sm:bottom-auto sm:-translate-y-1/2"
284279 aria-label="Next media"
285280 onClick={() => navigateImage(1)}
286281 >
apps/web/src/components/chat/MessageCopyButton.tsx+2-3
......@@ -2,7 +2,6 @@ import { memo, useRef } from "react";
22import { CopyIcon, CheckIcon } from "lucide-react";
33import { Button } from "../ui/button";
44import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
5import { cn } from "~/lib/utils";
65import {
76 ANCHORED_COPY_TOAST_TIMEOUT_MS,
87 showAnchoredCopyErrorToast,
......@@ -43,8 +42,8 @@ export const MessageCopyButton = memo(function MessageCopyButton({
4342 ref={ref}
4443 type="button"
4544 size={size}
46 variant={variant}
47 className={cn("text-muted-foreground hover:text-foreground", className)}
45 variant={variant === "ghost" ? "ghost-muted" : variant}
46 className={className}
4847 />
4948 }
5049 >
apps/web/src/components/chat/MessagesTimeline.tsx+2-2
......@@ -3956,11 +3956,11 @@ const CollapsibleUserMessageBody = memo(function CollapsibleUserMessageBody(prop
39563956 <Button
39573957 type="button"
39583958 size="xs"
3959 variant="ghost"
3959 variant="ghost-muted"
39603960 aria-expanded={expanded}
39613961 data-scroll-anchor-ignore
39623962 onClick={() => setExpanded((value) => !value)}
3963 className="-ml-1 h-6 rounded-md px-1.5 text-secondary-label text-xs hover:bg-muted/55 hover:text-message-foreground"
3963 className="-ml-1"
39643964 >
39653965 {expanded ? "Show less" : "Show full message"}
39663966 </Button>
apps/web/src/components/chat/OpenInPicker.tsx-1
......@@ -353,7 +353,6 @@ export const OpenInPicker = memo(function OpenInPicker({
353353 <Group aria-label="Open in editor">
354354 <Button
355355 aria-label={compact ? "Open file in preferred editor" : undefined}
356 className="ps-[8.5px]"
357356 size="xs"
358357 variant="outline"
359358 disabled={!preferredEditor || !openInCwd || remote.mode === "remote-unavailable"}
apps/web/src/components/chat/SnapShotAttachmentDetails.tsx+2-5
......@@ -153,7 +153,7 @@ export function SnapShotContentsButton({
153153 className={className}
154154 onClick={(event) => event.stopPropagation()}
155155 size="icon-micro"
156 variant="ghost-muted"
156 variant="overlay"
157157 />
158158 }
159159 />
......@@ -211,10 +211,7 @@ export function SnapShotAttachmentDetails({
211211 <div className="min-w-0 flex-1">
212212 <div className="flex min-w-0 items-center gap-1.5 text-[11px] font-medium leading-3.5 text-white">
213213 <span className="truncate">{source.appName}</span>
214 <SnapShotContentsButton
215 source={source}
216 className="pointer-events-auto text-white/60 hover:bg-white/10 hover:text-white focus-visible:ring-white/70"
217 />
214 <SnapShotContentsButton source={source} className="pointer-events-auto" />
218215 </div>
219216 <div className="truncate text-[9px] leading-3.5 text-white/70">
220217 {source.windowTitle || "Captured window"}
apps/web/src/components/diffs/DiffCommentAnnotation.tsx+10-9
......@@ -67,15 +67,16 @@ export function DiffCommentAnnotation({
6767 <MessageCircle className="mt-0.5 size-3.5 shrink-0 text-primary/70" aria-hidden="true" />
6868 <p className="min-w-0 flex-1 whitespace-pre-wrap text-[13px] leading-5">{displayedText}</p>
6969 {onDelete ? (
70 <Button
71 className="-my-1 -mr-1 shrink-0 opacity-0 transition-opacity group-hover/comment:opacity-100 focus-visible:opacity-100 max-sm:opacity-100"
72 variant="ghost-muted"
73 size="icon-xs"
74 aria-label="Delete comment"
75 onClick={onDelete}
76 >
77 <Trash2 className="size-3" />
78 </Button>
70 <span className="-my-1 -mr-1 flex shrink-0 opacity-0 transition-opacity group-hover/comment:opacity-100 focus-within:opacity-100 max-sm:opacity-100">
71 <Button
72 variant="ghost-muted"
73 size="icon-xs"
74 aria-label="Delete comment"
75 onClick={onDelete}
76 >
77 <Trash2 className="size-3" />
78 </Button>
79 </span>
7980 ) : null}
8081 </div>
8182 );
apps/web/src/components/onboarding/WelcomeWizard.tsx+5-7
......@@ -357,12 +357,13 @@ function ConnectionStep({
357357 render={
358358 <Button
359359 variant="ghost"
360 className="h-auto min-h-14 w-full justify-start gap-3 px-3 py-3 text-left whitespace-normal sm:h-auto"
360 size="sm-multiline"
361 className="min-h-14 w-full justify-start"
361362 />
362363 }
363364 >
364365 <LinkIcon className="size-4 text-muted-foreground" />
365 <span className="flex-1">Add a computer</span>
366 <span className="flex-1 text-left">Add a computer</span>
366367 <ChevronRightIcon
367368 className={cn("size-4 text-muted-foreground", pairingOpen && "rotate-90")}
368369 />
......@@ -429,14 +430,11 @@ function ConnectAccountOption({
429430 }
430431 }}
431432 render={
432 <Button
433 variant="ghost"
434 className="h-auto min-h-14 w-full justify-start gap-3 px-3 py-3 text-left whitespace-normal sm:h-auto"
435 />
433 <Button variant="ghost" size="sm-multiline" className="min-h-14 w-full justify-start" />
436434 }
437435 >
438436 <CloudIcon className="size-4 text-muted-foreground" />
439 <span className="flex-1">T3 Connect</span>
437 <span className="flex-1 text-left">T3 Connect</span>
440438 <span className="text-xs text-muted-foreground">
441439 {!isLoaded
442440 ? "Loading sign-in…"
apps/web/src/components/preview/PreviewMoreMenu.tsx-1
......@@ -185,7 +185,6 @@ export function PreviewMoreMenu({
185185 type="button"
186186 onClick={callTab(bridge.resetZoom)}
187187 aria-label="Reset zoom"
188 className="[:hover,[data-pressed]]:bg-foreground/10"
189188 disabled={tabDisabled}
190189 >
191190 <RotateCcw />
apps/web/src/components/projectScriptEditor.tsx+1-1
......@@ -319,7 +319,7 @@ export function ProjectScriptEditorDialog({
319319 <Button
320320 type="button"
321321 variant="outline"
322 className="size-9 shrink-0 hover:bg-popover active:bg-popover data-pressed:bg-popover data-pressed:shadow-xs/5 data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:border-transparent dark:bg-white/[0.035] dark:data-pressed:before:shadow-none"
322 className="size-9 shrink-0"
323323 aria-label="Choose icon"
324324 />
325325 }
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+1-1
......@@ -785,7 +785,7 @@ function PullRequestCodeTab({
785785 variant="ghost-muted"
786786 aria-expanded={!collapsed}
787787 aria-label={collapsed ? "Expand diff" : "Collapse diff"}
788 className="mr-1 rounded hover:bg-transparent"
788 className="mr-1"
789789 onClick={(event) => {
790790 event.stopPropagation();
791791 toggleFile(item.id);
apps/web/src/components/pullRequest/PullRequestComposer.tsx+1-7
......@@ -78,13 +78,7 @@ export function PullRequestComposer({
7878 }}
7979 >
8080 <PopoverTrigger
81 render={
82 <Button
83 size="icon"
84 variant="glass"
85 className="rounded-full shadow-lg [--glass-opacity:50%]"
86 />
87 }
81 render={<Button size="icon" variant="glass" />}
8882 // The only label this control has, so the pending count belongs in it: the badge beside
8983 // the icon is decorative and a reader who cannot see it still needs the number.
9084 aria-label={
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+1-2
......@@ -2662,8 +2662,7 @@ export function PullRequestDetailPanel({
26622662 </PullRequestMetaLine>
26632663 <Button
26642664 size="xs"
2665 variant="ghost"
2666 className="h-7 px-2 text-[10px] text-muted-foreground"
2665 variant="ghost-muted"
26672666 aria-label={
26682667 timelineOrder === "newest"
26692668 ? "Show oldest activity first"
apps/web/src/components/pullRequest/PullRequestEditButton.tsx+6-7
......@@ -12,16 +12,15 @@ export function PullRequestEditButton({
1212 "aria-label": string;
1313}) {
1414 return (
15 <Button
16 {...props}
17 size="icon-xs"
18 variant="ghost"
15 <span
1916 className={cn(
20 "shrink-0 text-muted-foreground opacity-0 transition-opacity pointer-coarse:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none",
17 "flex shrink-0 opacity-0 transition-opacity pointer-coarse:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 focus-within:opacity-100 motion-reduce:transition-none",
2118 className,
2219 )}
2320 >
24 <PencilIcon aria-hidden className="size-3" />
25 </Button>
21 <Button {...props} size="icon-xs" variant="ghost-muted">
22 <PencilIcon aria-hidden className="size-3" />
23 </Button>
24 </span>
2625 );
2726}
apps/web/src/components/pullRequest/PullRequestReviewAnnotation.tsx+1-7
......@@ -312,7 +312,6 @@ export function ReviewThreadCard({
312312 <Button
313313 size="xs"
314314 variant="ghost"
315 className="px-1"
316315 disabled={loadingMore}
317316 onClick={() => void loadMore()}
318317 >
......@@ -352,12 +351,7 @@ export function ReviewThreadCard({
352351 </div>
353352 </div>
354353 ) : (
355 <Button
356 size="xs"
357 variant="ghost"
358 className="mt-2 px-1"
359 onClick={() => setReplying(true)}
360 >
354 <Button size="xs" variant="ghost" className="mt-2" onClick={() => setReplying(true)}>
361355 Reply
362356 </Button>
363357 )
apps/web/src/components/pullRequest/PullRequestSummaryTab.tsx+2-2
......@@ -922,8 +922,8 @@ export function PullRequestSummaryTab({
922922 actions={
923923 <Button
924924 size="xs"
925 variant="ghost"
926 className="h-7 shrink-0 px-2 text-[10px] text-muted-foreground"
925 variant="ghost-muted"
926 className="shrink-0"
927927 aria-label={
928928 commentOrder === "newest"
929929 ? "Show oldest comments first"
apps/web/src/components/settings/ConnectionsSettings.tsx+2-11
......@@ -3680,11 +3680,7 @@ export function ConnectionsSettings() {
36803680 headerAction={
36813681 <div className="flex items-center gap-1">
36823682 {savedServerUpdateTargets.length > 0 ? (
3683 <ServerUpdatesAction
3684 targets={savedServerUpdateTargets}
3685 variant="ghost"
3686 className="font-normal text-muted-foreground/60 hover:text-muted-foreground"
3687 />
3683 <ServerUpdatesAction targets={savedServerUpdateTargets} variant="ghost-muted" />
36883684 ) : null}
36893685 <Dialog
36903686 open={addBackendDialogOpen}
......@@ -3700,12 +3696,7 @@ export function ConnectionsSettings() {
37003696 render={
37013697 <DialogTrigger
37023698 render={
3703 <Button
3704 size="xs"
3705 variant="ghost"
3706 className="font-normal text-muted-foreground/60 hover:text-muted-foreground"
3707 aria-label="Add environment"
3708 >
3699 <Button size="xs" variant="ghost-muted" aria-label="Add environment">
37093700 <PlusIcon className="size-3" />
37103701 <span>Add environment</span>
37113702 </Button>
apps/web/src/components/settings/KeybindingsSettings.tsx+2-2
......@@ -891,12 +891,12 @@ function WhenClauseControl({
891891 <Button
892892 variant={expression ? "ghost" : "ghost-muted"}
893893 size="micro"
894 className="min-w-0 shrink font-mono"
894 className="min-w-0 shrink"
895895 />
896896 }
897897 aria-label={`Edit when clause for ${label}`}
898898 >
899 <span className="truncate">{expression || "Always"}</span>
899 <span className="truncate font-mono">{expression || "Always"}</span>
900900 <ChevronDownIcon className="size-3.5 shrink-0 opacity-60" />
901901 </PopoverTrigger>
902902 <PopoverContent align="start" sideOffset={6}>
apps/web/src/components/settings/ProjectActionsList.tsx+11-10
......@@ -51,16 +51,17 @@ export function ProjectActionsList({
5151 {shortcutLabel ? (
5252 <span className="text-xs text-muted-foreground">{shortcutLabel}</span>
5353 ) : null}
54 <Button
55 size="icon-xs"
56 variant="ghost-muted"
57 className="shrink-0 opacity-0 group-focus-within:opacity-100 group-hover:opacity-100"
58 aria-label={`Edit ${script.name}`}
59 disabled={disabled}
60 onClick={() => onEdit(script)}
61 >
62 <SettingsIcon className="size-3.5" />
63 </Button>
54 <span className="flex shrink-0 opacity-0 group-focus-within:opacity-100 group-hover:opacity-100">
55 <Button
56 size="icon-xs"
57 variant="ghost-muted"
58 aria-label={`Edit ${script.name}`}
59 disabled={disabled}
60 onClick={() => onEdit(script)}
61 >
62 <SettingsIcon className="size-3.5" />
63 </Button>
64 </span>
6465 </>
6566 }
6667 />
apps/web/src/components/settings/ProviderAccentColorPicker.tsx+17-15
......@@ -92,21 +92,23 @@ function ProviderCustomColorPicker(props: {
9292 />
9393 <PopoverPopup side="bottom" align="start" sideOffset={6} padding="none">
9494 <ProviderCustomColorPanel value={normalized} onCommit={props.onCommit} />
95 <PopoverClose
96 render={
97 <Button
98 type="button"
99 size="sm"
100 variant="ghost"
101 className="h-8 w-full justify-start rounded-none border-t border-border/60 px-3 text-xs text-muted-foreground [--control-icon-color:currentColor]"
102 onClick={props.onClear}
103 disabled={!props.value}
104 >
105 <XIcon className="size-3.5" aria-hidden />
106 Clear color
107 </Button>
108 }
109 />
95 <div className="border-t border-border/60 p-1">
96 <PopoverClose
97 render={
98 <Button
99 type="button"
100 size="compact"
101 variant="ghost-muted"
102 className="w-full justify-start"
103 onClick={props.onClear}
104 disabled={!props.value}
105 >
106 <XIcon aria-hidden />
107 Clear color
108 </Button>
109 }
110 />
111 </div>
110112 </PopoverPopup>
111113 </Popover>
112114 );
apps/web/src/components/settings/SettingsSidebarNav.tsx+2-2
......@@ -265,8 +265,8 @@ export function SettingsSidebarNav({ pathname }: { pathname: string }) {
265265 <Button
266266 type="button"
267267 size="icon-micro"
268 variant="ghost"
269 className="shrink-0 text-sidebar-muted-foreground hover:bg-sidebar-control-surface hover:text-sidebar-foreground"
268 variant="ghost-muted"
269 className="shrink-0"
270270 aria-label="Clear settings search"
271271 onClick={() => {
272272 clearSearch();
apps/web/src/components/sidebar/SidebarProviderUpdatePill.tsx+4-6
......@@ -11,7 +11,6 @@ import {
1111 type ProviderUpdateSidebarPillView,
1212} from "../ProviderUpdateLaunchNotification.logic";
1313import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
14import { Button } from "../ui/button";
1514
1615const PROVIDER_UPDATE_PILL_STYLES = {
1716 loading:
......@@ -192,15 +191,14 @@ export function SidebarProviderUpdatePill() {
192191 <Tooltip>
193192 <TooltipTrigger
194193 render={
195 <Button
196 size="icon-micro"
197 variant="ghost"
194 <button
195 type="button"
198196 aria-label="Dismiss provider update notice"
199 className="relative z-[1] mr-1 [--control-icon-color:currentColor] rounded-md text-inherit opacity-70 hover:bg-transparent hover:opacity-100"
197 className="relative z-[1] mr-1 flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-md opacity-70 outline-none hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring"
200198 onClick={() => startExit(displayedView.key, null, displayedView.key)}
201199 >
202200 <XIcon className="size-3.5 shrink-0" />
203 </Button>
201 </button>
204202 }
205203 />
206204 <TooltipPopup side="top">Dismiss until provider status changes</TooltipPopup>
apps/web/src/components/sidebar/SidebarThreadHeader.tsx+2-2
......@@ -108,8 +108,8 @@ export function SidebarThreadHeader({
108108 <Button
109109 type="button"
110110 size="icon-micro"
111 variant="ghost"
112 className="shrink-0 text-sidebar-muted-foreground hover:bg-sidebar-control-surface hover:text-sidebar-foreground"
111 variant="ghost-muted"
112 className="shrink-0"
113113 aria-label="Clear thread search"
114114 onClick={() => {
115115 onClearSearch();
apps/web/src/components/ui/button.tsx+2-2
......@@ -8,7 +8,7 @@ import type * as React from "react";
88import { cn } from "~/lib/utils";
99
1010const buttonVariants = cva(
11 "[--control-icon-color:currentColor] [&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-[var(--control-radius)] border font-medium text-base outline-none transition-[box-shadow,scale] [&:active:not([aria-haspopup])]:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--control-radius)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 sm:text-sm [&_svg:not([class*='text-'])]:text-[var(--control-icon-color)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
11 "[--control-icon-color:currentColor] [&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-[var(--control-radius)] border font-medium text-base outline-none transition-[box-shadow,scale] [&:active:not([aria-haspopup])]:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--control-radius)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 aria-disabled:cursor-not-allowed aria-disabled:opacity-64 sm:text-sm [&_svg:not([class*='text-'])]:text-[var(--control-icon-color)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1212 {
1313 defaultVariants: {
1414 size: "default",
......@@ -52,7 +52,7 @@ const buttonVariants = cva(
5252 "ghost-destructive":
5353 "[--control-icon-color:currentColor] border-transparent text-muted-foreground data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent [:hover,[data-pressed]]:text-destructive",
5454 glass:
55 "surface-glass [--control-icon-color:var(--contrast-muted-foreground)] border-border/60 text-foreground shadow-sm [:hover,[data-pressed]]:border-border",
55 "surface-glass [--control-icon-color:var(--contrast-muted-foreground)] rounded-full border-border/60 text-foreground shadow-sm before:rounded-full [:hover,[data-pressed]]:border-border",
5656 link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline",
5757 "media-close":
5858 "[--control-icon-color:currentColor] border-transparent bg-black/65 text-white shadow-sm ring-1 ring-white/20 [:hover,[data-pressed]]:bg-black/80 focus-visible:ring-white",
apps/web/src/components/ui/input.tsx+3
......@@ -28,6 +28,9 @@ function Input({
2828 size === "lg" && "h-9.5 leading-9.5 sm:h-8.5 sm:leading-8.5",
2929 props.type === "search" &&
3030 "[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none",
31 // Number fields are typed into; browser spin buttons crowd narrow fields and step by 1.
32 props.type === "number" &&
33 "[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
3134 props.type === "file" &&
3235 "text-muted-foreground file:me-3 file:bg-transparent file:font-medium file:text-foreground file:text-sm",
3336 );
apps/web/src/index.css+2-18
......@@ -1350,8 +1350,7 @@ html[data-theme-id] .chat-markdown .chat-markdown-codeblock pre {
13501350 background-color: transparent;
13511351}
13521352
1353html[data-theme-id] .chat-markdown .chat-markdown-codeblock-header,
1354html[data-theme-id] .chat-markdown .chat-markdown-chrome-action {
1353html[data-theme-id] .chat-markdown .chat-markdown-codeblock-header {
13551354 color: color-mix(in srgb, var(--code-foreground) 72%, transparent);
13561355}
13571356
......@@ -1377,11 +1376,6 @@ html[data-theme-id="t3-chat"] {
13771376 }
13781377}
13791378
1380html[data-theme-id] .chat-markdown .chat-markdown-chrome-action:hover,
1381html[data-theme-id] .chat-markdown .chat-markdown-chrome-action[aria-pressed="true"] {
1382 color: var(--code-foreground);
1383}
1384
13851379html[data-theme-id] [data-app-sidebar] {
13861380 --background: var(--app-theme-canvas);
13871381 --foreground: var(--app-theme-text);
......@@ -1858,20 +1852,10 @@ code {
18581852 background: color-mix(in srgb, var(--contrast-border) 78%, transparent);
18591853}
18601854
1861.chat-markdown .chat-markdown-codeblock-header,
1862.chat-markdown .chat-markdown-chrome-action {
1855.chat-markdown .chat-markdown-codeblock-header {
18631856 color: color-mix(in srgb, var(--contrast-foreground) 72%, transparent);
18641857}
18651858
1866.chat-markdown .chat-markdown-chrome-action:hover {
1867 color: var(--contrast-foreground);
1868}
1869
1870.chat-markdown .chat-markdown-chrome-action[aria-pressed="true"] {
1871 color: var(--contrast-foreground);
1872 background: color-mix(in srgb, var(--contrast-foreground) 8%, transparent);
1873}
1874
18751859.chat-markdown .chat-markdown-codeblock pre {
18761860 margin: 0;
18771861 border: none;
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 = 250;
11export const RESTYLE_CEILING = 101;
1212
1313const RULE = "shadcn(no-restyle)";
1414