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