| author | |
| committer | |
| log | 4aa841a8d45ccd611a809351db0b693faba6ba13 |
| tree | 9a74a709fdf177b124ff461aeb5a66e890b81c8e |
| parent | 14337401bc801d6239dd10e34997b4481081cf1d |
| signature | Signed by PGP key B5690EEEBB952194 |
5 files changed, 48 insertions(+), 30 deletions(-)
apps/web/src/components/settings/FoldedSettingsSection.tsx+2-5| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { SettingsGroup } from "./SettingsGroup"; | ||
| 1 | import { ChevronRightIcon } from "lucide-react"; | 2 | import { ChevronRightIcon } from "lucide-react"; |
| 2 | import { type ReactNode, useState } from "react"; | 3 | import { type ReactNode, useState } from "react"; |
| 3 | 4 | ||
| ... | @@ -35,11 +36,7 @@ export function FoldedSettingsSection({ | ... | @@ -35,11 +36,7 @@ export function FoldedSettingsSection({ |
| 35 | 36 | ||
| 36 | return ( | 37 | return ( |
| 37 | <section id={id} ref={targetRef} tabIndex={-1} className="outline-none"> | 38 | <section id={id} ref={targetRef} tabIndex={-1} className="outline-none"> |
| 38 | <Collapsible | 39 | <Collapsible open={open} onOpenChange={setOpen} render={<SettingsGroup divided={false} />}> |
| 39 | open={open} | ||
| 40 | onOpenChange={setOpen} | ||
| 41 | className="rounded-xl border border-border/60 bg-card/40 text-foreground shadow-xs/5" | ||
| 42 | > | ||
| 43 | <div className="flex items-center gap-4 px-3 sm:px-4"> | 40 | <div className="flex items-center gap-4 px-3 sm:px-4"> |
| 44 | <CollapsibleTrigger className="flex min-h-11 min-w-0 flex-1 items-center gap-2 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-md"> | 41 | <CollapsibleTrigger className="flex min-h-11 min-w-0 flex-1 items-center gap-2 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-md"> |
| 45 | <ChevronRightIcon | 42 | <ChevronRightIcon |
apps/web/src/components/settings/ProviderSettingsPanel.tsx+10-13| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { SettingsGroup } from "./SettingsGroup"; | ||
| 1 | import { RefreshIcon } from "~/components/ui/refresh-icon"; | 2 | import { RefreshIcon } from "~/components/ui/refresh-icon"; |
| 2 | import { useAtomValue } from "@effect/atom-react"; | 3 | import { useAtomValue } from "@effect/atom-react"; |
| 3 | import { connectionStatusTitle } from "@t3tools/client-runtime/connection"; | 4 | import { connectionStatusTitle } from "@t3tools/client-runtime/connection"; |
| ... | @@ -171,7 +172,6 @@ function providerEnvironmentDetail(environment: EnvironmentPresentation): string | ... | @@ -171,7 +172,6 @@ function providerEnvironmentDetail(environment: EnvironmentPresentation): string |
| 171 | return environment.displayUrl ?? "Remote device"; | 172 | return environment.displayUrl ?? "Remote device"; |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 174 | const providerCardClassName = "rounded-xl border border-border/60 bg-card/40 shadow-xs/5"; | ||
| 175 | // Shared by the editor grid and the placeholder states so switching devices | 175 | // Shared by the editor grid and the placeholder states so switching devices |
| 176 | // never changes the card's footprint. | 176 | // never changes the card's footprint. |
| 177 | const providerCardHeightClassName = | 177 | const providerCardHeightClassName = |
| ... | @@ -199,12 +199,9 @@ function ProviderSettingsPlaceholder({ | ... | @@ -199,12 +199,9 @@ function ProviderSettingsPlaceholder({ |
| 199 | {deviceTabs ? ( | 199 | {deviceTabs ? ( |
| 200 | <div className="flex min-h-11 min-w-0 items-center px-3 sm:px-4">{deviceTabs}</div> | 200 | <div className="flex min-h-11 min-w-0 items-center px-3 sm:px-4">{deviceTabs}</div> |
| 201 | ) : null} | 201 | ) : null} |
| 202 | <div | 202 | <SettingsGroup |
| 203 | className={cn( | 203 | divided={false} |
| 204 | providerCardClassName, | 204 | className={cn(providerCardHeightClassName, "flex overflow-x-hidden overflow-y-auto")} |
| 205 | providerCardHeightClassName, | ||
| 206 | "flex overflow-x-hidden overflow-y-auto", | ||
| 207 | )} | ||
| 208 | > | 205 | > |
| 209 | <Empty className="min-h-88"> | 206 | <Empty className="min-h-88"> |
| 210 | <EmptyMedia variant="icon">{icon}</EmptyMedia> | 207 | <EmptyMedia variant="icon">{icon}</EmptyMedia> |
| ... | @@ -214,7 +211,7 @@ function ProviderSettingsPlaceholder({ | ... | @@ -214,7 +211,7 @@ function ProviderSettingsPlaceholder({ |
| 214 | </EmptyHeader> | 211 | </EmptyHeader> |
| 215 | {children ? <EmptyContent className="max-w-xl">{children}</EmptyContent> : null} | 212 | {children ? <EmptyContent className="max-w-xl">{children}</EmptyContent> : null} |
| 216 | </Empty> | 213 | </Empty> |
| 217 | </div> | 214 | </SettingsGroup> |
| 218 | </SettingsSection> | 215 | </SettingsSection> |
| 219 | ); | 216 | ); |
| 220 | } | 217 | } |
| ... | @@ -1044,16 +1041,16 @@ export function EnvironmentProviderSettings({ | ... | @@ -1044,16 +1041,16 @@ export function EnvironmentProviderSettings({ |
| 1044 | </div> | 1041 | </div> |
| 1045 | </div> | 1042 | </div> |
| 1046 | {readOnly ? ( | 1043 | {readOnly ? ( |
| 1047 | <div className={cn(providerCardClassName, "overflow-hidden")}> | 1044 | <SettingsGroup divided={false} className="overflow-hidden"> |
| 1048 | <SettingsRow | 1045 | <SettingsRow |
| 1049 | title="Limited permissions" | 1046 | title="Limited permissions" |
| 1050 | description={`This session can view ${environmentLabel}'s providers but can't change their settings.`} | 1047 | description={`This session can view ${environmentLabel}'s providers but can't change their settings.`} |
| 1051 | /> | 1048 | /> |
| 1052 | </div> | 1049 | </SettingsGroup> |
| 1053 | ) : null} | 1050 | ) : null} |
| 1054 | <div | 1051 | <SettingsGroup |
| 1052 | divided={false} | ||
| 1055 | className={cn( | 1053 | className={cn( |
| 1056 | providerCardClassName, | ||
| 1057 | providerCardHeightClassName, | 1054 | providerCardHeightClassName, |
| 1058 | "overflow-hidden @min-[48rem]/providers:grid @min-[48rem]/providers:grid-cols-[17rem_minmax(0,1fr)]", | 1055 | "overflow-hidden @min-[48rem]/providers:grid @min-[48rem]/providers:grid-cols-[17rem_minmax(0,1fr)]", |
| 1059 | )} | 1056 | )} |
| ... | @@ -1083,7 +1080,7 @@ export function EnvironmentProviderSettings({ | ... | @@ -1083,7 +1080,7 @@ export function EnvironmentProviderSettings({ |
| 1083 | </div> | 1080 | </div> |
| 1084 | )} | 1081 | )} |
| 1085 | </div> | 1082 | </div> |
| 1086 | </div> | 1083 | </SettingsGroup> |
| 1087 | </SettingsSection> | 1084 | </SettingsSection> |
| 1088 | 1085 | ||
| 1089 | <UsageProviderSettings | 1086 | <UsageProviderSettings |
apps/web/src/components/settings/SettingsGroup.tsx created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | import type { ComponentProps } from "react"; | ||
| 2 | |||
| 3 | import { cn } from "../../lib/utils"; | ||
| 4 | |||
| 5 | /** Shared settings card surface, with optional separators between rows. */ | ||
| 6 | export function SettingsGroup({ | ||
| 7 | variant = "grouped", | ||
| 8 | divided = true, | ||
| 9 | className, | ||
| 10 | ...props | ||
| 11 | }: ComponentProps<"div"> & { | ||
| 12 | variant?: "grouped" | "plain"; | ||
| 13 | divided?: boolean; | ||
| 14 | }) { | ||
| 15 | return ( | ||
| 16 | <div | ||
| 17 | {...props} | ||
| 18 | className={cn( | ||
| 19 | "relative overflow-visible text-foreground", | ||
| 20 | variant === "grouped" | ||
| 21 | ? "rounded-xl border border-border/60 bg-card/40 shadow-xs/5" | ||
| 22 | : "space-y-1", | ||
| 23 | variant === "grouped" && | ||
| 24 | divided && | ||
| 25 | "[&>*+*]:border-t [&>*+*]:border-border/50 [&>[data-slot=settings-row]]:rounded-none", | ||
| 26 | className, | ||
| 27 | )} | ||
| 28 | /> | ||
| 29 | ); | ||
| 30 | } | ||
apps/web/src/components/settings/SettingsPanels.tsx+3-2| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { SettingsGroup } from "./SettingsGroup"; | ||
| 1 | import { Spinner } from "~/components/ui/spinner"; | 2 | import { Spinner } from "~/components/ui/spinner"; |
| 2 | import { NotificationSettings } from "./NotificationSettings"; | 3 | import { NotificationSettings } from "./NotificationSettings"; |
| 3 | import { ArchiveIcon, ArchiveX, CheckIcon, ChevronRightIcon, SettingsIcon } from "lucide-react"; | 4 | import { ArchiveIcon, ArchiveX, CheckIcon, ChevronRightIcon, SettingsIcon } from "lucide-react"; |
| ... | @@ -2047,7 +2048,7 @@ function LegacyFeaturesSection() { | ... | @@ -2047,7 +2048,7 @@ function LegacyFeaturesSection() { |
| 2047 | <ChevronRightIcon className="size-4 text-muted-foreground transition-transform duration-200 group-data-panel-open:rotate-90" /> | 2048 | <ChevronRightIcon className="size-4 text-muted-foreground transition-transform duration-200 group-data-panel-open:rotate-90" /> |
| 2048 | </CollapsibleTrigger> | 2049 | </CollapsibleTrigger> |
| 2049 | <CollapsiblePanel> | 2050 | <CollapsiblePanel> |
| 2050 | <div className="relative overflow-visible rounded-xl border border-border/60 bg-card/40 text-foreground shadow-xs/5 [&>*+*]:border-t [&>*+*]:border-border/50 [&>[data-slot=settings-row]]:rounded-none"> | 2051 | <SettingsGroup> |
| 2051 | <SettingsRow | 2052 | <SettingsRow |
| 2052 | {...searchableSetting("legacy-plan-mode")} | 2053 | {...searchableSetting("legacy-plan-mode")} |
| 2053 | description="Restore Build/Plan, /plan, /default, and Shift+Tab. Off uses build mode." | 2054 | description="Restore Build/Plan, /plan, /default, and Shift+Tab. Off uses build mode." |
| ... | @@ -2087,7 +2088,7 @@ function LegacyFeaturesSection() { | ... | @@ -2087,7 +2088,7 @@ function LegacyFeaturesSection() { |
| 2087 | /> | 2088 | /> |
| 2088 | } | 2089 | } |
| 2089 | /> | 2090 | /> |
| 2090 | </div> | 2091 | </SettingsGroup> |
| 2091 | </CollapsiblePanel> | 2092 | </CollapsiblePanel> |
| 2092 | </Collapsible> | 2093 | </Collapsible> |
| 2093 | </section> | 2094 | </section> |
apps/web/src/components/settings/settingsLayout.tsx+3-10| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { SettingsGroup } from "./SettingsGroup"; | ||
| 1 | import { InfoIcon, Undo2Icon } from "lucide-react"; | 2 | import { InfoIcon, Undo2Icon } from "lucide-react"; |
| 2 | import { DEFAULT_SERVER_SETTINGS, type ServerSettings } from "@t3tools/contracts"; | 3 | import { DEFAULT_SERVER_SETTINGS, type ServerSettings } from "@t3tools/contracts"; |
| 3 | import * as Equal from "effect/Equal"; | 4 | import * as Equal from "effect/Equal"; |
| ... | @@ -215,17 +216,9 @@ export function SettingsSection({ | ... | @@ -215,17 +216,9 @@ export function SettingsSection({ |
| 215 | <div className="flex min-h-7 min-w-7 items-center justify-end">{headerAction}</div> | 216 | <div className="flex min-h-7 min-w-7 items-center justify-end">{headerAction}</div> |
| 216 | </div> | 217 | </div> |
| 217 | )} | 218 | )} |
| 218 | <div | 219 | <SettingsGroup data-settings-scroll-target={hideTitle ? "" : undefined} variant={variant}> |
| 219 | data-settings-scroll-target={hideTitle ? "" : undefined} | ||
| 220 | className={cn( | ||
| 221 | "relative overflow-visible text-foreground", | ||
| 222 | variant === "grouped" | ||
| 223 | ? "rounded-xl border border-border/60 bg-card/40 shadow-xs/5 [&>*+*]:border-t [&>*+*]:border-border/50 [&>[data-slot=settings-row]]:rounded-none" | ||
| 224 | : "space-y-1", | ||
| 225 | )} | ||
| 226 | > | ||
| 227 | {children} | 220 | {children} |
| 228 | </div> | 221 | </SettingsGroup> |
| 229 | </section> | 222 | </section> |
| 230 | ); | 223 | ); |
| 231 | } | 224 | } |