| author | |
| committer | |
| log | e51538b812392d522947494ae32dacf3f3859f5e |
| tree | db8c5fbd1d0df94349c43b98a7016af27e4d29d9 |
| parent | 1c9a6de26eb41f77dbf2f6039427f50f2e9f8b39 |
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure18 files changed, 212 insertions(+), 225 deletions(-)
apps/web/src/components/ChatView.tsx+1-1| ... | @@ -5592,7 +5592,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -5592,7 +5592,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 5592 | : undefined | 5592 | : undefined |
| 5593 | } | 5593 | } |
| 5594 | > | 5594 | > |
| 5595 | <div className="chat-composer-glass-host mx-auto w-full max-w-3xl overflow-hidden rounded-[22px]"> | 5595 | <div className="chat-composer-glass-host mx-auto w-full max-w-3xl rounded-[22px]"> |
| 5596 | <div ref={attachDraftHeroComposerAnchorRef} className="relative z-10 isolate"> | 5596 | <div ref={attachDraftHeroComposerAnchorRef} className="relative z-10 isolate"> |
| 5597 | <ChatComposer | 5597 | <ChatComposer |
| 5598 | composerRef={composerRef} | 5598 | composerRef={composerRef} |
apps/web/src/components/GitActionsControl.tsx+9-20| ... | @@ -544,10 +544,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { | ... | @@ -544,10 +544,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { |
| 544 | 544 | ||
| 545 | return ( | 545 | return ( |
| 546 | <Dialog open={props.open} onOpenChange={handleOpenChange}> | 546 | <Dialog open={props.open} onOpenChange={handleOpenChange}> |
| 547 | <DialogPopup | 547 | <DialogPopup className="max-w-xl overflow-hidden"> |
| 548 | backdropClassName="bg-black/40 backdrop-blur-none" | ||
| 549 | className="workflow-dialog-surface max-w-xl overflow-hidden before:hidden" | ||
| 550 | > | ||
| 551 | <div className="flex min-h-0 flex-col overflow-hidden border-foreground/10 bg-transparent"> | 548 | <div className="flex min-h-0 flex-col overflow-hidden border-foreground/10 bg-transparent"> |
| 552 | <DialogHeader className="border-b border-border/70 bg-foreground/[0.025] dark:border-transparent dark:bg-transparent"> | 549 | <DialogHeader className="border-b border-border/70 bg-foreground/[0.025] dark:border-transparent dark:bg-transparent"> |
| 553 | <DialogTitle>Publish repository</DialogTitle> | 550 | <DialogTitle>Publish repository</DialogTitle> |
| ... | @@ -1828,16 +1825,13 @@ export default function GitActionsControl({ | ... | @@ -1828,16 +1825,13 @@ export default function GitActionsControl({ |
| 1828 | } | 1825 | } |
| 1829 | }} | 1826 | }} |
| 1830 | > | 1827 | > |
| 1831 | <DialogPopup | 1828 | <DialogPopup> |
| 1832 | backdropClassName="bg-black/40 backdrop-blur-none" | ||
| 1833 | className="command-palette-dialog-surface workflow-dialog-surface before:hidden" | ||
| 1834 | > | ||
| 1835 | <DialogHeader> | 1829 | <DialogHeader> |
| 1836 | <DialogTitle>{COMMIT_DIALOG_TITLE}</DialogTitle> | 1830 | <DialogTitle>{COMMIT_DIALOG_TITLE}</DialogTitle> |
| 1837 | <DialogDescription>{COMMIT_DIALOG_DESCRIPTION}</DialogDescription> | 1831 | <DialogDescription>{COMMIT_DIALOG_DESCRIPTION}</DialogDescription> |
| 1838 | </DialogHeader> | 1832 | </DialogHeader> |
| 1839 | <DialogPanel className="space-y-4"> | 1833 | <DialogPanel className="space-y-4"> |
| 1840 | <div className="space-y-3 rounded-lg border border-input bg-muted/40 p-3 text-xs dark:border-transparent dark:bg-white/[0.035]"> | 1834 | <div className="space-y-3 rounded-xl bg-zinc-25 p-3 text-sm ring-1 ring-black/5 dark:bg-white/[0.035] dark:ring-white/5"> |
| 1841 | <div className="grid grid-cols-[auto_1fr] items-center gap-x-2 gap-y-1"> | 1835 | <div className="grid grid-cols-[auto_1fr] items-center gap-x-2 gap-y-1"> |
| 1842 | <span className="text-muted-foreground">Branch</span> | 1836 | <span className="text-muted-foreground">Branch</span> |
| 1843 | <span className="flex items-center justify-between gap-2"> | 1837 | <span className="flex items-center justify-between gap-2"> |
| ... | @@ -1845,9 +1839,7 @@ export default function GitActionsControl({ | ... | @@ -1845,9 +1839,7 @@ export default function GitActionsControl({ |
| 1845 | {gitStatusForActions?.refName ?? "(detached HEAD)"} | 1839 | {gitStatusForActions?.refName ?? "(detached HEAD)"} |
| 1846 | </span> | 1840 | </span> |
| 1847 | {isDefaultRef && ( | 1841 | {isDefaultRef && ( |
| 1848 | <span className="text-right text-warning text-xs"> | 1842 | <span className="text-right text-warning">Warning: default refName</span> |
| 1849 | Warning: default refName | ||
| 1850 | </span> | ||
| 1851 | )} | 1843 | )} |
| 1852 | </span> | 1844 | </span> |
| 1853 | </div> | 1845 | </div> |
| ... | @@ -1886,14 +1878,14 @@ export default function GitActionsControl({ | ... | @@ -1886,14 +1878,14 @@ export default function GitActionsControl({ |
| 1886 | <p className="font-medium">none</p> | 1878 | <p className="font-medium">none</p> |
| 1887 | ) : ( | 1879 | ) : ( |
| 1888 | <div className="space-y-2"> | 1880 | <div className="space-y-2"> |
| 1889 | <ScrollArea className="h-44 rounded-md border border-input bg-background dark:border-transparent dark:bg-white/[0.025]"> | 1881 | <ScrollArea className="h-44 rounded-lg bg-card ring-1 ring-black/5 dark:bg-white/[0.025] dark:ring-white/5"> |
| 1890 | <div className="space-y-1 p-1"> | 1882 | <div className="space-y-1 p-1"> |
| 1891 | {allFiles.map((file) => { | 1883 | {allFiles.map((file) => { |
| 1892 | const isExcluded = excludedFiles.has(file.path); | 1884 | const isExcluded = excludedFiles.has(file.path); |
| 1893 | return ( | 1885 | return ( |
| 1894 | <div | 1886 | <div |
| 1895 | key={file.path} | 1887 | key={file.path} |
| 1896 | className="flex w-full items-center gap-2 rounded-md px-2 py-1 font-mono text-xs transition-colors hover:bg-accent/50" | 1888 | className="flex w-full items-center gap-2 rounded-md px-2 py-1 font-mono hover:bg-accent/50" |
| 1897 | > | 1889 | > |
| 1898 | {isEditingFiles && ( | 1890 | {isEditingFiles && ( |
| 1899 | <Checkbox | 1891 | <Checkbox |
| ... | @@ -1952,7 +1944,7 @@ export default function GitActionsControl({ | ... | @@ -1952,7 +1944,7 @@ export default function GitActionsControl({ |
| 1952 | </div> | 1944 | </div> |
| 1953 | </div> | 1945 | </div> |
| 1954 | <div className="space-y-1"> | 1946 | <div className="space-y-1"> |
| 1955 | <p className="text-xs font-medium">Commit message (optional)</p> | 1947 | <p className="text-sm font-medium">Commit message (optional)</p> |
| 1956 | <Textarea | 1948 | <Textarea |
| 1957 | value={dialogCommitMessage} | 1949 | value={dialogCommitMessage} |
| 1958 | onChange={(event) => setDialogCommitMessage(event.target.value)} | 1950 | onChange={(event) => setDialogCommitMessage(event.target.value)} |
| ... | @@ -1961,7 +1953,7 @@ export default function GitActionsControl({ | ... | @@ -1961,7 +1953,7 @@ export default function GitActionsControl({ |
| 1961 | /> | 1953 | /> |
| 1962 | </div> | 1954 | </div> |
| 1963 | </DialogPanel> | 1955 | </DialogPanel> |
| 1964 | <DialogFooter className="dark:border-transparent dark:bg-transparent"> | 1956 | <DialogFooter variant="bare"> |
| 1965 | <Button | 1957 | <Button |
| 1966 | variant="outline" | 1958 | variant="outline" |
| 1967 | size="sm" | 1959 | size="sm" |
| ... | @@ -2004,10 +1996,7 @@ export default function GitActionsControl({ | ... | @@ -2004,10 +1996,7 @@ export default function GitActionsControl({ |
| 2004 | } | 1996 | } |
| 2005 | }} | 1997 | }} |
| 2006 | > | 1998 | > |
| 2007 | <DialogPopup | 1999 | <DialogPopup className="max-w-xl"> |
| 2008 | backdropClassName="bg-black/40 backdrop-blur-none" | ||
| 2009 | className="workflow-dialog-surface max-w-xl before:hidden" | ||
| 2010 | > | ||
| 2011 | <DialogHeader> | 2000 | <DialogHeader> |
| 2012 | <DialogTitle> | 2001 | <DialogTitle> |
| 2013 | {pendingDefaultBranchActionCopy?.title ?? "Run action on default refName?"} | 2002 | {pendingDefaultBranchActionCopy?.title ?? "Run action on default refName?"} |
apps/web/src/components/ProjectScriptsControl.tsx+1-1| ... | @@ -461,7 +461,7 @@ export default function ProjectScriptsControl({ | ... | @@ -461,7 +461,7 @@ export default function ProjectScriptsControl({ |
| 461 | }} | 461 | }} |
| 462 | open={dialogOpen} | 462 | open={dialogOpen} |
| 463 | > | 463 | > |
| 464 | <DialogPopup className="before:hidden"> | 464 | <DialogPopup> |
| 465 | <DialogHeader> | 465 | <DialogHeader> |
| 466 | <DialogTitle>{isEditing ? "Edit Action" : "Add Action"}</DialogTitle> | 466 | <DialogTitle>{isEditing ? "Edit Action" : "Add Action"}</DialogTitle> |
| 467 | <DialogDescription> | 467 | <DialogDescription> |
apps/web/src/components/SidebarV2.tsx+7-7| ... | @@ -677,13 +677,13 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { | ... | @@ -677,13 +677,13 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 677 | <span className="text-red-600 dark:text-red-400">−{diff.deletions}</span> | 677 | <span className="text-red-600 dark:text-red-400">−{diff.deletions}</span> |
| 678 | </span> | 678 | </span> |
| 679 | ) : null} | 679 | ) : null} |
| 680 | <span className="ml-auto inline-flex shrink-0 items-center gap-1"> | 680 | <span |
| 681 | aria-hidden | ||
| 682 | className="pointer-events-none ml-auto inline-flex shrink-0 items-center gap-1" | ||
| 683 | > | ||
| 681 | {isRemote ? ( | 684 | {isRemote ? ( |
| 682 | <span | 685 | <span className="inline-flex shrink-0 items-center text-sidebar-muted-foreground/70"> |
| 683 | aria-label={props.environmentLabel ?? "Remote environment"} | 686 | <ServerIcon aria-hidden className="size-3.5" /> |
| 684 | className="inline-flex shrink-0 items-center text-sidebar-muted-foreground/70" | ||
| 685 | > | ||
| 686 | <ServerIcon aria-hidden className="size-4" /> | ||
| 687 | </span> | 687 | </span> |
| 688 | ) : null} | 688 | ) : null} |
| 689 | {driverKind ? ( | 689 | {driverKind ? ( |
| ... | @@ -691,7 +691,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { | ... | @@ -691,7 +691,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { |
| 691 | <ProviderInstanceIcon | 691 | <ProviderInstanceIcon |
| 692 | driverKind={driverKind} | 692 | driverKind={driverKind} |
| 693 | displayName={thread.session?.providerName ?? modelInstanceId} | 693 | displayName={thread.session?.providerName ?? modelInstanceId} |
| 694 | iconClassName="size-4" | 694 | iconClassName="size-3.5" |
| 695 | /> | 695 | /> |
| 696 | </span> | 696 | </span> |
| 697 | ) : null} | 697 | ) : null} |
apps/web/src/components/chat/ChangedFilesTree.tsx+2-2| ... | @@ -41,8 +41,8 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: { | ... | @@ -41,8 +41,8 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: { |
| 41 | const summaryStat = useMemo(() => summarizeTurnDiffStats(files), [files]); | 41 | const summaryStat = useMemo(() => summarizeTurnDiffStats(files), [files]); |
| 42 | 42 | ||
| 43 | return ( | 43 | return ( |
| 44 | <div className="mt-4 rounded-2xl bg-background p-2 pt-4 shadow-xs/5 not-dark:bg-clip-padding dark:bg-input/32"> | 44 | <div className="mt-4 rounded-2xl border border-border/70 bg-secondary p-2 pt-4 dark:border-transparent dark:bg-input/32"> |
| 45 | <div className="sticky top-0 z-10 mb-3 flex items-center justify-between gap-2 bg-background px-2 before:absolute before:inset-x-0 before:-top-4 before:h-4 before:bg-background before:content-[''] dark:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))] dark:before:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))]"> | 45 | <div className="sticky top-0 z-10 mb-3 flex items-center justify-between gap-2 bg-secondary px-2 before:absolute before:inset-x-0 before:-top-4 before:h-4 before:bg-secondary before:content-[''] dark:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))] dark:before:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))]"> |
| 46 | <p className="flex items-center gap-1 whitespace-nowrap font-medium text-foreground text-xs leading-4"> | 46 | <p className="flex items-center gap-1 whitespace-nowrap font-medium text-foreground text-xs leading-4"> |
| 47 | <span> | 47 | <span> |
| 48 | {files.length} changed file{files.length === 1 ? "" : "s"} | 48 | {files.length} changed file{files.length === 1 ? "" : "s"} |
apps/web/src/components/chat/ComposerCommandMenu.tsx+1-4| ... | @@ -139,10 +139,7 @@ export const ComposerCommandMenu = memo(function ComposerCommandMenu(props: { | ... | @@ -139,10 +139,7 @@ export const ComposerCommandMenu = memo(function ComposerCommandMenu(props: { |
| 139 | ); | 139 | ); |
| 140 | }} | 140 | }} |
| 141 | > | 141 | > |
| 142 | <div | 142 | <div ref={listRef} className="dropdown-glass relative w-full overflow-hidden rounded-[20px]"> |
| 143 | ref={listRef} | ||
| 144 | className="relative w-full overflow-hidden rounded-[20px] border border-border/80 bg-popover/96 shadow-lg/8 backdrop-blur-xs" | ||
| 145 | > | ||
| 146 | {props.items.length > 0 ? ( | 143 | {props.items.length > 0 ? ( |
| 147 | <CommandList className="max-h-72"> | 144 | <CommandList className="max-h-72"> |
| 148 | {groups.map((group, groupIndex) => ( | 145 | {groups.map((group, groupIndex) => ( |
apps/web/src/components/chat/MessagesTimeline.tsx+2-2| ... | @@ -1285,8 +1285,8 @@ function AssistantChangedFilesSectionInner({ | ... | @@ -1285,8 +1285,8 @@ function AssistantChangedFilesSectionInner({ |
| 1285 | const summaryStat = summarizeTurnDiffStats(checkpointFiles); | 1285 | const summaryStat = summarizeTurnDiffStats(checkpointFiles); |
| 1286 | 1286 | ||
| 1287 | return ( | 1287 | return ( |
| 1288 | <div className="mt-4 rounded-2xl bg-background p-2 pt-4 shadow-xs/5 not-dark:bg-clip-padding dark:bg-input/32"> | 1288 | <div className="mt-4 rounded-2xl border border-border/70 bg-secondary p-2 pt-4 dark:border-transparent dark:bg-input/32"> |
| 1289 | <div className="sticky top-2 z-10 mb-3 flex items-center justify-between gap-2 bg-background px-2 before:absolute before:inset-x-0 before:-top-4 before:h-4 before:bg-background before:content-[''] dark:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))] dark:before:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))]"> | 1289 | <div className="sticky top-2 z-10 mb-3 flex items-center justify-between gap-2 bg-secondary px-2 before:absolute before:inset-x-0 before:-top-4 before:h-4 before:bg-secondary before:content-[''] dark:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))] dark:before:bg-[color-mix(in_srgb,var(--foreground)_2.5%,var(--background))]"> |
| 1290 | <p className="flex items-center gap-1 whitespace-nowrap font-medium text-foreground text-xs leading-4"> | 1290 | <p className="flex items-center gap-1 whitespace-nowrap font-medium text-foreground text-xs leading-4"> |
| 1291 | <span> | 1291 | <span> |
| 1292 | {checkpointFiles.length} changed file{checkpointFiles.length === 1 ? "" : "s"} | 1292 | {checkpointFiles.length} changed file{checkpointFiles.length === 1 ? "" : "s"} |
apps/web/src/components/clerk/T3ConnectSidebarSignIn.tsx+2-2| ... | @@ -55,10 +55,10 @@ function ConfiguredT3ConnectSidebarSignIn() { | ... | @@ -55,10 +55,10 @@ function ConfiguredT3ConnectSidebarSignIn() { |
| 55 | <SidebarMenuItem> | 55 | <SidebarMenuItem> |
| 56 | <SidebarMenuButton | 56 | <SidebarMenuButton |
| 57 | size="sm" | 57 | size="sm" |
| 58 | className="gap-2 px-2 py-2 text-xs text-muted-foreground hover:bg-accent hover:text-foreground" | 58 | className="h-8 items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-sidebar-muted-foreground/80 hover:bg-sidebar-row-hover hover:text-sidebar-foreground" |
| 59 | onClick={openAuthPrompt} | 59 | onClick={openAuthPrompt} |
| 60 | > | 60 | > |
| 61 | <LogInIcon className="size-4" /> | 61 | <LogInIcon className="size-4 shrink-0" /> |
| 62 | <span>Sign in to T3 Connect</span> | 62 | <span>Sign in to T3 Connect</span> |
| 63 | </SidebarMenuButton> | 63 | </SidebarMenuButton> |
| 64 | </SidebarMenuItem> | 64 | </SidebarMenuItem> |
apps/web/src/components/settings/AddProviderInstanceDialog.tsx+17-20| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | "use client"; | 1 | "use client"; |
| 2 | 2 | ||
| 3 | import { Radio as RadioPrimitive } from "@base-ui/react/radio"; | 3 | import { Radio as RadioPrimitive } from "@base-ui/react/radio"; |
| 4 | import { CheckIcon } from "lucide-react"; | ||
| 4 | import { useMemo, useState } from "react"; | 5 | import { useMemo, useState } from "react"; |
| 5 | import { | 6 | import { |
| 6 | ProviderInstanceId, | 7 | ProviderInstanceId, |
| ... | @@ -223,7 +224,7 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns | ... | @@ -223,7 +224,7 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns |
| 223 | <Dialog open={open} onOpenChange={onOpenChange}> | 224 | <Dialog open={open} onOpenChange={onOpenChange}> |
| 224 | <DialogPopup className="max-w-xl overflow-hidden"> | 225 | <DialogPopup className="max-w-xl overflow-hidden"> |
| 225 | <div className="flex min-h-0 flex-col overflow-hidden"> | 226 | <div className="flex min-h-0 flex-col overflow-hidden"> |
| 226 | <DialogHeader className="border-b border-border/70"> | 227 | <DialogHeader> |
| 227 | <DialogTitle>Add provider instance</DialogTitle> | 228 | <DialogTitle>Add provider instance</DialogTitle> |
| 228 | <DialogDescription> | 229 | <DialogDescription> |
| 229 | Configure an additional provider instance — for example, a second Codex install | 230 | Configure an additional provider instance — for example, a second Codex install |
| ... | @@ -239,41 +240,37 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns | ... | @@ -239,41 +240,37 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns |
| 239 | 240 | ||
| 240 | <div | 241 | <div |
| 241 | data-slot="dialog-panel" | 242 | data-slot="dialog-panel" |
| 242 | className="space-y-4 border-b border-border/70 bg-foreground/[0.025] px-6 py-5" | 243 | className="space-y-4 bg-zinc-25/80 px-6 py-5 ring-1 ring-black/5 dark:bg-white/2 dark:ring-white/5" |
| 243 | > | 244 | > |
| 244 | <AnimatedHeight> | 245 | <AnimatedHeight> |
| 245 | <div className={cn("grid gap-2", wizardStep !== 0 && "hidden")}> | 246 | <div className={cn("grid gap-2", wizardStep !== 0 && "hidden")}> |
| 246 | <span | 247 | <div id="add-instance-driver-label" className="text-sm font-medium text-foreground"> |
| 247 | id="add-instance-driver-label" | ||
| 248 | className="text-xs font-medium text-foreground" | ||
| 249 | > | ||
| 250 | Driver | 248 | Driver |
| 251 | </span> | 249 | </div> |
| 252 | <RadioGroup | 250 | <RadioGroup |
| 253 | value={driver} | 251 | value={driver} |
| 254 | onValueChange={(value) => setDriver(ProviderDriverKind.make(value))} | 252 | onValueChange={(value) => setDriver(ProviderDriverKind.make(value))} |
| 255 | aria-labelledby="add-instance-driver-label" | 253 | aria-labelledby="add-instance-driver-label" |
| 256 | className="grid grid-cols-2 gap-2.5" | 254 | className="grid grid-cols-1 gap-2 sm:grid-cols-2" |
| 257 | > | 255 | > |
| 258 | {DRIVER_OPTIONS.map((option) => { | 256 | {DRIVER_OPTIONS.map((option) => { |
| 259 | const IconComponent = option.icon; | 257 | const IconComponent = option.icon; |
| 260 | const isSelected = option.value === driver; | ||
| 261 | return ( | 258 | return ( |
| 262 | <RadioPrimitive.Root | 259 | <RadioPrimitive.Root |
| 263 | key={option.value} | 260 | key={option.value} |
| 264 | value={option.value} | 261 | value={option.value} |
| 265 | className={cn( | 262 | className="relative flex cursor-pointer items-center gap-3 rounded-lg bg-card px-3 py-3 text-left text-muted-foreground outline-none ring-1 ring-black/5 hover:bg-zinc-50 focus-visible:ring-2 focus-visible:ring-ring data-checked:bg-primary/8 data-checked:text-foreground data-checked:ring-2 data-checked:ring-primary data-checked:hover:bg-primary/8 dark:bg-white/3 dark:ring-white/5 dark:hover:bg-white/5 dark:data-checked:bg-primary/15 dark:data-checked:ring-primary dark:data-checked:hover:bg-primary/15" |
| 266 | "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-3 text-left outline-none transition-[background-color,border-color,box-shadow]", | ||
| 267 | "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", | ||
| 268 | isSelected | ||
| 269 | ? "border-primary bg-background shadow-sm ring-2 ring-primary/35" | ||
| 270 | : "border-border bg-background hover:border-foreground/20 hover:bg-muted/50", | ||
| 271 | )} | ||
| 272 | > | 263 | > |
| 273 | <IconComponent className="size-5 shrink-0" aria-hidden /> | 264 | <IconComponent className="size-4 shrink-0" aria-hidden /> |
| 274 | <span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground"> | 265 | <span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground"> |
| 275 | {option.label} | 266 | {option.label} |
| 276 | </span> | 267 | </span> |
| 268 | <RadioPrimitive.Indicator | ||
| 269 | className="grid size-5 shrink-0 place-items-center rounded-full bg-primary text-primary-foreground" | ||
| 270 | aria-hidden | ||
| 271 | > | ||
| 272 | <CheckIcon className="size-3.5 shrink-0" /> | ||
| 273 | </RadioPrimitive.Indicator> | ||
| 277 | {option.badgeLabel ? ( | 274 | {option.badgeLabel ? ( |
| 278 | <Badge variant="warning" size="sm"> | 275 | <Badge variant="warning" size="sm"> |
| 279 | {option.badgeLabel} | 276 | {option.badgeLabel} |
| ... | @@ -290,11 +287,11 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns | ... | @@ -290,11 +287,11 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns |
| 290 | value={option.value} | 287 | value={option.value} |
| 291 | disabled | 288 | disabled |
| 292 | className={cn( | 289 | className={cn( |
| 293 | "relative flex cursor-not-allowed items-center gap-3 rounded-lg border border-border bg-background px-3 py-3 text-left opacity-55 outline-none", | 290 | "relative flex cursor-not-allowed items-center gap-3 rounded-lg bg-card/60 px-3 py-3 text-left opacity-55 outline-none ring-1 ring-black/5 dark:bg-white/2 dark:ring-white/5", |
| 294 | )} | 291 | )} |
| 295 | > | 292 | > |
| 296 | <IconComponent | 293 | <IconComponent |
| 297 | className="size-5 shrink-0 text-muted-foreground" | 294 | className="size-4 shrink-0 text-muted-foreground" |
| 298 | aria-hidden | 295 | aria-hidden |
| 299 | /> | 296 | /> |
| 300 | <span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground"> | 297 | <span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground"> |
| ... | @@ -409,7 +406,7 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns | ... | @@ -409,7 +406,7 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns |
| 409 | </AnimatedHeight> | 406 | </AnimatedHeight> |
| 410 | </div> | 407 | </div> |
| 411 | 408 | ||
| 412 | <DialogFooter className="border-t bg-transparent"> | 409 | <DialogFooter variant="bare"> |
| 413 | <Button | 410 | <Button |
| 414 | variant="outline" | 411 | variant="outline" |
| 415 | size="sm" | 412 | size="sm" |
apps/web/src/components/settings/AddProviderInstanceWizardSteps.test.tsx+7-3| ... | @@ -9,6 +9,10 @@ interface StepButtonProps { | ... | @@ -9,6 +9,10 @@ interface StepButtonProps { |
| 9 | readonly onClick: () => void; | 9 | readonly onClick: () => void; |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | interface StepListItemProps { | ||
| 13 | readonly children: ReactElement<StepButtonProps>; | ||
| 14 | } | ||
| 15 | |||
| 12 | function renderStepButtons( | 16 | function renderStepButtons( |
| 13 | currentStep: number, | 17 | currentStep: number, |
| 14 | instanceIdError: string | null, | 18 | instanceIdError: string | null, |
| ... | @@ -21,9 +25,9 @@ function renderStepButtons( | ... | @@ -21,9 +25,9 @@ function renderStepButtons( |
| 21 | onNavigation, | 25 | onNavigation, |
| 22 | }); | 26 | }); |
| 23 | 27 | ||
| 24 | return Children.toArray(header.props.children).filter( | 28 | return Children.toArray(header.props.children) |
| 25 | (child): child is ReactElement<StepButtonProps> => isValidElement(child), | 29 | .filter((child): child is ReactElement<StepListItemProps> => isValidElement(child)) |
| 26 | ); | 30 | .map((item) => item.props.children); |
| 27 | } | 31 | } |
| 28 | 32 | ||
| 29 | describe("AddProviderInstanceWizardSteps", () => { | 33 | describe("AddProviderInstanceWizardSteps", () => { |
apps/web/src/components/settings/AddProviderInstanceWizardSteps.tsx+43-40| ... | @@ -21,50 +21,53 @@ export function AddProviderInstanceWizardSteps({ | ... | @@ -21,50 +21,53 @@ export function AddProviderInstanceWizardSteps({ |
| 21 | onNavigation, | 21 | onNavigation, |
| 22 | }: AddProviderInstanceWizardStepsProps) { | 22 | }: AddProviderInstanceWizardStepsProps) { |
| 23 | return ( | 23 | return ( |
| 24 | <div className="grid grid-cols-3 gap-2"> | 24 | <ol |
| 25 | className="grid grid-cols-3 gap-1 rounded-xl bg-zinc-25 p-1 ring-1 ring-black/5 dark:bg-white/4 dark:ring-white/5" | ||
| 26 | role="list" | ||
| 27 | > | ||
| 25 | {ADD_PROVIDER_WIZARD_STEPS.map((step, index) => ( | 28 | {ADD_PROVIDER_WIZARD_STEPS.map((step, index) => ( |
| 26 | <button | 29 | <li key={step} className="min-w-0"> |
| 27 | key={step} | 30 | <button |
| 28 | type="button" | 31 | type="button" |
| 29 | className={cn( | ||
| 30 | "grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] gap-x-2 rounded-lg border px-3 py-2 text-left", | ||
| 31 | index === currentStep | ||
| 32 | ? "border-primary bg-primary/10 ring-1 ring-primary/25" | ||
| 33 | : index < currentStep | ||
| 34 | ? "border-border bg-background" | ||
| 35 | : "border-border bg-muted/40", | ||
| 36 | )} | ||
| 37 | aria-current={index === currentStep ? "step" : undefined} | ||
| 38 | onClick={() => | ||
| 39 | onNavigation( | ||
| 40 | resolveWizardNavigation(currentStep, index, ADD_PROVIDER_WIZARD_STEPS.length, { | ||
| 41 | instanceIdError, | ||
| 42 | }), | ||
| 43 | ) | ||
| 44 | } | ||
| 45 | > | ||
| 46 | <span | ||
| 47 | className={cn( | 32 | className={cn( |
| 48 | "row-span-2 mt-0.5 grid size-4 place-items-center rounded-full border", | 33 | "flex w-full min-w-0 cursor-pointer items-center gap-2 rounded-lg px-2.5 py-2 text-left outline-none hover:bg-card focus-visible:ring-2 focus-visible:ring-ring max-sm:justify-center max-sm:px-2", |
| 49 | index < currentStep | 34 | index === currentStep && |
| 50 | ? "border-primary bg-primary text-primary-foreground" | 35 | "bg-card text-foreground shadow-xs ring-1 ring-black/5 hover:bg-card dark:shadow-none dark:ring-white/5", |
| 51 | : index === currentStep | ||
| 52 | ? "border-primary bg-background" | ||
| 53 | : "border-muted-foreground/35 bg-background", | ||
| 54 | )} | 36 | )} |
| 55 | aria-hidden | 37 | aria-current={index === currentStep ? "step" : undefined} |
| 38 | aria-label={`${step}, step ${index + 1}${index < currentStep && summaries[index] ? `, ${summaries[index]}` : ""}`} | ||
| 39 | onClick={() => | ||
| 40 | onNavigation( | ||
| 41 | resolveWizardNavigation(currentStep, index, ADD_PROVIDER_WIZARD_STEPS.length, { | ||
| 42 | instanceIdError, | ||
| 43 | }), | ||
| 44 | ) | ||
| 45 | } | ||
| 56 | > | 46 | > |
| 57 | {index < currentStep ? <CheckIcon className="size-3" /> : null} | 47 | <span |
| 58 | </span> | 48 | className={cn( |
| 59 | <span className="text-[10px] font-medium uppercase text-muted-foreground"> | 49 | "grid size-5 shrink-0 place-items-center rounded-full text-sm font-medium ring-1", |
| 60 | Step {index + 1} | 50 | index < currentStep |
| 61 | </span> | 51 | ? "bg-primary text-primary-foreground ring-primary" |
| 62 | <span className="truncate text-xs font-semibold text-foreground"> | 52 | : index === currentStep |
| 63 | {step} | 53 | ? "bg-primary/10 text-primary ring-primary/30" |
| 64 | {index < currentStep && summaries[index] ? `: ${summaries[index]}` : ""} | 54 | : "bg-card text-muted-foreground ring-black/10 dark:bg-white/5 dark:ring-white/10", |
| 65 | </span> | 55 | )} |
| 66 | </button> | 56 | aria-hidden |
| 57 | > | ||
| 58 | {index < currentStep ? <CheckIcon className="size-4 shrink-0" /> : index + 1} | ||
| 59 | </span> | ||
| 60 | <span | ||
| 61 | className={cn( | ||
| 62 | "min-w-0 truncate text-sm font-medium max-sm:hidden", | ||
| 63 | index === currentStep ? "text-foreground" : "text-muted-foreground", | ||
| 64 | )} | ||
| 65 | > | ||
| 66 | {step} | ||
| 67 | </span> | ||
| 68 | </button> | ||
| 69 | </li> | ||
| 67 | ))} | 70 | ))} |
| 68 | </div> | 71 | </ol> |
| 69 | ); | 72 | ); |
| 70 | } | 73 | } |
apps/web/src/components/ui/alert-dialog.tsx+3-3| ... | @@ -19,7 +19,7 @@ function AlertDialogBackdrop({ className, ...props }: AlertDialogPrimitive.Backd | ... | @@ -19,7 +19,7 @@ function AlertDialogBackdrop({ className, ...props }: AlertDialogPrimitive.Backd |
| 19 | <AlertDialogPrimitive.Backdrop | 19 | <AlertDialogPrimitive.Backdrop |
| 20 | forceRender | 20 | forceRender |
| 21 | className={cn( | 21 | className={cn( |
| 22 | "fixed inset-0 z-50 bg-black/20 backdrop-blur-[2px] transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:bg-black/55", | 22 | "dialog-backdrop fixed inset-0 z-50 transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0", |
| 23 | className, | 23 | className, |
| 24 | )} | 24 | )} |
| 25 | data-slot="alert-dialog-backdrop" | 25 | data-slot="alert-dialog-backdrop" |
| ... | @@ -56,9 +56,9 @@ function AlertDialogPopup({ | ... | @@ -56,9 +56,9 @@ function AlertDialogPopup({ |
| 56 | > | 56 | > |
| 57 | <AlertDialogPrimitive.Popup | 57 | <AlertDialogPrimitive.Popup |
| 58 | className={cn( | 58 | className={cn( |
| 59 | "dialog-glass -translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border border-border/70 text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", | 59 | "dialog-glass -translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] outline-none transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0", |
| 60 | bottomStickOnMobile && | 60 | bottomStickOnMobile && |
| 61 | "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none", | 61 | "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4", |
| 62 | className, | 62 | className, |
| 63 | )} | 63 | )} |
| 64 | data-slot="alert-dialog-popup" | 64 | data-slot="alert-dialog-popup" |
apps/web/src/components/ui/button.tsx+1-1| ... | @@ -40,7 +40,7 @@ const buttonVariants = cva( | ... | @@ -40,7 +40,7 @@ const buttonVariants = cva( |
| 40 | "border-transparent text-foreground data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent [&_svg:not([class*='text-'])]:text-muted-foreground", | 40 | "border-transparent text-foreground data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent [&_svg:not([class*='text-'])]:text-muted-foreground", |
| 41 | link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline", | 41 | link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline", |
| 42 | outline: | 42 | outline: |
| 43 | "border-transparent bg-popover not-dark:bg-clip-padding text-foreground shadow-none dark:bg-input/32 [:hover,[data-pressed]]:bg-accent/50 dark:[:hover,[data-pressed]]:bg-input/64 [&_svg:not([class*='text-'])]:text-muted-foreground", | 43 | "border-input bg-popover not-dark:bg-clip-padding text-foreground shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-accent/50 dark:[:hover,[data-pressed]]:bg-input/64 [&_svg:not([class*='text-'])]:text-muted-foreground", |
| 44 | secondary: | 44 | secondary: |
| 45 | "border-transparent bg-secondary text-secondary-foreground [:active,[data-pressed]]:bg-secondary/80 [:hover,[data-pressed]]:bg-secondary/90", | 45 | "border-transparent bg-secondary text-secondary-foreground [:active,[data-pressed]]:bg-secondary/80 [:hover,[data-pressed]]:bg-secondary/90", |
| 46 | }, | 46 | }, |
apps/web/src/components/ui/command.tsx+2-2| ... | @@ -30,7 +30,7 @@ function CommandDialogBackdrop({ className, ...props }: CommandDialogPrimitive.B | ... | @@ -30,7 +30,7 @@ function CommandDialogBackdrop({ className, ...props }: CommandDialogPrimitive.B |
| 30 | return ( | 30 | return ( |
| 31 | <CommandDialogPrimitive.Backdrop | 31 | <CommandDialogPrimitive.Backdrop |
| 32 | className={cn( | 32 | className={cn( |
| 33 | "fixed inset-0 z-50 bg-black/20 backdrop-blur-[2px] transition-opacity duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:bg-black/55", | 33 | "dialog-backdrop fixed inset-0 z-50 transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0", |
| 34 | className, | 34 | className, |
| 35 | )} | 35 | )} |
| 36 | data-slot="command-dialog-backdrop" | 36 | data-slot="command-dialog-backdrop" |
| ... | @@ -66,7 +66,7 @@ function CommandDialogPopup({ | ... | @@ -66,7 +66,7 @@ function CommandDialogPopup({ |
| 66 | <CommandDialogViewport> | 66 | <CommandDialogViewport> |
| 67 | <CommandDialogPrimitive.Popup | 67 | <CommandDialogPrimitive.Popup |
| 68 | className={cn( | 68 | className={cn( |
| 69 | "chat-composer-glass command-palette-glass pointer-events-auto -translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-105 min-h-0 w-full min-w-0 max-w-xl scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl bg-[color-mix(in_srgb,var(--background)_var(--glass-opacity),transparent)] text-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] outline-none transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 **:data-[slot=scroll-area-viewport]:data-has-overflow-y:pe-1", | 69 | "dialog-glass pointer-events-auto -translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-105 min-h-0 w-full min-w-0 max-w-xl scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border text-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] outline-none transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 **:data-[slot=scroll-area-viewport]:data-has-overflow-y:pe-1", |
| 70 | className, | 70 | className, |
| 71 | )} | 71 | )} |
| 72 | data-slot="command-dialog-popup" | 72 | data-slot="command-dialog-popup" |
apps/web/src/components/ui/dialog.tsx+4-5| ... | @@ -25,7 +25,7 @@ function DialogBackdrop({ className, ...props }: DialogPrimitive.Backdrop.Props) | ... | @@ -25,7 +25,7 @@ function DialogBackdrop({ className, ...props }: DialogPrimitive.Backdrop.Props) |
| 25 | <DialogPrimitive.Backdrop | 25 | <DialogPrimitive.Backdrop |
| 26 | forceRender | 26 | forceRender |
| 27 | className={cn( | 27 | className={cn( |
| 28 | "fixed inset-0 z-50 bg-black/20 backdrop-blur-[2px] transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:bg-black/55", | 28 | "dialog-backdrop fixed inset-0 z-50 transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0", |
| 29 | className, | 29 | className, |
| 30 | )} | 30 | )} |
| 31 | data-slot="dialog-backdrop" | 31 | data-slot="dialog-backdrop" |
| ... | @@ -67,9 +67,9 @@ function DialogPopup({ | ... | @@ -67,9 +67,9 @@ function DialogPopup({ |
| 67 | > | 67 | > |
| 68 | <DialogPrimitive.Popup | 68 | <DialogPrimitive.Popup |
| 69 | className={cn( | 69 | className={cn( |
| 70 | "dialog-glass -translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border border-border/70 text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", | 70 | "dialog-glass -translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] outline-none transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0", |
| 71 | bottomStickOnMobile && | 71 | bottomStickOnMobile && |
| 72 | "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none", | 72 | "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4", |
| 73 | className, | 73 | className, |
| 74 | )} | 74 | )} |
| 75 | data-slot="dialog-popup" | 75 | data-slot="dialog-popup" |
| ... | @@ -116,8 +116,7 @@ function DialogFooter({ | ... | @@ -116,8 +116,7 @@ function DialogFooter({ |
| 116 | className={cn( | 116 | className={cn( |
| 117 | "flex flex-col-reverse gap-2 px-6 sm:flex-row sm:justify-end sm:rounded-b-[calc(var(--radius-2xl)-1px)]", | 117 | "flex flex-col-reverse gap-2 px-6 sm:flex-row sm:justify-end sm:rounded-b-[calc(var(--radius-2xl)-1px)]", |
| 118 | variant === "default" && "border-t bg-muted/72 py-4", | 118 | variant === "default" && "border-t bg-muted/72 py-4", |
| 119 | variant === "bare" && | 119 | variant === "bare" && "py-4", |
| 120 | "in-[[data-slot=dialog-popup]:has([data-slot=dialog-panel])]:pt-3 pt-4 pb-6", | ||
| 121 | className, | 120 | className, |
| 122 | )} | 121 | )} |
| 123 | data-slot="dialog-footer" | 122 | data-slot="dialog-footer" |
apps/web/src/index.css+107-109| ... | @@ -77,7 +77,9 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -77,7 +77,9 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 77 | 77 | ||
| 78 | :root { | 78 | :root { |
| 79 | --app-scrollbar-width: 6px; | 79 | --app-scrollbar-width: 6px; |
| 80 | --glass-blur: 12px; | ||
| 80 | --glass-opacity: 80%; | 81 | --glass-opacity: 80%; |
| 82 | --glass-saturation: 1.14; | ||
| 81 | --desktop-window-right-resize-inset: 0px; | 83 | --desktop-window-right-resize-inset: 0px; |
| 82 | --workspace-topbar-height: 52px; | 84 | --workspace-topbar-height: 52px; |
| 83 | --workspace-controls-top: 0px; | 85 | --workspace-controls-top: 0px; |
| ... | @@ -88,6 +90,11 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -88,6 +90,11 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 88 | --workspace-titlebar-control-gap: 0.75rem; | 90 | --workspace-titlebar-control-gap: 0.75rem; |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 93 | .dark { | ||
| 94 | --glass-blur: 16px; | ||
| 95 | --glass-saturation: 1.08; | ||
| 96 | } | ||
| 97 | |||
| 91 | [data-slot="sidebar-wrapper"] { | 98 | [data-slot="sidebar-wrapper"] { |
| 92 | --workspace-titlebar-content-left: calc( | 99 | --workspace-titlebar-content-left: calc( |
| 93 | var(--workspace-controls-left) + var(--workspace-titlebar-control-size) + | 100 | var(--workspace-controls-left) + var(--workspace-titlebar-control-size) + |
| ... | @@ -108,6 +115,7 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -108,6 +115,7 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 108 | } | 115 | } |
| 109 | 116 | ||
| 110 | @theme inline { | 117 | @theme inline { |
| 118 | --color-zinc-25: oklch(99.2% 0 0); | ||
| 111 | --animate-skeleton: skeleton 2s -1s infinite linear; | 119 | --animate-skeleton: skeleton 2s -1s infinite linear; |
| 112 | /* Duty-cycled indicator animations: long holds with stepped ramps, so the | 120 | /* Duty-cycled indicator animations: long holds with stepped ramps, so the |
| 113 | compositor updates discrete frames instead of every vsync. */ | 121 | compositor updates discrete frames instead of every vsync. */ |
| ... | @@ -365,25 +373,39 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -365,25 +373,39 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 365 | 373 | ||
| 366 | .chat-composer-glass { | 374 | .chat-composer-glass { |
| 367 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); | 375 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); |
| 368 | -webkit-backdrop-filter: blur(16px); | 376 | -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 369 | backdrop-filter: blur(16px); | 377 | backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 370 | } | 378 | } |
| 371 | 379 | ||
| 372 | .chat-composer-glass-host { | 380 | .chat-composer-glass-host { |
| 373 | --chat-composer-glass-surface: color-mix(in srgb, var(--background) 96%, var(--color-black)); | 381 | --chat-composer-glass-surface: var(--card); |
| 382 | |||
| 383 | position: relative; | ||
| 384 | isolation: isolate; | ||
| 385 | box-shadow: | ||
| 386 | 0 0 0 1px rgb(0 0 0 / 8%), | ||
| 387 | 0 12px 28px -18px rgb(0 0 0 / 40%); | ||
| 388 | } | ||
| 374 | 389 | ||
| 390 | .chat-composer-glass-host::before { | ||
| 391 | position: absolute; | ||
| 392 | z-index: -1; | ||
| 393 | inset: 0; | ||
| 394 | border-radius: inherit; | ||
| 375 | background: color-mix( | 395 | background: color-mix( |
| 376 | in srgb, | 396 | in srgb, |
| 377 | var(--chat-composer-glass-surface) var(--glass-opacity), | 397 | var(--chat-composer-glass-surface) var(--glass-opacity), |
| 378 | transparent | 398 | transparent |
| 379 | ); | 399 | ); |
| 380 | box-shadow: 0 12px 28px -18px rgb(0 0 0 / 40%); | 400 | -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 381 | -webkit-backdrop-filter: blur(16px); | 401 | backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 382 | backdrop-filter: blur(16px); | 402 | content: ""; |
| 383 | } | 403 | } |
| 384 | 404 | ||
| 385 | .dark .chat-composer-glass-host { | 405 | .dark .chat-composer-glass-host { |
| 386 | --chat-composer-glass-surface: color-mix(in srgb, var(--background) 96%, var(--color-white)); | 406 | --chat-composer-glass-surface: color-mix(in srgb, var(--background) 84%, var(--color-white)); |
| 407 | |||
| 408 | box-shadow: 0 0 0 1px rgb(255 255 255 / 10%); | ||
| 387 | } | 409 | } |
| 388 | 410 | ||
| 389 | .alert-glass { | 411 | .alert-glass { |
| ... | @@ -395,8 +417,8 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -395,8 +417,8 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 395 | color-mix(in srgb, var(--alert-glass-tint) 4%, transparent) | 417 | color-mix(in srgb, var(--alert-glass-tint) 4%, transparent) |
| 396 | ), | 418 | ), |
| 397 | color-mix(in srgb, var(--background) var(--glass-opacity), transparent) !important; | 419 | color-mix(in srgb, var(--background) var(--glass-opacity), transparent) !important; |
| 398 | -webkit-backdrop-filter: blur(16px) saturate(1.1); | 420 | -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 399 | backdrop-filter: blur(16px) saturate(1.1); | 421 | backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 400 | } | 422 | } |
| 401 | 423 | ||
| 402 | .alert-glass[data-variant="error"] { | 424 | .alert-glass[data-variant="error"] { |
| ... | @@ -416,12 +438,16 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -416,12 +438,16 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 416 | } | 438 | } |
| 417 | 439 | ||
| 418 | .dropdown-glass, | 440 | .dropdown-glass, |
| 419 | .dialog-glass, | 441 | .dialog-glass { |
| 420 | .workflow-dialog-surface, | ||
| 421 | .command-palette-dialog-surface { | ||
| 422 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); | 442 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); |
| 423 | -webkit-backdrop-filter: blur(16px); | 443 | -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 424 | backdrop-filter: blur(16px); | 444 | backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturation)); |
| 445 | } | ||
| 446 | |||
| 447 | .dialog-backdrop { | ||
| 448 | background: color-mix(in srgb, var(--background) 60%, transparent); | ||
| 449 | -webkit-backdrop-filter: blur(4px); | ||
| 450 | backdrop-filter: blur(4px); | ||
| 425 | } | 451 | } |
| 426 | 452 | ||
| 427 | .dropdown-glass { | 453 | .dropdown-glass { |
| ... | @@ -429,30 +455,12 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -429,30 +455,12 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 429 | box-shadow: 0 16px 40px -18px rgb(0 0 0 / 55%); | 455 | box-shadow: 0 16px 40px -18px rgb(0 0 0 / 55%); |
| 430 | } | 456 | } |
| 431 | 457 | ||
| 432 | .command-palette-glass { | 458 | .dialog-glass { |
| 433 | box-shadow: 0 24px 64px -24px rgb(0 0 0 / 65%); | ||
| 434 | } | ||
| 435 | |||
| 436 | .command-menu-surface { | ||
| 437 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); | ||
| 438 | -webkit-backdrop-filter: blur(16px); | ||
| 439 | backdrop-filter: blur(16px); | ||
| 440 | box-shadow: 0 24px 64px -24px rgb(0 0 0 / 65%); | ||
| 441 | } | ||
| 442 | |||
| 443 | .workflow-dialog-surface { | ||
| 444 | border-color: color-mix(in srgb, var(--foreground) 10%, transparent); | 459 | border-color: color-mix(in srgb, var(--foreground) 10%, transparent); |
| 445 | box-shadow: 0 24px 64px -24px rgb(0 0 0 / 65%); | 460 | box-shadow: 0 24px 64px -24px rgb(0 0 0 / 65%); |
| 446 | } | 461 | } |
| 447 | 462 | ||
| 448 | .command-palette-dialog-surface { | 463 | .dark .dropdown-glass { |
| 449 | border-color: color-mix(in srgb, var(--foreground) 10%, transparent) !important; | ||
| 450 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent) !important; | ||
| 451 | box-shadow: 0 24px 64px -24px rgb(0 0 0 / 65%) !important; | ||
| 452 | } | ||
| 453 | |||
| 454 | .dark .dropdown-glass, | ||
| 455 | .dark .dialog-glass { | ||
| 456 | box-shadow: 0 18px 44px -18px rgb(0 0 0 / 80%); | 464 | box-shadow: 0 18px 44px -18px rgb(0 0 0 / 80%); |
| 457 | } | 465 | } |
| 458 | 466 | ||
| ... | @@ -460,33 +468,15 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -460,33 +468,15 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 460 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); | 468 | background: color-mix(in srgb, var(--background) var(--glass-opacity), transparent); |
| 461 | } | 469 | } |
| 462 | 470 | ||
| 463 | .dark .command-menu-surface, | 471 | .dark .dialog-glass { |
| 464 | .dark .command-palette-glass, | 472 | border-color: color-mix(in srgb, var(--color-white) 14%, transparent); |
| 465 | .dark .workflow-dialog-surface { | 473 | box-shadow: |
| 466 | box-shadow: none; | 474 | inset 0 1px rgb(255 255 255 / 4%), |
| 467 | } | 475 | 0 24px 72px -20px rgb(0 0 0 / 90%); |
| 468 | |||
| 469 | .dark .command-palette-dialog-surface { | ||
| 470 | box-shadow: none !important; | ||
| 471 | } | ||
| 472 | |||
| 473 | .dark | ||
| 474 | .command-palette-dialog-surface | ||
| 475 | :is([data-slot="input-control"], [data-slot="textarea-control"]) { | ||
| 476 | background: var(--secondary) !important; | ||
| 477 | } | ||
| 478 | |||
| 479 | .dark | ||
| 480 | .command-palette-dialog-surface | ||
| 481 | :is([data-slot="input-control"], [data-slot="textarea-control"]):not(:has(:focus-visible)) { | ||
| 482 | border-color: transparent !important; | ||
| 483 | box-shadow: none !important; | ||
| 484 | } | 476 | } |
| 485 | 477 | ||
| 486 | .dark | 478 | .dark .dialog-backdrop { |
| 487 | .command-palette-dialog-surface | 479 | background: color-mix(in srgb, var(--background) 64%, transparent); |
| 488 | :is([data-slot="input-control"], [data-slot="textarea-control"])::before { | ||
| 489 | box-shadow: none !important; | ||
| 490 | } | 480 | } |
| 491 | 481 | ||
| 492 | .glass-opacity-slider { | 482 | .glass-opacity-slider { |
| ... | @@ -622,15 +612,12 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -622,15 +612,12 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 622 | background: var(--background) !important; | 612 | background: var(--background) !important; |
| 623 | } | 613 | } |
| 624 | 614 | ||
| 625 | .chat-composer-glass-host { | 615 | .chat-composer-glass-host::before { |
| 626 | background: var(--chat-composer-glass-surface); | 616 | background: var(--chat-composer-glass-surface); |
| 627 | } | 617 | } |
| 628 | 618 | ||
| 629 | .dialog-glass, | 619 | .dialog-glass, |
| 630 | .dropdown-glass, | 620 | .dropdown-glass { |
| 631 | .command-menu-surface, | ||
| 632 | .command-palette-dialog-surface, | ||
| 633 | .workflow-dialog-surface { | ||
| 634 | background: var(--popover) !important; | 621 | background: var(--popover) !important; |
| 635 | } | 622 | } |
| 636 | } | 623 | } |
| ... | @@ -673,25 +660,25 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -673,25 +660,25 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 673 | :root { | 660 | :root { |
| 674 | color-scheme: light; | 661 | color-scheme: light; |
| 675 | --radius: 0.625rem; | 662 | --radius: 0.625rem; |
| 676 | --background: var(--color-white); | 663 | --background: var(--color-zinc-25); |
| 677 | --app-chrome-background: var(--background); | 664 | --app-chrome-background: var(--background); |
| 678 | --surface-raised: var(--secondary); | 665 | --surface-raised: color-mix(in srgb, var(--card) 20%, transparent); |
| 679 | --foreground: var(--color-neutral-800); | 666 | --foreground: var(--color-zinc-800); |
| 680 | --card: var(--color-white); | 667 | --card: var(--color-white); |
| 681 | --card-foreground: var(--color-neutral-800); | 668 | --card-foreground: var(--color-zinc-800); |
| 682 | --popover: var(--color-white); | 669 | --popover: var(--color-white); |
| 683 | --popover-foreground: var(--color-neutral-800); | 670 | --popover-foreground: var(--color-zinc-800); |
| 684 | --primary: oklch(0.488 0.217 264); | 671 | --primary: oklch(0.488 0.217 264); |
| 685 | --primary-foreground: var(--color-white); | 672 | --primary-foreground: var(--color-white); |
| 686 | --secondary: --alpha(var(--color-black) / 4%); | 673 | --secondary: var(--color-zinc-50); |
| 687 | --secondary-foreground: var(--color-neutral-800); | 674 | --secondary-foreground: var(--color-zinc-800); |
| 688 | --muted: --alpha(var(--color-black) / 4%); | 675 | --muted: var(--color-zinc-50); |
| 689 | --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-black)); | 676 | --muted-foreground: var(--color-zinc-500); |
| 690 | --accent: --alpha(var(--color-black) / 4%); | 677 | --accent: var(--color-zinc-100); |
| 691 | --accent-foreground: var(--color-neutral-800); | 678 | --accent-foreground: var(--color-zinc-900); |
| 692 | --destructive: var(--color-red-500); | 679 | --destructive: var(--color-red-500); |
| 693 | --border: --alpha(var(--color-black) / 8%); | 680 | --border: var(--color-zinc-200); |
| 694 | --input: --alpha(var(--color-black) / 10%); | 681 | --input: var(--color-zinc-300); |
| 695 | --ring: oklch(0.488 0.217 264); | 682 | --ring: oklch(0.488 0.217 264); |
| 696 | --destructive-foreground: var(--color-red-700); | 683 | --destructive-foreground: var(--color-red-700); |
| 697 | --info: var(--color-blue-500); | 684 | --info: var(--color-blue-500); |
| ... | @@ -700,16 +687,17 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -700,16 +687,17 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 700 | --success-foreground: var(--color-emerald-700); | 687 | --success-foreground: var(--color-emerald-700); |
| 701 | --warning: var(--color-amber-500); | 688 | --warning: var(--color-amber-500); |
| 702 | --warning-foreground: var(--color-amber-700); | 689 | --warning-foreground: var(--color-amber-700); |
| 703 | /* Fallbacks for standalone sidebar primitives. App sidebars override these | 690 | /* Keep every sidebar primitive on the same light surface hierarchy, including |
| 704 | roles on their own root so the surface hierarchy stays out of page content. */ | 691 | portaled mobile sheets and settings navigation outside the app sidebar. */ |
| 705 | --sidebar: var(--card); | 692 | --sidebar: var(--color-zinc-50); |
| 706 | --sidebar-foreground: var(--foreground); | 693 | --sidebar-foreground: var(--foreground); |
| 707 | --sidebar-muted-foreground: var(--muted-foreground); | 694 | --sidebar-muted-foreground: var(--muted-foreground); |
| 708 | --sidebar-control-surface: var(--accent); | 695 | --sidebar-control-surface: var(--color-zinc-100); |
| 709 | --sidebar-row-hover: var(--accent); | 696 | --sidebar-row-hover: var(--color-zinc-25); |
| 710 | --sidebar-row-active: var(--accent); | 697 | --sidebar-row-active: var(--color-white); |
| 711 | --sidebar-row-selected: var(--muted); | 698 | --sidebar-row-selected: var(--color-white); |
| 712 | --sidebar-border: var(--border); | 699 | --sidebar-border: var(--border); |
| 700 | --sidebar-stage-fade: var(--sidebar); | ||
| 713 | 701 | ||
| 714 | @variant dark { | 702 | @variant dark { |
| 715 | color-scheme: dark; | 703 | color-scheme: dark; |
| ... | @@ -742,34 +730,44 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -742,34 +730,44 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 742 | --success-foreground: var(--color-emerald-400); | 730 | --success-foreground: var(--color-emerald-400); |
| 743 | --warning: var(--color-amber-500); | 731 | --warning: var(--color-amber-500); |
| 744 | --warning-foreground: var(--color-amber-400); | 732 | --warning-foreground: var(--color-amber-400); |
| 745 | } | 733 | --sidebar: var(--card); |
| 746 | } | 734 | --sidebar-foreground: var(--foreground); |
| 747 | 735 | --sidebar-muted-foreground: var(--muted-foreground); | |
| 748 | /* Give both navigation implementations the same cool graphite surface. The | 736 | --sidebar-control-surface: var(--muted); |
| 749 | version attribute remains useful for layout-specific styling, but color is | 737 | --sidebar-row-hover: var(--accent); |
| 750 | shared so switching the beta does not switch visual systems. */ | 738 | --sidebar-row-active: var(--accent); |
| 739 | --sidebar-row-selected: var(--muted); | ||
| 740 | --sidebar-border: var(--border); | ||
| 741 | --sidebar-stage-fade: var(--card); | ||
| 742 | } | ||
| 743 | } | ||
| 744 | |||
| 745 | /* Keep both navigation implementations on the same quiet zinc hierarchy: | ||
| 746 | zinc-50 navigation, zinc-25 hover, and white selected/raised surfaces. | ||
| 747 | The version attribute remains useful for layout-specific styling without | ||
| 748 | changing the color system when the beta is toggled. */ | ||
| 751 | [data-sidebar-version="v1"], | 749 | [data-sidebar-version="v1"], |
| 752 | [data-sidebar-version="v2"] { | 750 | [data-sidebar-version="v2"] { |
| 753 | --background: oklch(0.965 0.009 265); | 751 | --background: var(--color-zinc-25); |
| 754 | --foreground: oklch(0.27 0.025 265); | 752 | --foreground: var(--color-zinc-800); |
| 755 | --card: oklch(0.945 0.014 265); | 753 | --card: var(--color-white); |
| 756 | --card-foreground: var(--foreground); | 754 | --card-foreground: var(--color-zinc-800); |
| 757 | --accent: oklch(0.875 0.008 265); | 755 | --accent: var(--color-zinc-100); |
| 758 | --accent-foreground: oklch(0.24 0.012 265); | 756 | --accent-foreground: var(--color-zinc-900); |
| 759 | --muted: oklch(0.9 0.018 265); | 757 | --muted: var(--color-zinc-50); |
| 760 | --muted-foreground: oklch(0.49 0.03 265); | 758 | --muted-foreground: var(--color-zinc-500); |
| 761 | --border: oklch(0.72 0.025 265 / 28%); | 759 | --border: var(--color-zinc-200); |
| 762 | --input: oklch(0.62 0.03 265 / 28%); | 760 | --input: var(--color-zinc-300); |
| 763 | --sidebar: var(--card); | 761 | --sidebar: var(--color-zinc-50); |
| 764 | --sidebar-foreground: var(--foreground); | 762 | --sidebar-foreground: var(--color-zinc-800); |
| 765 | --sidebar-muted-foreground: var(--muted-foreground); | 763 | --sidebar-muted-foreground: var(--color-zinc-500); |
| 766 | --sidebar-control-surface: var(--muted); | 764 | --sidebar-control-surface: var(--color-zinc-100); |
| 767 | --sidebar-row-hover: color-mix(in srgb, var(--foreground) 6%, transparent); | 765 | --sidebar-row-hover: var(--color-zinc-25); |
| 768 | --sidebar-row-active: color-mix(in srgb, var(--foreground) 11%, transparent); | 766 | --sidebar-row-active: var(--color-white); |
| 769 | --sidebar-row-selected: color-mix(in srgb, var(--foreground) 7%, transparent); | 767 | --sidebar-row-selected: var(--color-white); |
| 770 | --sidebar-border: var(--border); | 768 | --sidebar-border: var(--color-zinc-200); |
| 771 | --sidebar-stage-fade: var(--sidebar); | 769 | --sidebar-stage-fade: var(--sidebar); |
| 772 | background-color: var(--card); | 770 | background-color: var(--sidebar); |
| 773 | } | 771 | } |
| 774 | 772 | ||
| 775 | .dark [data-sidebar-version="v1"], | 773 | .dark [data-sidebar-version="v1"], |
packages/contracts/src/settings.test.ts+2-2| ... | @@ -38,12 +38,12 @@ describe("ClientSettings glass opacity", () => { | ... | @@ -38,12 +38,12 @@ describe("ClientSettings glass opacity", () => { |
| 38 | expect(decodeClientSettings({}).glassOpacity).toBe(80); | 38 | expect(decodeClientSettings({}).glassOpacity).toBe(80); |
| 39 | }); | 39 | }); |
| 40 | 40 | ||
| 41 | it.each([49, 101, 72.5])("rejects an invalid glass opacity: %s", (value) => { | 41 | it.each([39, 101, 72.5])("rejects an invalid glass opacity: %s", (value) => { |
| 42 | expect(() => decodeClientSettings({ glassOpacity: value })).toThrow(); | 42 | expect(() => decodeClientSettings({ glassOpacity: value })).toThrow(); |
| 43 | expect(() => decodeClientSettingsPatch({ glassOpacity: value })).toThrow(); | 43 | expect(() => decodeClientSettingsPatch({ glassOpacity: value })).toThrow(); |
| 44 | }); | 44 | }); |
| 45 | 45 | ||
| 46 | it.each([50, 75, 100])("accepts a glass opacity within the supported range: %s", (value) => { | 46 | it.each([40, 75, 100])("accepts a glass opacity within the supported range: %s", (value) => { |
| 47 | expect(decodeClientSettings({ glassOpacity: value }).glassOpacity).toBe(value); | 47 | expect(decodeClientSettings({ glassOpacity: value }).glassOpacity).toBe(value); |
| 48 | expect(decodeClientSettingsPatch({ glassOpacity: value }).glassOpacity).toBe(value); | 48 | expect(decodeClientSettingsPatch({ glassOpacity: value }).glassOpacity).toBe(value); |
| 49 | }); | 49 | }); |
packages/contracts/src/settings.ts+1-1| ... | @@ -48,7 +48,7 @@ export const SidebarAutoSettleAfterDays = Schema.Number.check( | ... | @@ -48,7 +48,7 @@ export const SidebarAutoSettleAfterDays = Schema.Number.check( |
| 48 | ); | 48 | ); |
| 49 | export type SidebarAutoSettleAfterDays = typeof SidebarAutoSettleAfterDays.Type; | 49 | export type SidebarAutoSettleAfterDays = typeof SidebarAutoSettleAfterDays.Type; |
| 50 | export const DEFAULT_SIDEBAR_AUTO_SETTLE_AFTER_DAYS: SidebarAutoSettleAfterDays = 3; | 50 | export const DEFAULT_SIDEBAR_AUTO_SETTLE_AFTER_DAYS: SidebarAutoSettleAfterDays = 3; |
| 51 | export const MIN_GLASS_OPACITY = 50; | 51 | export const MIN_GLASS_OPACITY = 40; |
| 52 | export const MAX_GLASS_OPACITY = 100; | 52 | export const MAX_GLASS_OPACITY = 100; |
| 53 | export const GlassOpacity = Schema.Int.check( | 53 | export const GlassOpacity = Schema.Int.check( |
| 54 | Schema.isBetween({ | 54 | Schema.isBetween({ |