| author | |
| committer | |
| log | b5a0f810108d42ca8635b5a3d75a6e885bb3a254 |
| tree | 0e6da149664827942d11cebd78a9c6abbfffdf0a |
| parent | 438bf466fd7e97bb80f0d1f936b2c857830249b7 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>36 files changed, 101 insertions(+), 59 deletions(-)
apps/web/src/components/BranchToolbarBranchSelector.tsx+1-1| ... | ... | @@ -905,7 +905,7 @@ export function BranchToolbarBranchSelector({ |
| 905 | 905 | className="flex cursor-pointer items-center justify-between gap-3 border-t border-border/60 px-3 py-2 text-xs" |
| 906 | 906 | > |
| 907 | 907 | <span className="flex min-w-0 items-center gap-1.5 font-medium text-muted-foreground"> |
| 908 | <RefreshIcon aria-hidden="true" className="size-3 shrink-0 opacity-70" /> | |
| 908 | <RefreshIcon aria-hidden="true" size="xs" className="shrink-0" /> | |
| 909 | 909 | <span className="truncate">Start from origin</span> |
| 910 | 910 | </span> |
| 911 | 911 | <Switch |
apps/web/src/components/DiffPanel.tsx+1-1| ... | ... | @@ -856,7 +856,7 @@ export default function DiffPanel({ |
| 856 | 856 | /> |
| 857 | 857 | } |
| 858 | 858 | > |
| 859 | <RefreshIcon className="size-3.5" refreshing={isRefreshingDiff} /> | |
| 859 | <RefreshIcon size="sm" refreshing={isRefreshingDiff} /> | |
| 860 | 860 | </TooltipTrigger> |
| 861 | 861 | <TooltipPopup side="top"> |
| 862 | 862 | {isRefreshingDiff ? "Refreshing diff…" : "Refresh diff"} |
apps/web/src/components/GitActionsControl.tsx+2-2| ... | ... | @@ -851,7 +851,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 851 | 851 | aria-live="polite" |
| 852 | 852 | className="flex items-center gap-2 rounded-md border border-input bg-muted/40 px-3 py-2 text-xs text-muted-foreground dark:border-transparent dark:bg-white/[0.035]" |
| 853 | 853 | > |
| 854 | <Spinner className="size-3.5" aria-hidden /> | |
| 854 | <Spinner size="sm" aria-hidden /> | |
| 855 | 855 | Publishing repository to {publishProviderLabel}... |
| 856 | 856 | </div> |
| 857 | 857 | ) : null} |
| ... | ... | @@ -938,7 +938,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 938 | 938 | <Button disabled={!canSubmitPublishRepository} onClick={submitPublishRepository}> |
| 939 | 939 | {publishRepositoryAction.isPending ? ( |
| 940 | 940 | <> |
| 941 | <Spinner className="size-3.5" aria-hidden /> | |
| 941 | <Spinner size="sm" aria-hidden /> | |
| 942 | 942 | Publishing... |
| 943 | 943 | </> |
| 944 | 944 | ) : ( |
apps/web/src/components/ProviderUpdateEnvironmentRows.tsx+1-1| ... | ... | @@ -118,7 +118,7 @@ function EnvironmentUpdateRow({ |
| 118 | 118 | let trailing: ReactNode; |
| 119 | 119 | switch (status.kind) { |
| 120 | 120 | case "loading": |
| 121 | trailing = <Spinner className="size-4 text-muted-foreground" />; | |
| 121 | trailing = <Spinner size="md" tone="muted" />; | |
| 122 | 122 | break; |
| 123 | 123 | case "success": |
| 124 | 124 | trailing = <CheckIcon aria-hidden="true" className="size-4 text-success" />; |
apps/web/src/components/PullRequestThreadDialog.tsx+1-1| ... | ... | @@ -252,7 +252,7 @@ export function PullRequestThreadDialog({ |
| 252 | 252 | |
| 253 | 253 | {isResolving ? ( |
| 254 | 254 | <div className="flex items-center gap-2 text-muted-foreground text-xs"> |
| 255 | <Spinner className="size-3.5" /> | |
| 255 | <Spinner size="sm" /> | |
| 256 | 256 | Resolving {terminology.singular}... |
| 257 | 257 | </div> |
| 258 | 258 | ) : null} |
apps/web/src/components/chat/ComposerPrimaryActions.tsx+1-1| ... | ... | @@ -254,7 +254,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ |
| 254 | 254 | </span> |
| 255 | 255 | ) : null} |
| 256 | 256 | {isConnecting || isSendBusy ? ( |
| 257 | <Spinner className="size-3.5" aria-hidden="true" /> | |
| 257 | <Spinner size="sm" aria-hidden="true" /> | |
| 258 | 258 | ) : ( |
| 259 | 259 | <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true"> |
| 260 | 260 | <path |
apps/web/src/components/chat/MessagesTimeline.tsx+1-1| ... | ... | @@ -2567,7 +2567,7 @@ function BackgroundWorktreeSetupChip({ snapshot }: { snapshot: WorktreeSetupSnap |
| 2567 | 2567 | /> |
| 2568 | 2568 | } |
| 2569 | 2569 | > |
| 2570 | <Spinner className="size-3 shrink-0" /> | |
| 2570 | <Spinner size="xs" className="shrink-0" /> | |
| 2571 | 2571 | <span className="truncate">{scriptName}</span> |
| 2572 | 2572 | </PopoverTrigger> |
| 2573 | 2573 | <PopoverPopup |
apps/web/src/components/chat/WorktreeSetupCard.tsx+1-1| ... | ... | @@ -61,7 +61,7 @@ function StageIcon({ status }: { status: WorktreeSetupStage["status"] }) { |
| 61 | 61 | case "done": |
| 62 | 62 | return <CheckIcon aria-hidden className={className} />; |
| 63 | 63 | case "running": |
| 64 | return <Spinner className={className} />; | |
| 64 | return <Spinner size="md" className="shrink-0" />; | |
| 65 | 65 | case "failed": |
| 66 | 66 | return <XIcon aria-hidden className={className} />; |
| 67 | 67 | case "warning": |
apps/web/src/components/clerk/ClerkUserProfilePage.tsx+1-1| ... | ... | @@ -56,7 +56,7 @@ export function ClerkUserProfileRefreshButton({ |
| 56 | 56 | disabled={disabled || isPending} |
| 57 | 57 | onClick={onClick} |
| 58 | 58 | > |
| 59 | <RefreshIcon aria-hidden="true" className="size-3.5" refreshing={isPending} /> | |
| 59 | <RefreshIcon aria-hidden="true" size="sm" refreshing={isPending} /> | |
| 60 | 60 | Refresh |
| 61 | 61 | </Button> |
| 62 | 62 | ); |
apps/web/src/components/device/DeviceLoadingView.tsx+1-1| ... | ... | @@ -27,7 +27,7 @@ export function DeviceLoadingView(props: { |
| 27 | 27 | ) : null} |
| 28 | 28 | </div> |
| 29 | 29 | <div className="flex items-center gap-2 text-xs text-muted-foreground"> |
| 30 | {!props.error ? <Spinner className="size-3" /> : null} | |
| 30 | {!props.error ? <Spinner size="xs" /> : null} | |
| 31 | 31 | <span>{props.message}</span> |
| 32 | 32 | </div> |
| 33 | 33 | {props.children} |
apps/web/src/components/device/DevicePanel.tsx+1-1| ... | ... | @@ -367,7 +367,7 @@ export function DevicePanel(props: { |
| 367 | 367 | onClick={() => void selectDevice(deviceKey(device))} |
| 368 | 368 | action={ |
| 369 | 369 | pendingDeviceKey === deviceKey(device) ? ( |
| 370 | <Spinner className="size-3" /> | |
| 370 | <Spinner size="xs" /> | |
| 371 | 371 | ) : ( |
| 372 | 372 | <span className="text-xs text-muted-foreground"> |
| 373 | 373 | {device.booted ? "Open" : "Start"} |
apps/web/src/components/device/DeviceSetup.tsx+3-3| ... | ... | @@ -203,7 +203,7 @@ export function DeviceHubSetupStatus({ |
| 203 | 203 | if (!pending && state.hostStatus !== "ready") return null; |
| 204 | 204 | return ( |
| 205 | 205 | <p role="status" className="flex items-center gap-2 text-xs text-muted-foreground"> |
| 206 | {pending ? <Spinner className="size-3" /> : <Check className="size-3 text-success" />} | |
| 206 | {pending ? <Spinner size="xs" /> : <Check className="size-3 text-success" />} | |
| 207 | 207 | {pending |
| 208 | 208 | ? state.hostStatus === "installing" |
| 209 | 209 | ? compact |
| ... | ... | @@ -235,7 +235,7 @@ function DevicePlatformSetup(props: { |
| 235 | 235 | You can use either platform. Fixing a missing platform does not block the other one. |
| 236 | 236 | </p> |
| 237 | 237 | <Button size="compact" variant="outline" disabled={props.disabled} onClick={props.onCheck}> |
| 238 | {props.checking ? <Spinner className="size-3" /> : null} | |
| 238 | {props.checking ? <Spinner size="xs" /> : null} | |
| 239 | 239 | {props.checking ? "Checking…" : "Check again"} |
| 240 | 240 | </Button> |
| 241 | 241 | </div> |
| ... | ... | @@ -262,7 +262,7 @@ export function AgentDeviceSetupStatus(props: { |
| 262 | 262 | : "Updating agent access…"; |
| 263 | 263 | return ( |
| 264 | 264 | <p role="status" className="flex items-center gap-2 text-xs text-muted-foreground"> |
| 265 | <Spinner className="size-3" /> | |
| 265 | <Spinner size="xs" /> | |
| 266 | 266 | {label} |
| 267 | 267 | </p> |
| 268 | 268 | ); |
apps/web/src/components/device/DeviceToolsPanel.tsx+2-2| ... | ... | @@ -173,7 +173,7 @@ export function DeviceToolsPanel(props: { |
| 173 | 173 | > |
| 174 | 174 | <div className="flex h-9 shrink-0 items-center gap-2 border-b px-3"> |
| 175 | 175 | <span className="font-medium">Tools</span> |
| 176 | {pending ? <Spinner className="size-3.5" /> : null} | |
| 176 | {pending ? <Spinner size="sm" /> : null} | |
| 177 | 177 | <Button |
| 178 | 178 | size="icon-xs" |
| 179 | 179 | variant="ghost-muted" |
| ... | ... | @@ -190,7 +190,7 @@ export function DeviceToolsPanel(props: { |
| 190 | 190 | ) : null} |
| 191 | 191 | {detail === null && !error ? ( |
| 192 | 192 | <div className="flex items-center gap-2 px-3 py-3 text-xs text-muted-foreground"> |
| 193 | <Spinner className="size-3.5" /> Reading device settings… | |
| 193 | <Spinner size="sm" /> Reading device settings… | |
| 194 | 194 | </div> |
| 195 | 195 | ) : null} |
| 196 | 196 |
apps/web/src/components/files/FilePreviewPanel.tsx+3-3| ... | ... | @@ -169,7 +169,7 @@ function WorkspaceImagePreview(props: { |
| 169 | 169 | </div> |
| 170 | 170 | ) : ( |
| 171 | 171 | <div className="flex min-h-0 flex-1 items-center justify-center text-muted-foreground"> |
| 172 | <Spinner className="size-5" /> | |
| 172 | <Spinner size="lg" /> | |
| 173 | 173 | </div> |
| 174 | 174 | ); |
| 175 | 175 | } |
| ... | ... | @@ -214,7 +214,7 @@ function WorkspaceBrowserPreview(props: { |
| 214 | 214 | if (assetUrl._tag !== "Success") { |
| 215 | 215 | return ( |
| 216 | 216 | <div className="flex min-h-0 flex-1 items-center justify-center text-muted-foreground"> |
| 217 | <Spinner className="size-5" /> | |
| 217 | <Spinner size="lg" /> | |
| 218 | 218 | </div> |
| 219 | 219 | ); |
| 220 | 220 | } |
| ... | ... | @@ -1232,7 +1232,7 @@ export default function FilePreviewPanel({ |
| 1232 | 1232 | </div> |
| 1233 | 1233 | ) : relativePath && file.data === null ? ( |
| 1234 | 1234 | <div className="flex min-h-0 flex-1 items-center justify-center text-muted-foreground"> |
| 1235 | <Spinner className="size-5" /> | |
| 1235 | <Spinner size="lg" /> | |
| 1236 | 1236 | </div> |
| 1237 | 1237 | ) : relativePath && file.data ? ( |
| 1238 | 1238 | isMarkdown && renderMarkdown ? ( |
apps/web/src/components/files/fileSurfaceChrome.tsx+1-1| ... | ... | @@ -131,7 +131,7 @@ export function FileSurfaceLoading(props: { readonly className?: string }) { |
| 131 | 131 | props.className, |
| 132 | 132 | )} |
| 133 | 133 | > |
| 134 | <Spinner className="size-5" /> | |
| 134 | <Spinner size="lg" /> | |
| 135 | 135 | </div> |
| 136 | 136 | ); |
| 137 | 137 | } |
apps/web/src/components/onboarding/WelcomeWizard.tsx+2-2| ... | ... | @@ -1162,7 +1162,7 @@ function ImportStep({ |
| 1162 | 1162 | <div className="flex h-full min-h-40 flex-col"> |
| 1163 | 1163 | <h1 className="text-2xl font-semibold tracking-tight text-foreground">Your projects</h1> |
| 1164 | 1164 | <div className="flex flex-1 flex-col items-center justify-center gap-3 py-6"> |
| 1165 | <Spinner className="size-5 text-muted-foreground" /> | |
| 1165 | <Spinner size="lg" tone="muted" /> | |
| 1166 | 1166 | <p className="text-center text-sm text-muted-foreground"> |
| 1167 | 1167 | Looking for projects from Claude Code and Codex… |
| 1168 | 1168 | </p> |
| ... | ... | @@ -1229,7 +1229,7 @@ function ImportStep({ |
| 1229 | 1229 | ) : null} |
| 1230 | 1230 | {scan.isPending && scan.data === null ? ( |
| 1231 | 1231 | <div className="flex items-center gap-2 py-3 text-sm text-muted-foreground"> |
| 1232 | <Spinner className="size-4" /> | |
| 1232 | <Spinner size="md" /> | |
| 1233 | 1233 | Looking for projects… |
| 1234 | 1234 | </div> |
| 1235 | 1235 | ) : scan.error !== null ? ( |
apps/web/src/components/pullRequest/PullRequestActivityUnavailableState.tsx+1-1| ... | ... | @@ -23,7 +23,7 @@ export function PullRequestActivityUnavailableState({ |
| 23 | 23 | <p className="text-sm font-medium text-foreground">Could not load pull request activity</p> |
| 24 | 24 | <p className="max-w-md text-xs text-muted-foreground">{error}</p> |
| 25 | 25 | <Button size="sm" variant="outline" onClick={onRetry}> |
| 26 | <RefreshIcon aria-hidden className="size-3.5" /> | |
| 26 | <RefreshIcon aria-hidden size="sm" /> | |
| 27 | 27 | Retry |
| 28 | 28 | </Button> |
| 29 | 29 | </div> |
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+2-2| ... | ... | @@ -2010,7 +2010,7 @@ export function PullRequestDetailPanel({ |
| 2010 | 2010 | the spinning glyph in place of the dots: the reader sees the panel |
| 2011 | 2011 | is fetching without a control appearing or the row shifting. */} |
| 2012 | 2012 | {refreshing ? ( |
| 2013 | <RefreshIcon refreshing className="size-4" /> | |
| 2013 | <RefreshIcon refreshing size="md" /> | |
| 2014 | 2014 | ) : ( |
| 2015 | 2015 | <MoreHorizontalIcon className="size-4" /> |
| 2016 | 2016 | )} |
| ... | ... | @@ -2034,7 +2034,7 @@ export function PullRequestDetailPanel({ |
| 2034 | 2034 | onPickerOpenChange={setThreadPickerOpen} |
| 2035 | 2035 | /> |
| 2036 | 2036 | <MenuItem disabled={refreshing} onClick={() => void refreshFromHost()}> |
| 2037 | <RefreshIcon className="size-3.5" refreshing={refreshing} /> | |
| 2037 | <RefreshIcon size="sm" refreshing={refreshing} /> | |
| 2038 | 2038 | Refresh |
| 2039 | 2039 | </MenuItem> |
| 2040 | 2040 | <MenuItem disabled={handoff !== null} onClick={askAboutPullRequest}> |
apps/web/src/components/pullRequest/PullRequestListEmptyState.tsx+2-2| ... | ... | @@ -150,7 +150,7 @@ export function PullRequestListEmptyState({ |
| 150 | 150 | {/* The hosts answered this query once; a pull request opened since then would answer |
| 151 | 151 | differently, and nothing on screen says which of the two the reader is looking at. */} |
| 152 | 152 | <Button size="sm" variant="outline" disabled={refreshing} onClick={onRefresh}> |
| 153 | <RefreshIcon className="size-3.5" refreshing={refreshing} /> | |
| 153 | <RefreshIcon size="sm" refreshing={refreshing} /> | |
| 154 | 154 | {refreshing ? "Checking..." : "Check again"} |
| 155 | 155 | </Button> |
| 156 | 156 | </EmptyContent> |
| ... | ... | @@ -176,7 +176,7 @@ export function PullRequestListEmptyState({ |
| 176 | 176 | </Button> |
| 177 | 177 | ) : null} |
| 178 | 178 | <Button size="sm" variant="outline" disabled={refreshing} onClick={onRefresh}> |
| 179 | <RefreshIcon className="size-3.5" refreshing={refreshing} /> | |
| 179 | <RefreshIcon size="sm" refreshing={refreshing} /> | |
| 180 | 180 | {refreshing ? "Checking..." : "Check again"} |
| 181 | 181 | </Button> |
| 182 | 182 | </EmptyContent> |
apps/web/src/components/pullRequest/PullRequestsUnavailableState.tsx+1-1| ... | ... | @@ -46,7 +46,7 @@ export function PullRequestsUnavailableState({ |
| 46 | 46 | disabled={refreshing} |
| 47 | 47 | aria-busy={refreshing} |
| 48 | 48 | > |
| 49 | <RefreshIcon className="size-3.5" refreshing={refreshing} /> | |
| 49 | <RefreshIcon size="sm" refreshing={refreshing} /> | |
| 50 | 50 | Retry |
| 51 | 51 | </Button> |
| 52 | 52 | ) : null} |
apps/web/src/components/search/ProjectContentSearchDialog.tsx+1-1| ... | ... | @@ -226,7 +226,7 @@ function OpenContentSearchDialog(props: { |
| 226 | 226 | <div className="flex h-9 shrink-0 items-center border-b px-3 text-xs text-muted-foreground"> |
| 227 | 227 | {search.isPending ? ( |
| 228 | 228 | <span className="flex items-center gap-2"> |
| 229 | <Spinner className="size-3.5" /> Searching… | |
| 229 | <Spinner size="sm" /> Searching… | |
| 230 | 230 | </span> |
| 231 | 231 | ) : search.error ? ( |
| 232 | 232 | <span className="text-destructive">{search.error}</span> |
apps/web/src/components/settings/BrowserImportWizard.tsx+2-2| ... | ... | @@ -491,7 +491,7 @@ function ImportingStep() { |
| 491 | 491 | <DialogDescription>This may take a moment.</DialogDescription> |
| 492 | 492 | </DialogHeader> |
| 493 | 493 | <DialogPanel className="flex items-center gap-3 py-6"> |
| 494 | <Spinner className="size-4 text-muted-foreground" /> | |
| 494 | <Spinner size="md" tone="muted" /> | |
| 495 | 495 | <span className="text-sm text-muted-foreground">Importing…</span> |
| 496 | 496 | </DialogPanel> |
| 497 | 497 | </> |
| ... | ... | @@ -516,7 +516,7 @@ function CheckingStep({ |
| 516 | 516 | </DialogDescription> |
| 517 | 517 | </DialogHeader> |
| 518 | 518 | <DialogPanel className="flex items-center gap-3 py-6"> |
| 519 | <Spinner className="size-4 text-muted-foreground" /> | |
| 519 | <Spinner size="md" tone="muted" /> | |
| 520 | 520 | <span className="text-sm text-muted-foreground"> |
| 521 | 521 | {check === "fullDiskAccess" ? "Checking access…" : "Checking…"} |
| 522 | 522 | </span> |
apps/web/src/components/settings/ConnectionsSettings.tsx+6-6| ... | ... | @@ -3435,7 +3435,7 @@ export function ConnectionsSettings() { |
| 3435 | 3435 | pendingDesktopServerExposureMode === null || isUpdatingDesktopServerExposure |
| 3436 | 3436 | } |
| 3437 | 3437 | > |
| 3438 | {isUpdatingDesktopServerExposure && <Spinner className="size-3.5" />} | |
| 3438 | {isUpdatingDesktopServerExposure && <Spinner size="sm" />} | |
| 3439 | 3439 | <span className="[text-box:trim-both_cap_alphabetic]"> |
| 3440 | 3440 | {isUpdatingDesktopServerExposure |
| 3441 | 3441 | ? "Restarting…" |
| ... | ... | @@ -3499,7 +3499,7 @@ export function ConnectionsSettings() { |
| 3499 | 3499 | > |
| 3500 | 3500 | {isUpdatingWslBackend ? ( |
| 3501 | 3501 | <> |
| 3502 | <Spinner className="size-3.5" /> | |
| 3502 | <Spinner size="sm" /> | |
| 3503 | 3503 | Applying… |
| 3504 | 3504 | </> |
| 3505 | 3505 | ) : ( |
| ... | ... | @@ -3513,7 +3513,7 @@ export function ConnectionsSettings() { |
| 3513 | 3513 | > |
| 3514 | 3514 | {isUpdatingWslBackend ? ( |
| 3515 | 3515 | <> |
| 3516 | <Spinner className="size-3.5" /> | |
| 3516 | <Spinner size="sm" /> | |
| 3517 | 3517 | Applying… |
| 3518 | 3518 | </> |
| 3519 | 3519 | ) : ( |
| ... | ... | @@ -3534,7 +3534,7 @@ export function ConnectionsSettings() { |
| 3534 | 3534 | > |
| 3535 | 3535 | {isUpdatingWslBackend ? ( |
| 3536 | 3536 | <> |
| 3537 | <Spinner className="size-3.5" /> | |
| 3537 | <Spinner size="sm" /> | |
| 3538 | 3538 | Applying… |
| 3539 | 3539 | </> |
| 3540 | 3540 | ) : pendingWslChange?.kind === "disable" ? ( |
| ... | ... | @@ -3583,7 +3583,7 @@ export function ConnectionsSettings() { |
| 3583 | 3583 | > |
| 3584 | 3584 | {isUpdatingTailscaleServe ? ( |
| 3585 | 3585 | <> |
| 3586 | <Spinner className="size-3.5" /> | |
| 3586 | <Spinner size="sm" /> | |
| 3587 | 3587 | Restarting… |
| 3588 | 3588 | </> |
| 3589 | 3589 | ) : ( |
| ... | ... | @@ -3657,7 +3657,7 @@ export function ConnectionsSettings() { |
| 3657 | 3657 | > |
| 3658 | 3658 | {isUpdatingTailscaleServe ? ( |
| 3659 | 3659 | <> |
| 3660 | <Spinner className="size-3.5" /> | |
| 3660 | <Spinner size="sm" /> | |
| 3661 | 3661 | Restarting… |
| 3662 | 3662 | </> |
| 3663 | 3663 | ) : ( |
apps/web/src/components/settings/DeviceHostEditor.tsx+3-3| ... | ... | @@ -156,7 +156,7 @@ export function DeviceHostEditor({ |
| 156 | 156 | if (Option.isSome(input)) void testConnection(input.value); |
| 157 | 157 | }} |
| 158 | 158 | > |
| 159 | {checking ? <Spinner className="size-3" /> : null} Test connection | |
| 159 | {checking ? <Spinner size="xs" /> : null} Test connection | |
| 160 | 160 | </Button> |
| 161 | 161 | </div> |
| 162 | 162 | {results ? ( |
| ... | ... | @@ -173,7 +173,7 @@ export function DeviceHostEditor({ |
| 173 | 173 | > |
| 174 | 174 | {result.status === "pending" ? ( |
| 175 | 175 | <> |
| 176 | <Spinner className="size-3" /> Checking… | |
| 176 | <Spinner size="xs" /> Checking… | |
| 177 | 177 | </> |
| 178 | 178 | ) : result.status === "local" ? ( |
| 179 | 179 | <> |
| ... | ... | @@ -215,7 +215,7 @@ export function DeviceHostEditor({ |
| 215 | 215 | Cancel |
| 216 | 216 | </Button> |
| 217 | 217 | <Button type="submit" disabled={busy || checking || !valid || !draft.label.trim()}> |
| 218 | {busy ? <Spinner className="size-3" /> : null} Save host | |
| 218 | {busy ? <Spinner size="xs" /> : null} Save host | |
| 219 | 219 | </Button> |
| 220 | 220 | </DialogFooter> |
| 221 | 221 | </DialogPopup> |
apps/web/src/components/settings/DeviceHostsSettings.tsx+1-1| ... | ... | @@ -267,7 +267,7 @@ function DeviceHostList({ |
| 267 | 267 | role="status" |
| 268 | 268 | className="inline-flex items-center gap-1.5 text-xs text-muted-foreground" |
| 269 | 269 | > |
| 270 | <Spinner className="size-3" /> | |
| 270 | <Spinner size="xs" /> | |
| 271 | 271 | {progress} |
| 272 | 272 | </span> |
| 273 | 273 | ) : null} |
apps/web/src/components/settings/LocalEnvironmentSetting.tsx+1-1| ... | ... | @@ -86,7 +86,7 @@ export function LocalEnvironmentSetting() { |
| 86 | 86 | > |
| 87 | 87 | {isUpdating ? ( |
| 88 | 88 | <> |
| 89 | <Spinner className="size-3.5" /> | |
| 89 | <Spinner size="sm" /> | |
| 90 | 90 | Restarting… |
| 91 | 91 | </> |
| 92 | 92 | ) : enabled ? ( |
apps/web/src/components/settings/ResourceTelemetryDiagnostics.tsx+3-3| ... | ... | @@ -976,7 +976,7 @@ export function ResourceTelemetryDiagnostics({ |
| 976 | 976 | onClick={telemetry.refresh} |
| 977 | 977 | aria-label="Refresh resource telemetry" |
| 978 | 978 | > |
| 979 | <RefreshIcon className="size-3" refreshing={telemetry.isPending} /> | |
| 979 | <RefreshIcon size="xs" refreshing={telemetry.isPending} /> | |
| 980 | 980 | </Button> |
| 981 | 981 | } |
| 982 | 982 | /> |
| ... | ... | @@ -1087,7 +1087,7 @@ export function ResourceTelemetryDiagnostics({ |
| 1087 | 1087 | headerAction={ |
| 1088 | 1088 | collectorNeedsRetry ? ( |
| 1089 | 1089 | <Button size="xs" variant="outline" disabled={isRetrying} onClick={retryCollector}> |
| 1090 | <RefreshIcon className="size-3" refreshing={isRetrying} /> | |
| 1090 | <RefreshIcon size="xs" refreshing={isRetrying} /> | |
| 1091 | 1091 | Retry monitor |
| 1092 | 1092 | </Button> |
| 1093 | 1093 | ) : null |
| ... | ... | @@ -1225,7 +1225,7 @@ export function ResourceTelemetryDiagnostics({ |
| 1225 | 1225 | onClick={history.refresh} |
| 1226 | 1226 | aria-label="Refresh resource history" |
| 1227 | 1227 | > |
| 1228 | <RefreshIcon className="size-3" refreshing={history.isPending} /> | |
| 1228 | <RefreshIcon size="xs" refreshing={history.isPending} /> | |
| 1229 | 1229 | </Button> |
| 1230 | 1230 | </div> |
| 1231 | 1231 | } |
apps/web/src/components/settings/SettingsPanels.tsx+1-1| ... | ... | @@ -3359,7 +3359,7 @@ export function ArchivedThreadsPanel() { |
| 3359 | 3359 | title={ |
| 3360 | 3360 | <span className="inline-flex items-center gap-2"> |
| 3361 | 3361 | {isLoadingArchive ? ( |
| 3362 | <Spinner className="size-3.5 text-muted-foreground" /> | |
| 3362 | <Spinner size="sm" tone="muted" /> | |
| 3363 | 3363 | ) : ( |
| 3364 | 3364 | <ArchiveIcon className="size-3.5 text-muted-foreground" /> |
| 3365 | 3365 | )} |
apps/web/src/components/settings/SourceControlSettings.tsx+1-1| ... | ... | @@ -491,7 +491,7 @@ function EmptySourceControlDiscovery({ |
| 491 | 491 | </EmptyHeader> |
| 492 | 492 | <EmptyContent> |
| 493 | 493 | <Button size="sm" variant="outline" onClick={onScan} disabled={isPending}> |
| 494 | <RefreshIcon className="size-3.5" refreshing={isPending} /> | |
| 494 | <RefreshIcon size="sm" refreshing={isPending} /> | |
| 495 | 495 | Scan |
| 496 | 496 | </Button> |
| 497 | 497 | </EmptyContent> |
apps/web/src/components/sidebar/SidebarProviderUpdatePill.tsx+1-1| ... | ... | @@ -174,7 +174,7 @@ export function SidebarProviderUpdatePill() { |
| 174 | 174 | onClick={openProviderSettings} |
| 175 | 175 | > |
| 176 | 176 | {displayedView.tone === "loading" ? ( |
| 177 | <Spinner className="size-3.5 shrink-0" /> | |
| 177 | <Spinner size="sm" className="shrink-0" /> | |
| 178 | 178 | ) : displayedView.tone === "success" ? ( |
| 179 | 179 | <CircleCheckIcon className="size-3.5 shrink-0" /> |
| 180 | 180 | ) : displayedView.tone === "error" ? ( |
apps/web/src/components/ui/refresh-icon.tsx+21-2| ... | ... | @@ -1,19 +1,38 @@ |
| 1 | 1 | import { RefreshCwIcon } from "lucide-react"; |
| 2 | import { cva, type VariantProps } from "class-variance-authority"; | |
| 2 | 3 | |
| 3 | 4 | import { cn } from "~/lib/utils"; |
| 4 | 5 | import { observeVisibleAnimation } from "~/lib/visibleAnimation"; |
| 5 | 6 | |
| 7 | // No default size: inside a Button the parent's svg rule sizes the glyph. | |
| 8 | const refreshIconVariants = cva("", { | |
| 9 | variants: { | |
| 10 | size: { | |
| 11 | xs: "size-3", | |
| 12 | sm: "size-3.5", | |
| 13 | md: "size-4", | |
| 14 | lg: "size-5", | |
| 15 | }, | |
| 16 | }, | |
| 17 | }); | |
| 18 | ||
| 6 | 19 | /** Keep the refresh glyph in place while its owning action is running. */ |
| 7 | 20 | export function RefreshIcon({ |
| 8 | 21 | refreshing = false, |
| 9 | 22 | className, |
| 23 | size, | |
| 10 | 24 | ...props |
| 11 | }: React.ComponentPropsWithoutRef<typeof RefreshCwIcon> & { refreshing?: boolean }) { | |
| 25 | }: React.ComponentPropsWithoutRef<typeof RefreshCwIcon> & | |
| 26 | VariantProps<typeof refreshIconVariants> & { refreshing?: boolean }) { | |
| 12 | 27 | return ( |
| 13 | 28 | <RefreshCwIcon |
| 14 | 29 | aria-hidden |
| 15 | 30 | ref={refreshing ? observeVisibleAnimation : undefined} |
| 16 | className={cn(refreshing && "motion-safe:visible-animate-spin", className)} | |
| 31 | className={cn( | |
| 32 | refreshIconVariants({ size }), | |
| 33 | refreshing && "motion-safe:visible-animate-spin", | |
| 34 | className, | |
| 35 | )} | |
| 17 | 36 | {...props} |
| 18 | 37 | /> |
| 19 | 38 | ); |
apps/web/src/components/ui/spinner.tsx+25-2| ... | ... | @@ -1,13 +1,36 @@ |
| 1 | 1 | import { LoaderCircleIcon } from "lucide-react"; |
| 2 | import { cva, type VariantProps } from "class-variance-authority"; | |
| 2 | 3 | import { observeVisibleAnimation } from "~/lib/visibleAnimation"; |
| 3 | 4 | import { cn } from "~/lib/utils"; |
| 4 | 5 | |
| 5 | function Spinner({ className, ...props }: React.ComponentPropsWithoutRef<typeof LoaderCircleIcon>) { | |
| 6 | // No default size: inside a Button the parent's svg rule sizes the glyph. | |
| 7 | const spinnerVariants = cva("motion-safe:visible-animate-spin", { | |
| 8 | variants: { | |
| 9 | size: { | |
| 10 | xs: "size-3", | |
| 11 | sm: "size-3.5", | |
| 12 | md: "size-4", | |
| 13 | lg: "size-5", | |
| 14 | }, | |
| 15 | tone: { | |
| 16 | current: "", | |
| 17 | muted: "text-muted-foreground", | |
| 18 | }, | |
| 19 | }, | |
| 20 | defaultVariants: { tone: "current" }, | |
| 21 | }); | |
| 22 | ||
| 23 | function Spinner({ | |
| 24 | className, | |
| 25 | size, | |
| 26 | tone, | |
| 27 | ...props | |
| 28 | }: React.ComponentPropsWithoutRef<typeof LoaderCircleIcon> & VariantProps<typeof spinnerVariants>) { | |
| 6 | 29 | return ( |
| 7 | 30 | <LoaderCircleIcon |
| 8 | 31 | aria-label="Loading" |
| 9 | 32 | ref={observeVisibleAnimation} |
| 10 | className={cn("motion-safe:visible-animate-spin", className)} | |
| 33 | className={cn(spinnerVariants({ size, tone }), className)} | |
| 11 | 34 | role="status" |
| 12 | 35 | {...props} |
| 13 | 36 | /> |
apps/web/src/components/usage/UsagePage.tsx+2-2| ... | ... | @@ -300,7 +300,7 @@ export function UsagePage() { |
| 300 | 300 | size="icon-sm" |
| 301 | 301 | variant="ghost" |
| 302 | 302 | > |
| 303 | <RefreshIcon className="size-3.5" refreshing={isRefreshing} /> | |
| 303 | <RefreshIcon size="sm" refreshing={isRefreshing} /> | |
| 304 | 304 | </Button> |
| 305 | 305 | </div> |
| 306 | 306 | <div className="col-span-2 ms-auto flex min-w-0 items-center justify-end gap-1 xl:hidden"> |
| ... | ... | @@ -359,7 +359,7 @@ export function UsagePage() { |
| 359 | 359 | size="icon-sm" |
| 360 | 360 | variant="ghost" |
| 361 | 361 | > |
| 362 | <RefreshIcon className="size-3.5" refreshing={isRefreshing} /> | |
| 362 | <RefreshIcon size="sm" refreshing={isRefreshing} /> | |
| 363 | 363 | </Button> |
| 364 | 364 | </div> |
| 365 | 365 | </div> |
apps/web/src/routes/_chat.index.tsx+1-1| ... | ... | @@ -99,7 +99,7 @@ function DraftStartError({ onRetry }: { readonly onRetry: () => void }) { |
| 99 | 99 | </EmptyDescription> |
| 100 | 100 | <div className="mt-5 flex justify-center"> |
| 101 | 101 | <Button size="sm" onClick={onRetry}> |
| 102 | <RefreshIcon className="size-4" /> | |
| 102 | <RefreshIcon size="md" /> | |
| 103 | 103 | Try again |
| 104 | 104 | </Button> |
| 105 | 105 | </div> |
apps/web/src/routes/_chat.pull-requests.tsx+2-2| ... | ... | @@ -1830,7 +1830,7 @@ function PullRequestsRouteView() { |
| 1830 | 1830 | <div className="flex justify-center py-3 text-xs text-muted-foreground"> |
| 1831 | 1831 | {loadingMore ? ( |
| 1832 | 1832 | <span className="flex items-center gap-2"> |
| 1833 | <Spinner aria-hidden className="size-3.5" /> | |
| 1833 | <Spinner aria-hidden size="sm" /> | |
| 1834 | 1834 | {sentCursors === null ? "Updating pull requests" : "Loading more"} |
| 1835 | 1835 | </span> |
| 1836 | 1836 | ) : canContinue || pageSize < MAX_PAGE_SIZE ? ( |
| ... | ... | @@ -2592,7 +2592,7 @@ function PullRequestRefreshControl({ |
| 2592 | 2592 | onClick={onRefresh} |
| 2593 | 2593 | disabled={refreshing} |
| 2594 | 2594 | > |
| 2595 | <RefreshIcon className="size-4" refreshing={refreshing} /> | |
| 2595 | <RefreshIcon size="md" refreshing={refreshing} /> | |
| 2596 | 2596 | </Button> |
| 2597 | 2597 | ); |
| 2598 | 2598 | } |
scripts/lint-restyle-ceiling.ts+1-1| ... | ... | @@ -8,7 +8,7 @@ import * as NodeURL from "node:url"; |
| 8 | 8 | // components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the |
| 9 | 9 | // count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you |
| 10 | 10 | // migrate a file, and delete this script when the rule becomes an error. |
| 11 | export const RESTYLE_CEILING = 1214; | |
| 11 | export const RESTYLE_CEILING = 1207; | |
| 12 | 12 | |
| 13 | 13 | const RULE = "shadcn(no-restyle)"; |
| 14 | 14 |