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