| author | |
| committer | |
| log | 5a2f3ebf6ee6eab6124ad68272c2fb5d74bc0f5d |
| tree | 6daffe963d655f8df9dbc6eb6dddadd893ed0aeb |
| parent | 389bbcc8d9dd5c463668944f7093052301c8a850 |
| signature | Signed by PGP key B5690EEEBB952194 |
10 files changed, 106 insertions(+), 106 deletions(-)
apps/web/src/components/DiffPanel.tsx+5-4| ... | ... | @@ -800,8 +800,9 @@ export default function DiffPanel({ |
| 800 | 800 | </Tooltip> |
| 801 | 801 | )} |
| 802 | 802 | <ToggleGroup |
| 803 | className="shrink-0 gap-1" | |
| 804 | size="sm" | |
| 803 | aria-label="Diff layout" | |
| 804 | className="shrink-0" | |
| 805 | variant="segmented" | |
| 805 | 806 | value={[diffLayout]} |
| 806 | 807 | onValueChange={(value) => { |
| 807 | 808 | const next = value[0]; |
| ... | ... | @@ -810,10 +811,10 @@ export default function DiffPanel({ |
| 810 | 811 | } |
| 811 | 812 | }} |
| 812 | 813 | > |
| 813 | <Toggle aria-label="Stacked diff view" value="stacked" variant="ghost"> | |
| 814 | <Toggle aria-label="Stacked diff view" value="stacked"> | |
| 814 | 815 | <Rows3Icon className="size-3.5" /> |
| 815 | 816 | </Toggle> |
| 816 | <Toggle aria-label="Split diff view" value="split" variant="ghost"> | |
| 817 | <Toggle aria-label="Split diff view" value="split"> | |
| 817 | 818 | <Columns2Icon className="size-3.5" /> |
| 818 | 819 | </Toggle> |
| 819 | 820 | </ToggleGroup> |
apps/web/src/components/GitActionsControl.tsx+20-22| ... | ... | @@ -42,6 +42,7 @@ import { Radio as RadioPrimitive } from "@base-ui/react/radio"; |
| 42 | 42 | import { AzureDevOpsIcon, BitbucketIcon, GitHubIcon, GitLabIcon } from "~/components/Icons"; |
| 43 | 43 | import { RadioGroup } from "~/components/ui/radio-group"; |
| 44 | 44 | import { Spinner } from "~/components/ui/spinner"; |
| 45 | import { toggleVariants } from "~/components/ui/toggle"; | |
| 45 | 46 | import { cn } from "~/lib/utils"; |
| 46 | 47 | import { |
| 47 | 48 | buildGitActionProgressStages, |
| ... | ... | @@ -831,32 +832,29 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 831 | 832 | Protocol |
| 832 | 833 | </span> |
| 833 | 834 | <RadioGroup |
| 835 | className="w-fit flex-row gap-0.5 rounded-lg bg-input/40 p-0.5" | |
| 834 | 836 | value={publishProtocol} |
| 835 | onValueChange={(value) => | |
| 836 | setPublishProtocol(value as SourceControlCloneProtocol) | |
| 837 | } | |
| 837 | onValueChange={(protocol) => { | |
| 838 | if (protocol === "ssh" || protocol === "https") { | |
| 839 | setPublishProtocol(protocol); | |
| 840 | } | |
| 841 | }} | |
| 838 | 842 | aria-labelledby="publish-protocol-label" |
| 839 | 843 | disabled={publishRepositoryAction.isPending} |
| 840 | className="grid grid-cols-2 gap-2" | |
| 841 | 844 | > |
| 842 | {(["ssh", "https"] as const).map((value) => { | |
| 843 | const isSelected = publishProtocol === value; | |
| 844 | return ( | |
| 845 | <RadioPrimitive.Root | |
| 846 | key={value} | |
| 847 | value={value} | |
| 848 | className={cn( | |
| 849 | "rounded-md border px-3 py-1.5 text-center text-sm font-medium outline-none transition", | |
| 850 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | |
| 851 | isSelected | |
| 852 | ? "border-primary bg-background ring-2 ring-primary/35 text-foreground dark:border-transparent dark:bg-primary/10 dark:ring-1 dark:ring-primary/30" | |
| 853 | : "border-border bg-background text-muted-foreground hover:border-foreground/20 hover:text-foreground dark:border-transparent dark:bg-white/[0.035]", | |
| 854 | )} | |
| 855 | > | |
| 856 | {value === "ssh" ? "SSH" : "HTTPS"} | |
| 857 | </RadioPrimitive.Root> | |
| 858 | ); | |
| 859 | })} | |
| 845 | {(["ssh", "https"] as const).map((protocol) => ( | |
| 846 | <RadioPrimitive.Root | |
| 847 | key={protocol} | |
| 848 | value={protocol} | |
| 849 | data-pressed={publishProtocol === protocol ? "" : undefined} | |
| 850 | className={toggleVariants({ | |
| 851 | variant: "segmented", | |
| 852 | size: "segmented", | |
| 853 | })} | |
| 854 | > | |
| 855 | {protocol.toUpperCase()} | |
| 856 | </RadioPrimitive.Root> | |
| 857 | ))} | |
| 860 | 858 | </RadioGroup> |
| 861 | 859 | </div> |
| 862 | 860 | </div> |
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+5-4| ... | ... | @@ -1138,8 +1138,9 @@ export function PullRequestCodeTab({ |
| 1138 | 1138 | </Tooltip> |
| 1139 | 1139 | ) : null} |
| 1140 | 1140 | <ToggleGroup |
| 1141 | className="shrink-0 gap-1" | |
| 1142 | size="sm" | |
| 1141 | aria-label="Diff layout" | |
| 1142 | className="shrink-0" | |
| 1143 | variant="segmented" | |
| 1143 | 1144 | value={[diffLayout]} |
| 1144 | 1145 | onValueChange={(value) => { |
| 1145 | 1146 | const next = value[0]; |
| ... | ... | @@ -1148,10 +1149,10 @@ export function PullRequestCodeTab({ |
| 1148 | 1149 | } |
| 1149 | 1150 | }} |
| 1150 | 1151 | > |
| 1151 | <Toggle aria-label="Stacked diff view" value="stacked" variant="ghost"> | |
| 1152 | <Toggle aria-label="Stacked diff view" value="stacked"> | |
| 1152 | 1153 | <Rows3Icon className="size-3.5" /> |
| 1153 | 1154 | </Toggle> |
| 1154 | <Toggle aria-label="Split diff view" value="split" variant="ghost"> | |
| 1155 | <Toggle aria-label="Split diff view" value="split"> | |
| 1155 | 1156 | <Columns2Icon className="size-3.5" /> |
| 1156 | 1157 | </Toggle> |
| 1157 | 1158 | </ToggleGroup> |
apps/web/src/components/pullRequest/PullRequestMarkdownEditor.tsx+14-18| ... | ... | @@ -5,6 +5,7 @@ import { cn } from "~/lib/utils"; |
| 5 | 5 | |
| 6 | 6 | import { Button } from "../ui/button"; |
| 7 | 7 | import { Textarea } from "../ui/textarea"; |
| 8 | import { Toggle, ToggleGroup } from "../ui/toggle-group"; | |
| 8 | 9 | import { PullRequestMarkdown } from "./PullRequestMarkdown"; |
| 9 | 10 | |
| 10 | 11 | /** |
| ... | ... | @@ -64,24 +65,19 @@ export function PullRequestMarkdownEditor({ |
| 64 | 65 | onCancel(); |
| 65 | 66 | }} |
| 66 | 67 | > |
| 67 | <div className="flex items-center gap-1"> | |
| 68 | <Button | |
| 69 | size="xs" | |
| 70 | variant={preview ? "ghost" : "outline"} | |
| 71 | disabled={saving} | |
| 72 | onClick={() => setPreview(false)} | |
| 73 | > | |
| 74 | Write | |
| 75 | </Button> | |
| 76 | <Button | |
| 77 | size="xs" | |
| 78 | variant={preview ? "outline" : "ghost"} | |
| 79 | disabled={saving} | |
| 80 | onClick={() => setPreview(true)} | |
| 81 | > | |
| 82 | Preview | |
| 83 | </Button> | |
| 84 | </div> | |
| 68 | <ToggleGroup | |
| 69 | aria-label="Markdown editor mode" | |
| 70 | variant="segmented" | |
| 71 | value={[preview ? "preview" : "write"]} | |
| 72 | disabled={saving} | |
| 73 | onValueChange={(next) => { | |
| 74 | const mode = next[0]; | |
| 75 | if (mode === "write" || mode === "preview") setPreview(mode === "preview"); | |
| 76 | }} | |
| 77 | > | |
| 78 | <Toggle value="write">Write</Toggle> | |
| 79 | <Toggle value="preview">Preview</Toggle> | |
| 80 | </ToggleGroup> | |
| 85 | 81 | {preview ? ( |
| 86 | 82 | <div className="rounded-lg border border-border/60 px-3 py-2"> |
| 87 | 83 | {empty ? ( |
apps/web/src/components/settings/DiagnosticsSettings.tsx+15-12| ... | ... | @@ -36,6 +36,7 @@ import { usePrimaryEnvironment } from "../../state/environments"; |
| 36 | 36 | import { useCopyToClipboard } from "../../hooks/useCopyToClipboard"; |
| 37 | 37 | import { Button } from "../ui/button"; |
| 38 | 38 | import { ScrollArea } from "../ui/scroll-area"; |
| 39 | import { Toggle, ToggleGroup } from "../ui/toggle-group"; | |
| 39 | 40 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 40 | 41 | import { toastManager } from "../ui/toast"; |
| 41 | 42 | import { ExpandableText } from "./ExpandableText"; |
| ... | ... | @@ -599,21 +600,23 @@ function ResourceHistoryWindowSelector({ |
| 599 | 600 | onSelect: (windowMs: number) => void; |
| 600 | 601 | }) { |
| 601 | 602 | return ( |
| 602 | <div className="flex items-center rounded-md border border-border/60 p-0.5"> | |
| 603 | <ToggleGroup | |
| 604 | aria-label="Process history period" | |
| 605 | variant="segmented" | |
| 606 | value={[String(selectedWindowMs)]} | |
| 607 | onValueChange={(next) => { | |
| 608 | const selected = RESOURCE_HISTORY_WINDOWS.find( | |
| 609 | (option) => String(option.windowMs) === next[0], | |
| 610 | ); | |
| 611 | if (selected) onSelect(selected.windowMs); | |
| 612 | }} | |
| 613 | > | |
| 603 | 614 | {RESOURCE_HISTORY_WINDOWS.map((option) => ( |
| 604 | <button | |
| 605 | key={option.windowMs} | |
| 606 | type="button" | |
| 607 | className={cn( | |
| 608 | "cursor-pointer h-6 rounded-sm px-2 text-[11px] font-medium text-muted-foreground hover:text-foreground", | |
| 609 | selectedWindowMs === option.windowMs && "bg-muted text-foreground", | |
| 610 | )} | |
| 611 | onClick={() => onSelect(option.windowMs)} | |
| 612 | > | |
| 615 | <Toggle key={option.windowMs} value={String(option.windowMs)}> | |
| 613 | 616 | {option.label} |
| 614 | </button> | |
| 617 | </Toggle> | |
| 615 | 618 | ))} |
| 616 | </div> | |
| 619 | </ToggleGroup> | |
| 617 | 620 | ); |
| 618 | 621 | } |
| 619 | 622 |
apps/web/src/components/settings/ProviderSettingsPanel.tsx+14-11| ... | ... | @@ -72,6 +72,7 @@ import { |
| 72 | 72 | NumberFieldInput, |
| 73 | 73 | } from "../ui/number-field"; |
| 74 | 74 | import { ScrollArea } from "../ui/scroll-area"; |
| 75 | import { Toggle, ToggleGroup } from "../ui/toggle-group"; | |
| 75 | 76 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 76 | 77 | import { stackedThreadToast, toastManager } from "../ui/toast"; |
| 77 | 78 | import { AddProviderInstanceDialog } from "./AddProviderInstanceDialog"; |
| ... | ... | @@ -80,7 +81,6 @@ import { ProviderInstanceCard } from "./ProviderInstanceCard"; |
| 80 | 81 | import { UsageProviderSettings } from "./UsageProviderSettings"; |
| 81 | 82 | import { ProviderSetupSection, readAntigravityAuthMethod } from "./ProviderSetupSection"; |
| 82 | 83 | import { DRIVER_OPTIONS, getDriverOption } from "./providerDriverMeta"; |
| 83 | import { providerSettingsTabClassName } from "./providerSettingsTabs"; | |
| 84 | 84 | import { searchableSetting } from "./settingsSearch"; |
| 85 | 85 | import { |
| 86 | 86 | backgroundActivityOverrideSettings, |
| ... | ... | @@ -326,22 +326,25 @@ function ProviderSettingsPanelContent(target: ProviderSettingsTarget) { |
| 326 | 326 | const deviceTabs = |
| 327 | 327 | !onlyPrimaryDevice && options.length > 0 ? ( |
| 328 | 328 | <ScrollArea hideScrollbars scrollFade className="h-11 min-w-0 flex-1 rounded-none"> |
| 329 | <div role="group" aria-label="Devices" className="flex h-full w-max min-w-full px-1"> | |
| 329 | <ToggleGroup | |
| 330 | aria-label="Devices" | |
| 331 | variant="segmented" | |
| 332 | className="my-2" | |
| 333 | value={effectiveEnvironmentId ? [effectiveEnvironmentId] : []} | |
| 334 | onValueChange={(next) => { | |
| 335 | const environment = options.find((option) => option.environmentId === next[0]); | |
| 336 | if (environment) setSelectedEnvironmentId(environment.environmentId); | |
| 337 | }} | |
| 338 | > | |
| 330 | 339 | {options.map((environment) => { |
| 331 | 340 | const machine = resolveEnvironmentMachineKind(environment.serverConfig); |
| 332 | const selected = environment.environmentId === effectiveEnvironmentId; | |
| 333 | 341 | const detail = providerEnvironmentDetail(environment); |
| 334 | 342 | const statusText = connectionStatusTitle(environment.connection); |
| 335 | 343 | return ( |
| 336 | 344 | <Tooltip key={environment.environmentId}> |
| 337 | 345 | <TooltipTrigger |
| 338 | 346 | render={ |
| 339 | <button | |
| 340 | type="button" | |
| 341 | aria-pressed={selected} | |
| 342 | className={cn(providerSettingsTabClassName(selected), "gap-2 text-left")} | |
| 343 | onClick={() => setSelectedEnvironmentId(environment.environmentId)} | |
| 344 | > | |
| 347 | <Toggle value={environment.environmentId} className="gap-2 text-left"> | |
| 345 | 348 | <EnvironmentMachineIcon |
| 346 | 349 | kind={machine} |
| 347 | 350 | className="size-3.5 shrink-0" |
| ... | ... | @@ -357,7 +360,7 @@ function ProviderSettingsPanelContent(target: ProviderSettingsTarget) { |
| 357 | 360 | <span className="sr-only"> |
| 358 | 361 | {detail}, {statusText} |
| 359 | 362 | </span> |
| 360 | </button> | |
| 363 | </Toggle> | |
| 361 | 364 | } |
| 362 | 365 | /> |
| 363 | 366 | <TooltipPopup side="top"> |
| ... | ... | @@ -366,7 +369,7 @@ function ProviderSettingsPanelContent(target: ProviderSettingsTarget) { |
| 366 | 369 | </Tooltip> |
| 367 | 370 | ); |
| 368 | 371 | })} |
| 369 | </div> | |
| 372 | </ToggleGroup> | |
| 370 | 373 | </ScrollArea> |
| 371 | 374 | ) : null; |
| 372 | 375 |
apps/web/src/components/settings/ResourceTelemetryDiagnostics.tsx+13-12| ... | ... | @@ -45,6 +45,7 @@ import { useAtomCommand } from "../../state/use-atom-command"; |
| 45 | 45 | import { formatRelativeTime } from "../../timestampFormat"; |
| 46 | 46 | import { Button } from "../ui/button"; |
| 47 | 47 | import { ScrollArea } from "../ui/scroll-area"; |
| 48 | import { Toggle, ToggleGroup } from "../ui/toggle-group"; | |
| 48 | 49 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 49 | 50 | import { toastManager } from "../ui/toast"; |
| 50 | 51 | import { |
| ... | ... | @@ -378,21 +379,21 @@ function HistoryWindowSelector({ |
| 378 | 379 | onSelect: (windowMs: number) => void; |
| 379 | 380 | }) { |
| 380 | 381 | return ( |
| 381 | <div className="flex items-center rounded-md border border-border/60 p-0.5"> | |
| 382 | <ToggleGroup | |
| 383 | aria-label="Resource history period" | |
| 384 | variant="segmented" | |
| 385 | value={[String(selectedWindowMs)]} | |
| 386 | onValueChange={(next) => { | |
| 387 | const selected = HISTORY_WINDOWS.find((option) => String(option.windowMs) === next[0]); | |
| 388 | if (selected) onSelect(selected.windowMs); | |
| 389 | }} | |
| 390 | > | |
| 382 | 391 | {HISTORY_WINDOWS.map((option) => ( |
| 383 | <button | |
| 384 | key={option.windowMs} | |
| 385 | type="button" | |
| 386 | className={cn( | |
| 387 | "cursor-pointer h-6 rounded-sm px-2 text-[11px] font-medium text-muted-foreground hover:text-foreground", | |
| 388 | selectedWindowMs === option.windowMs && "bg-muted text-foreground", | |
| 389 | )} | |
| 390 | onClick={() => onSelect(option.windowMs)} | |
| 391 | > | |
| 392 | <Toggle key={option.windowMs} value={String(option.windowMs)}> | |
| 392 | 393 | {option.label} |
| 393 | </button> | |
| 394 | </Toggle> | |
| 394 | 395 | ))} |
| 395 | </div> | |
| 396 | </ToggleGroup> | |
| 396 | 397 | ); |
| 397 | 398 | } |
| 398 | 399 |
apps/web/src/components/settings/ThemeEditorPanel.tsx+19-12| ... | ... | @@ -38,6 +38,7 @@ import { cn } from "../../lib/utils"; |
| 38 | 38 | import { Button } from "../ui/button"; |
| 39 | 39 | import { Input } from "../ui/input"; |
| 40 | 40 | import { Switch } from "../ui/switch"; |
| 41 | import { Toggle, ToggleGroup } from "../ui/toggle-group"; | |
| 41 | 42 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 42 | 43 | import { getThemeRoleLabel, ThemeColorField } from "./ThemeColorPicker"; |
| 43 | 44 | import { |
| ... | ... | @@ -942,24 +943,17 @@ export function ThemeEditorPanel({ |
| 942 | 943 | ); |
| 943 | 944 | |
| 944 | 945 | const renderAppearanceButton = (appearance: ThemeAppearance) => { |
| 945 | const isActive = activeAppearance === appearance; | |
| 946 | 946 | const lockReason = appearanceLockReason(appearance); |
| 947 | 947 | // A locked mode stays hoverable so the tooltip can say why it is off; |
| 948 | 948 | // a real disabled attribute would swallow the pointer events. |
| 949 | 949 | const button = ( |
| 950 | <Button | |
| 950 | <Toggle | |
| 951 | 951 | aria-disabled={lockReason !== null} |
| 952 | aria-pressed={isActive} | |
| 953 | size="sm" | |
| 952 | value={appearance} | |
| 954 | 953 | className={lockReason !== null ? "opacity-50" : undefined} |
| 955 | style={isActive ? { boxShadow: "inset 0 0 0 1px var(--ring)" } : undefined} | |
| 956 | variant={isActive ? "secondary" : "outline"} | |
| 957 | onClick={() => { | |
| 958 | if (lockReason === null) setActiveAppearance(appearance); | |
| 959 | }} | |
| 960 | 954 | > |
| 961 | 955 | {appearance === "light" ? "Light" : "Dark"} |
| 962 | </Button> | |
| 956 | </Toggle> | |
| 963 | 957 | ); |
| 964 | 958 | if (lockReason === null) return button; |
| 965 | 959 | return ( |
| ... | ... | @@ -973,10 +967,23 @@ export function ThemeEditorPanel({ |
| 973 | 967 | const renderAppearanceButtons = () => ( |
| 974 | 968 | <div className="grid grid-cols-[minmax(0,1fr)_minmax(0,2fr)] items-center gap-3"> |
| 975 | 969 | <span className="text-sm font-medium">Appearance</span> |
| 976 | <div aria-label="Theme appearance" className="grid grid-cols-2 gap-2" role="group"> | |
| 970 | <ToggleGroup | |
| 971 | aria-label="Theme appearance" | |
| 972 | variant="segmented" | |
| 973 | value={[activeAppearance]} | |
| 974 | onValueChange={(next) => { | |
| 975 | const appearance = next[0]; | |
| 976 | if ( | |
| 977 | (appearance === "light" || appearance === "dark") && | |
| 978 | appearanceLockReason(appearance) === null | |
| 979 | ) { | |
| 980 | setActiveAppearance(appearance); | |
| 981 | } | |
| 982 | }} | |
| 983 | > | |
| 977 | 984 | {renderAppearanceButton("light")} |
| 978 | 985 | {renderAppearanceButton("dark")} |
| 979 | </div> | |
| 986 | </ToggleGroup> | |
| 980 | 987 | </div> |
| 981 | 988 | ); |
| 982 | 989 |
apps/web/src/components/settings/providerSettingsTabs.ts deleted-10| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | import { cn } from "../../lib/utils"; | |
| 2 | ||
| 3 | export function providerSettingsTabClassName(selected: boolean): string { | |
| 4 | return cn( | |
| 5 | "relative flex h-full shrink-0 cursor-pointer items-center rounded-sm px-3 text-xs font-medium outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", | |
| 6 | selected | |
| 7 | ? "text-foreground after:absolute after:inset-x-0 after:bottom-0 after:h-0.5 after:bg-primary" | |
| 8 | : "text-muted-foreground hover:text-foreground", | |
| 9 | ); | |
| 10 | } |
apps/web/src/components/ui/toggle-group.tsx+1-1| ... | ... | @@ -16,7 +16,7 @@ const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariant |
| 16 | 16 | |
| 17 | 17 | function ToggleGroup({ |
| 18 | 18 | className, |
| 19 | variant = "default", | |
| 19 | variant = "segmented", | |
| 20 | 20 | size = variant === "segmented" ? "segmented" : "default", |
| 21 | 21 | orientation = "horizontal", |
| 22 | 22 | children, |