| author | |
| committer | |
| log | 361b047f5f559abccacc802cd5ab9992b01473ea |
| tree | 9c076940d77bbf97bf45a9efba075736937141f3 |
| parent | 266d70cc4d887b7459ec6557c430ec7bb92bd3fc |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>30 files changed, 127 insertions(+), 205 deletions(-)
apps/web/src/components/ChatView.tsx-1| ... | @@ -10378,7 +10378,6 @@ export default function ChatView(props: ChatViewProps) { | ... | @@ -10378,7 +10378,6 @@ export default function ChatView(props: ChatViewProps) { |
| 10378 | <RightPanelSheet | 10378 | <RightPanelSheet |
| 10379 | animationDurationMs={panelAnimationsActive ? panelAnimationDurationMs : 0} | 10379 | animationDurationMs={panelAnimationsActive ? panelAnimationDurationMs : 0} |
| 10380 | open={rightPanelOpen} | 10380 | open={rightPanelOpen} |
| 10381 | underFloatingPreview={previewMiniPlayerVisible} | ||
| 10382 | onClose={closePreviewPanel} | 10381 | onClose={closePreviewPanel} |
| 10383 | > | 10382 | > |
| 10384 | <RightPanelTabs | 10383 | <RightPanelTabs |
apps/web/src/components/CommandPalette.tsx-3| ... | @@ -2966,9 +2966,6 @@ function OpenCommandPaletteDialog(props: { | ... | @@ -2966,9 +2966,6 @@ function OpenCommandPaletteDialog(props: { |
| 2966 | }) | 2966 | }) |
| 2967 | : undefined, | 2967 | : undefined, |
| 2968 | placeholder: inputPlaceholder, | 2968 | placeholder: inputPlaceholder, |
| 2969 | wrapperClassName: isSubmenu | ||
| 2970 | ? "[&_[data-slot=autocomplete-start-addon]]:pointer-events-auto" | ||
| 2971 | : undefined, | ||
| 2972 | ...(isSubmenu | 2969 | ...(isSubmenu |
| 2973 | ? { | 2970 | ? { |
| 2974 | startAddon: ( | 2971 | startAddon: ( |
apps/web/src/components/DiffPanel.tsx-2| ... | @@ -775,7 +775,6 @@ export default function DiffPanel({ | ... | @@ -775,7 +775,6 @@ export default function DiffPanel({ |
| 775 | <ComboboxList className="max-h-64 min-w-0 overflow-x-hidden"> | 775 | <ComboboxList className="max-h-64 min-w-0 overflow-x-hidden"> |
| 776 | <ComboboxItem | 776 | <ComboboxItem |
| 777 | className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]" | 777 | className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]" |
| 778 | contentClassName="w-full min-w-0 overflow-hidden" | ||
| 779 | value={AUTOMATIC_BASE_REF} | 778 | value={AUTOMATIC_BASE_REF} |
| 780 | > | 779 | > |
| 781 | <span className="block min-w-0 truncate">Automatic</span> | 780 | <span className="block min-w-0 truncate">Automatic</span> |
| ... | @@ -788,7 +787,6 @@ export default function DiffPanel({ | ... | @@ -788,7 +787,6 @@ export default function DiffPanel({ |
| 788 | <ComboboxItem | 787 | <ComboboxItem |
| 789 | key={choice.id} | 788 | key={choice.id} |
| 790 | className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]" | 789 | className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]" |
| 791 | contentClassName="w-full min-w-0 overflow-hidden" | ||
| 792 | value={item} | 790 | value={item} |
| 793 | > | 791 | > |
| 794 | <div className="grid w-full min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center overflow-hidden"> | 792 | <div className="grid w-full min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center overflow-hidden"> |
apps/web/src/components/RightPanelSheet.tsx+1-11| ... | @@ -1,16 +1,12 @@ | ... | @@ -1,16 +1,12 @@ |
| 1 | import { type ReactNode } from "react"; | 1 | import { type ReactNode } from "react"; |
| 2 | 2 | ||
| 3 | import { | 3 | import { RIGHT_PANEL_SHEET_CLASS_NAME } from "../rightPanelLayout"; |
| 4 | RIGHT_PANEL_SHEET_CLASS_NAME, | ||
| 5 | RIGHT_PANEL_SHEET_LAYER_CLASS_NAME, | ||
| 6 | } from "../rightPanelLayout"; | ||
| 7 | import { Sheet, SheetPopup } from "./ui/sheet"; | 4 | import { Sheet, SheetPopup } from "./ui/sheet"; |
| 8 | 5 | ||
| 9 | export function RightPanelSheet(props: { | 6 | export function RightPanelSheet(props: { |
| 10 | animationDurationMs: number; | 7 | animationDurationMs: number; |
| 11 | children: ReactNode; | 8 | children: ReactNode; |
| 12 | open: boolean; | 9 | open: boolean; |
| 13 | underFloatingPreview?: boolean; | ||
| 14 | onClose: () => void; | 10 | onClose: () => void; |
| 15 | }) { | 11 | }) { |
| 16 | return ( | 12 | return ( |
| ... | @@ -27,12 +23,6 @@ export function RightPanelSheet(props: { | ... | @@ -27,12 +23,6 @@ export function RightPanelSheet(props: { |
| 27 | side="right" | 23 | side="right" |
| 28 | showCloseButton={false} | 24 | showCloseButton={false} |
| 29 | keepMounted | 25 | keepMounted |
| 30 | {...(props.underFloatingPreview | ||
| 31 | ? { | ||
| 32 | backdropClassName: RIGHT_PANEL_SHEET_LAYER_CLASS_NAME, | ||
| 33 | viewportClassName: RIGHT_PANEL_SHEET_LAYER_CLASS_NAME, | ||
| 34 | } | ||
| 35 | : {})} | ||
| 36 | className={RIGHT_PANEL_SHEET_CLASS_NAME} | 26 | className={RIGHT_PANEL_SHEET_CLASS_NAME} |
| 37 | > | 27 | > |
| 38 | {props.children} | 28 | {props.children} |
apps/web/src/components/Sidebar.tsx+15-24| ... | @@ -235,7 +235,7 @@ import { | ... | @@ -235,7 +235,7 @@ import { |
| 235 | import { SidebarContent, SidebarGroup, useSidebar } from "./ui/sidebar"; | 235 | import { SidebarContent, SidebarGroup, useSidebar } from "./ui/sidebar"; |
| 236 | import { SidebarChromeFooter, SidebarChromeHeader } from "./sidebar/SidebarChrome"; | 236 | import { SidebarChromeFooter, SidebarChromeHeader } from "./sidebar/SidebarChrome"; |
| 237 | import { SidebarHeaderIconButton, SidebarThreadHeader } from "./sidebar/SidebarThreadHeader"; | 237 | import { SidebarHeaderIconButton, SidebarThreadHeader } from "./sidebar/SidebarThreadHeader"; |
| 238 | import { Popover, PopoverPopup, PopoverTrigger } from "./ui/popover"; | 238 | import { Menu, MenuItem, MenuPopup, MenuSeparator, MenuShortcut, MenuTrigger } from "./ui/menu"; |
| 239 | import { Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger } from "./ui/tooltip"; | 239 | import { Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger } from "./ui/tooltip"; |
| 240 | import { MiddleTruncate } from "./ui/middle-truncate"; | 240 | import { MiddleTruncate } from "./ui/middle-truncate"; |
| 241 | import { | 241 | import { |
| ... | @@ -440,7 +440,7 @@ function SidebarThreadTooltip({ | ... | @@ -440,7 +440,7 @@ function SidebarThreadTooltip({ |
| 440 | * Controlled by the row (which also uses the open state to pin its hover | 440 | * Controlled by the row (which also uses the open state to pin its hover |
| 441 | * actions while the menu is up). | 441 | * actions while the menu is up). |
| 442 | */ | 442 | */ |
| 443 | function SnoozePopoverButton(props: { | 443 | function SnoozeMenuButton(props: { |
| 444 | open: boolean; | 444 | open: boolean; |
| 445 | onOpenChange: (open: boolean) => void; | 445 | onOpenChange: (open: boolean) => void; |
| 446 | onSnooze: (preset: Pick<SnoozePreset, "snoozedUntil">) => void; | 446 | onSnooze: (preset: Pick<SnoozePreset, "snoozedUntil">) => void; |
| ... | @@ -454,11 +454,11 @@ function SnoozePopoverButton(props: { | ... | @@ -454,11 +454,11 @@ function SnoozePopoverButton(props: { |
| 454 | [open, timestampFormat], | 454 | [open, timestampFormat], |
| 455 | ); | 455 | ); |
| 456 | return ( | 456 | return ( |
| 457 | <Popover open={open} onOpenChange={onOpenChange}> | 457 | <Menu open={open} onOpenChange={onOpenChange}> |
| 458 | <Tooltip> | 458 | <Tooltip> |
| 459 | <TooltipTrigger | 459 | <TooltipTrigger |
| 460 | render={ | 460 | render={ |
| 461 | <PopoverTrigger | 461 | <MenuTrigger |
| 462 | render={ | 462 | render={ |
| 463 | <button | 463 | <button |
| 464 | type="button" | 464 | type="button" |
| ... | @@ -475,39 +475,31 @@ function SnoozePopoverButton(props: { | ... | @@ -475,39 +475,31 @@ function SnoozePopoverButton(props: { |
| 475 | </TooltipTrigger> | 475 | </TooltipTrigger> |
| 476 | <TooltipPopup>Snooze thread</TooltipPopup> | 476 | <TooltipPopup>Snooze thread</TooltipPopup> |
| 477 | </Tooltip> | 477 | </Tooltip> |
| 478 | <PopoverPopup side="bottom" align="end" width="sm" viewportClassName="p-1"> | 478 | <MenuPopup side="bottom" align="end"> |
| 479 | {presets.map((preset) => ( | 479 | {presets.map((preset) => ( |
| 480 | <button | 480 | <MenuItem |
| 481 | key={preset.id} | 481 | key={preset.id} |
| 482 | type="button" | ||
| 483 | onClick={(event) => { | 482 | onClick={(event) => { |
| 484 | event.stopPropagation(); | 483 | event.stopPropagation(); |
| 485 | onOpenChange(false); | ||
| 486 | onSnooze(preset); | 484 | onSnooze(preset); |
| 487 | }} | 485 | }} |
| 488 | className="flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs text-foreground/90 hover:bg-accent hover:text-foreground" | ||
| 489 | > | 486 | > |
| 490 | <span className="flex-1">{preset.label}</span> | 487 | {preset.label} |
| 491 | <span className="font-mono text-[10px] text-muted-foreground/60 tabular-nums"> | 488 | <MenuShortcut>{preset.whenLabel}</MenuShortcut> |
| 492 | {preset.whenLabel} | 489 | </MenuItem> |
| 493 | </span> | ||
| 494 | </button> | ||
| 495 | ))} | 490 | ))} |
| 496 | <div className="my-1 border-t border-border/60" /> | 491 | <MenuSeparator /> |
| 497 | <button | 492 | <MenuItem |
| 498 | type="button" | ||
| 499 | className="flex w-full cursor-pointer rounded-md px-2 py-1.5 text-left text-xs text-foreground/90 hover:bg-accent hover:text-foreground" | ||
| 500 | onClick={async (event) => { | 493 | onClick={async (event) => { |
| 501 | event.stopPropagation(); | 494 | event.stopPropagation(); |
| 502 | onOpenChange(false); | ||
| 503 | const choice = await requestCustomSnooze(); | 495 | const choice = await requestCustomSnooze(); |
| 504 | if (choice) onSnooze(choice); | 496 | if (choice) onSnooze(choice); |
| 505 | }} | 497 | }} |
| 506 | > | 498 | > |
| 507 | Custom… | 499 | Custom… |
| 508 | </button> | 500 | </MenuItem> |
| 509 | </PopoverPopup> | 501 | </MenuPopup> |
| 510 | </Popover> | 502 | </Menu> |
| 511 | ); | 503 | ); |
| 512 | } | 504 | } |
| 513 | 505 | ||
| ... | @@ -1883,7 +1875,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -1883,7 +1875,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 1883 | </Tooltip> | 1875 | </Tooltip> |
| 1884 | ) : null} | 1876 | ) : null} |
| 1885 | {showSnoozeButton ? ( | 1877 | {showSnoozeButton ? ( |
| 1886 | <SnoozePopoverButton | 1878 | <SnoozeMenuButton |
| 1887 | open={snoozeMenuOpen} | 1879 | open={snoozeMenuOpen} |
| 1888 | onOpenChange={setSnoozeMenuOpen} | 1880 | onOpenChange={setSnoozeMenuOpen} |
| 1889 | onSnooze={handleSnoozePreset} | 1881 | onSnooze={handleSnoozePreset} |
| ... | @@ -4492,7 +4484,6 @@ export default function Sidebar() { | ... | @@ -4492,7 +4484,6 @@ export default function Sidebar() { |
| 4492 | hideIndicator | 4484 | hideIndicator |
| 4493 | value={item} | 4485 | value={item} |
| 4494 | className="font-medium" | 4486 | className="font-medium" |
| 4495 | contentClassName="flex min-w-0 items-center gap-2" | ||
| 4496 | onContextMenu={(event) => { | 4487 | onContextMenu={(event) => { |
| 4497 | if (project) handleProjectSettings(event, project); | 4488 | if (project) handleProjectSettings(event, project); |
| 4498 | }} | 4489 | }} |
apps/web/src/components/chat/AssistantCitationChip.tsx+1-1| ... | @@ -171,7 +171,7 @@ export function AssistantCitationChip({ | ... | @@ -171,7 +171,7 @@ export function AssistantCitationChip({ |
| 171 | }} | 171 | }} |
| 172 | aria-label="Edit citation comment" | 172 | aria-label="Edit citation comment" |
| 173 | width="md" | 173 | width="md" |
| 174 | viewportClassName="p-3" | 174 | padding="compact" |
| 175 | onPointerDown={(event) => event.stopPropagation()} | 175 | onPointerDown={(event) => event.stopPropagation()} |
| 176 | > | 176 | > |
| 177 | <AssistantCitationCommentEditor | 177 | <AssistantCitationCommentEditor |
apps/web/src/components/chat/ContextWindowMeter.tsx+1-1| ... | @@ -88,7 +88,7 @@ export function ContextWindowMeter(props: { | ... | @@ -88,7 +88,7 @@ export function ContextWindowMeter(props: { |
| 88 | tooltipStyle | 88 | tooltipStyle |
| 89 | side="top" | 89 | side="top" |
| 90 | align="end" | 90 | align="end" |
| 91 | viewportClassName="p-0" | 91 | padding="none" |
| 92 | width="sm" | 92 | width="sm" |
| 93 | className="text-left whitespace-normal" | 93 | className="text-left whitespace-normal" |
| 94 | > | 94 | > |
apps/web/src/components/chat/ExpandedImageDialog.tsx-2| ... | @@ -179,8 +179,6 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({ | ... | @@ -179,8 +179,6 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({ |
| 179 | variant="media" | 179 | variant="media" |
| 180 | showCloseButton={false} | 180 | showCloseButton={false} |
| 181 | bottomStickOnMobile={false} | 181 | bottomStickOnMobile={false} |
| 182 | backdropClassName="z-[60]" | ||
| 183 | viewportClassName="z-[60] grid-rows-1 place-items-center px-4 py-6 [-webkit-app-region:no-drag]" | ||
| 184 | className="row-start-1 max-h-[92vh] w-[92vw] max-w-[92vw] items-center overflow-visible [--media-width:92vw] [--media-height:min(86vh,calc(100vh-160px))] sm:[--media-width:calc(92vw-96px)]" | 182 | className="row-start-1 max-h-[92vh] w-[92vw] max-w-[92vw] items-center overflow-visible [--media-width:92vw] [--media-height:min(86vh,calc(100vh-160px))] sm:[--media-width:calc(92vw-96px)]" |
| 185 | onKeyDown={onKeyDown} | 183 | onKeyDown={onKeyDown} |
| 186 | initialFocus={closeButtonRef} | 184 | initialFocus={closeButtonRef} |
apps/web/src/components/chat/MessagesTimeline.tsx+1-1| ... | @@ -2567,7 +2567,7 @@ function BackgroundWorktreeSetupChip({ snapshot }: { snapshot: WorktreeSetupSnap | ... | @@ -2567,7 +2567,7 @@ function BackgroundWorktreeSetupChip({ snapshot }: { snapshot: WorktreeSetupSnap |
| 2567 | align="end" | 2567 | align="end" |
| 2568 | width="lg" | 2568 | width="lg" |
| 2569 | className="surface-glass!" | 2569 | className="surface-glass!" |
| 2570 | viewportClassName="py-3 [--viewport-inline-padding:--spacing(3)]" | 2570 | padding="compact" |
| 2571 | > | 2571 | > |
| 2572 | <WorktreeSetupCard | 2572 | <WorktreeSetupCard |
| 2573 | snapshot={snapshot} | 2573 | snapshot={snapshot} |
apps/web/src/components/chat/ModelListRow.tsx-1| ... | @@ -52,7 +52,6 @@ export const ModelListRow = memo(function ModelListRow(props: { | ... | @@ -52,7 +52,6 @@ export const ModelListRow = memo(function ModelListRow(props: { |
| 52 | index={props.index} | 52 | index={props.index} |
| 53 | value={modelPickerModelKey(props.instanceId, props.model.slug)} | 53 | value={modelPickerModelKey(props.instanceId, props.model.slug)} |
| 54 | disabled={Boolean(props.disabledReason)} | 54 | disabled={Boolean(props.disabledReason)} |
| 55 | contentClassName="flex w-full items-center gap-3" | ||
| 56 | className={cn( | 55 | className={cn( |
| 57 | "group relative w-full !min-w-0 max-w-full cursor-pointer rounded-md px-2 py-2 transition-[background-color,box-shadow,color]", | 56 | "group relative w-full !min-w-0 max-w-full cursor-pointer rounded-md px-2 py-2 transition-[background-color,box-shadow,color]", |
| 58 | "hover:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-highlighted:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-selected:bg-foreground/[0.08] data-selected:text-foreground data-selected:ring-0 [&[data-highlighted][data-selected]]:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))]", | 57 | "hover:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-highlighted:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-selected:bg-foreground/[0.08] data-selected:text-foreground data-selected:ring-0 [&[data-highlighted][data-selected]]:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))]", |
apps/web/src/components/chat/ModelPickerContent.tsx+57-73| ... | @@ -8,7 +8,7 @@ import { resolveSelectableModel } from "@t3tools/shared/model"; | ... | @@ -8,7 +8,7 @@ import { resolveSelectableModel } from "@t3tools/shared/model"; |
| 8 | import { useAtomValue } from "@effect/atom-react"; | 8 | import { useAtomValue } from "@effect/atom-react"; |
| 9 | import { LegendList, type LegendListRef } from "@legendapp/list/react"; | 9 | import { LegendList, type LegendListRef } from "@legendapp/list/react"; |
| 10 | import { memo, useMemo, useState, useCallback, useEffect, useLayoutEffect, useRef } from "react"; | 10 | import { memo, useMemo, useState, useCallback, useEffect, useLayoutEffect, useRef } from "react"; |
| 11 | import { ChevronRightIcon, SearchIcon } from "lucide-react"; | 11 | import { ChevronRightIcon } from "lucide-react"; |
| 12 | import { ModelListRow } from "./ModelListRow"; | 12 | import { ModelListRow } from "./ModelListRow"; |
| 13 | import { ModelPickerSidebar } from "./ModelPickerSidebar"; | 13 | import { ModelPickerSidebar } from "./ModelPickerSidebar"; |
| 14 | import { getProviderStatusMessage, hasProviderSetup } from "./ProviderStatusBanner"; | 14 | import { getProviderStatusMessage, hasProviderSetup } from "./ProviderStatusBanner"; |
| ... | @@ -22,7 +22,7 @@ import { buildModelPickerSearchText, scoreModelPickerSearch } from "./modelPicke | ... | @@ -22,7 +22,7 @@ import { buildModelPickerSearchText, scoreModelPickerSearch } from "./modelPicke |
| 22 | import { | 22 | import { |
| 23 | Combobox, | 23 | Combobox, |
| 24 | ComboboxEmpty, | 24 | ComboboxEmpty, |
| 25 | ComboboxInput, | 25 | ComboboxSearchInput, |
| 26 | ComboboxItem, | 26 | ComboboxItem, |
| 27 | ComboboxListVirtualized, | 27 | ComboboxListVirtualized, |
| 28 | } from "../ui/combobox"; | 28 | } from "../ui/combobox"; |
| ... | @@ -882,77 +882,62 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: { | ... | @@ -882,77 +882,62 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: { |
| 882 | showSidebar && "border-l border-border/70", | 882 | showSidebar && "border-l border-border/70", |
| 883 | )} | 883 | )} |
| 884 | > | 884 | > |
| 885 | {/* Search bar */} | 885 | <ComboboxSearchInput |
| 886 | <div className="px-2 pt-2"> | 886 | ref={searchInputRef} |
| 887 | <div className="border-b border-border/70 pb-2.5 transition-colors focus-within:border-ring"> | 887 | placeholder="Search models..." |
| 888 | <ComboboxInput | 888 | value={searchQuery} |
| 889 | ref={searchInputRef} | 889 | onChange={(e) => setSearchQuery(e.target.value)} |
| 890 | className="[&_input]:h-6.5 [&_input]:font-sans [&_input]:leading-6.5" | 890 | onKeyDown={(e) => { |
| 891 | inputClassName="rounded-none bg-transparent text-sm" | 891 | if ( |
| 892 | placeholder="Search models..." | 892 | showSidebar && |
| 893 | showTrigger={false} | 893 | !e.altKey && |
| 894 | startAddon={ | 894 | !e.ctrlKey && |
| 895 | <SearchIcon className="-translate-x-0.5 size-4 shrink-0 text-muted-foreground opacity-70" /> | 895 | !e.metaKey && |
| 896 | } | 896 | ((e.key === "ArrowLeft" && !e.shiftKey && searchQuery.length === 0) || |
| 897 | value={searchQuery} | 897 | (e.key === "Tab" && e.shiftKey)) |
| 898 | onChange={(e) => setSearchQuery(e.target.value)} | 898 | ) { |
| 899 | onKeyDown={(e) => { | 899 | const sidebar = e.currentTarget |
| 900 | if ( | 900 | .closest("[data-model-picker-content]") |
| 901 | showSidebar && | 901 | ?.querySelector("[data-model-picker-sidebar]"); |
| 902 | !e.altKey && | 902 | const button = |
| 903 | !e.ctrlKey && | 903 | sidebar?.querySelector<HTMLButtonElement>( |
| 904 | !e.metaKey && | 904 | 'button[aria-pressed="true"]:not(:disabled)', |
| 905 | ((e.key === "ArrowLeft" && !e.shiftKey && searchQuery.length === 0) || | 905 | ) ?? sidebar?.querySelector<HTMLButtonElement>("button:not(:disabled)"); |
| 906 | (e.key === "Tab" && e.shiftKey)) | 906 | if (button) { |
| 907 | ) { | 907 | e.preventDefault(); |
| 908 | const sidebar = e.currentTarget | ||
| 909 | .closest("[data-model-picker-content]") | ||
| 910 | ?.querySelector("[data-model-picker-sidebar]"); | ||
| 911 | const button = | ||
| 912 | sidebar?.querySelector<HTMLButtonElement>( | ||
| 913 | 'button[aria-pressed="true"]:not(:disabled)', | ||
| 914 | ) ?? sidebar?.querySelector<HTMLButtonElement>("button:not(:disabled)"); | ||
| 915 | if (button) { | ||
| 916 | e.preventDefault(); | ||
| 917 | e.stopPropagation(); | ||
| 918 | button.focus(); | ||
| 919 | return; | ||
| 920 | } | ||
| 921 | } | ||
| 922 | if (e.key === "Escape") { | ||
| 923 | e.preventDefault(); | ||
| 924 | e.stopPropagation(); | ||
| 925 | props.onRequestClose?.(); | ||
| 926 | return; | ||
| 927 | } | ||
| 928 | if (e.key === "Enter" && highlightedModelKeyRef.current) { | ||
| 929 | ( | ||
| 930 | e as typeof e & { preventBaseUIHandler?: () => void } | ||
| 931 | ).preventBaseUIHandler?.(); | ||
| 932 | e.preventDefault(); | ||
| 933 | e.stopPropagation(); | ||
| 934 | const legacyInstanceId = parseModelPickerLegacySectionKey( | ||
| 935 | highlightedModelKeyRef.current, | ||
| 936 | ); | ||
| 937 | if (legacyInstanceId) { | ||
| 938 | toggleLegacySection(legacyInstanceId); | ||
| 939 | return; | ||
| 940 | } | ||
| 941 | const model = parseModelPickerModelKey(highlightedModelKeyRef.current); | ||
| 942 | if (model) { | ||
| 943 | handleModelSelect(model.slug, model.instanceId, e.shiftKey); | ||
| 944 | } | ||
| 945 | return; | ||
| 946 | } | ||
| 947 | e.stopPropagation(); | 908 | e.stopPropagation(); |
| 948 | }} | 909 | button.focus(); |
| 949 | onMouseDown={(e) => e.stopPropagation()} | 910 | return; |
| 950 | onTouchStart={(e) => e.stopPropagation()} | 911 | } |
| 951 | size="sm" | 912 | } |
| 952 | unstyled | 913 | if (e.key === "Escape") { |
| 953 | /> | 914 | e.preventDefault(); |
| 954 | </div> | 915 | e.stopPropagation(); |
| 955 | </div> | 916 | props.onRequestClose?.(); |
| 917 | return; | ||
| 918 | } | ||
| 919 | if (e.key === "Enter" && highlightedModelKeyRef.current) { | ||
| 920 | (e as typeof e & { preventBaseUIHandler?: () => void }).preventBaseUIHandler?.(); | ||
| 921 | e.preventDefault(); | ||
| 922 | e.stopPropagation(); | ||
| 923 | const legacyInstanceId = parseModelPickerLegacySectionKey( | ||
| 924 | highlightedModelKeyRef.current, | ||
| 925 | ); | ||
| 926 | if (legacyInstanceId) { | ||
| 927 | toggleLegacySection(legacyInstanceId); | ||
| 928 | return; | ||
| 929 | } | ||
| 930 | const model = parseModelPickerModelKey(highlightedModelKeyRef.current); | ||
| 931 | if (model) { | ||
| 932 | handleModelSelect(model.slug, model.instanceId, e.shiftKey); | ||
| 933 | } | ||
| 934 | return; | ||
| 935 | } | ||
| 936 | e.stopPropagation(); | ||
| 937 | }} | ||
| 938 | onMouseDown={(e) => e.stopPropagation()} | ||
| 939 | onTouchStart={(e) => e.stopPropagation()} | ||
| 940 | /> | ||
| 956 | 941 | ||
| 957 | {/* Model list */} | 942 | {/* Model list */} |
| 958 | <div className="relative min-h-0 flex-1 overflow-hidden pr-px"> | 943 | <div className="relative min-h-0 flex-1 overflow-hidden pr-px"> |
| ... | @@ -971,7 +956,6 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: { | ... | @@ -971,7 +956,6 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: { |
| 971 | value={modelKey} | 956 | value={modelKey} |
| 972 | aria-expanded={legacySection.isExpanded} | 957 | aria-expanded={legacySection.isExpanded} |
| 973 | className="group w-full cursor-pointer rounded-md px-2 py-2" | 958 | className="group w-full cursor-pointer rounded-md px-2 py-2" |
| 974 | contentClassName="flex w-full items-center gap-3" | ||
| 975 | > | 959 | > |
| 976 | <div className="min-w-0 flex-1 text-left"> | 960 | <div className="min-w-0 flex-1 text-left"> |
| 977 | <div className="text-xs font-medium leading-snug">Legacy models</div> | 961 | <div className="text-xs font-medium leading-snug">Legacy models</div> |
apps/web/src/components/chat/ProviderModelPicker.tsx+2-2| ... | @@ -284,8 +284,8 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { | ... | @@ -284,8 +284,8 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { |
| 284 | <PopoverPopup | 284 | <PopoverPopup |
| 285 | {...(props.isComposerOwned ? composerFloatingLayerProps : {})} | 285 | {...(props.isComposerOwned ? composerFloatingLayerProps : {})} |
| 286 | align="start" | 286 | align="start" |
| 287 | className="before:hidden [--viewport-inline-padding:0]" | 287 | className="before:hidden" |
| 288 | viewportClassName="overflow-hidden! rounded-[calc(var(--radius-lg)-1px)] p-0 [clip-path:inset(0_round_calc(var(--radius-lg)-1px))]" | 288 | padding="none" |
| 289 | > | 289 | > |
| 290 | <ModelPickerContent | 290 | <ModelPickerContent |
| 291 | activeInstanceId={activeInstanceId} | 291 | activeInstanceId={activeInstanceId} |
apps/web/src/components/chat/SnapShotAttachmentDetails.tsx+2-7| ... | @@ -163,13 +163,8 @@ export function SnapShotContentsButton({ | ... | @@ -163,13 +163,8 @@ export function SnapShotContentsButton({ |
| 163 | </TooltipTrigger> | 163 | </TooltipTrigger> |
| 164 | <TooltipPopup side={side}>{tooltip}</TooltipPopup> | 164 | <TooltipPopup side={side}>{tooltip}</TooltipPopup> |
| 165 | </Tooltip> | 165 | </Tooltip> |
| 166 | <PopoverPopup | 166 | <PopoverPopup side={side} align="center" width="md"> |
| 167 | side={side} | 167 | <div className="max-h-[min(28rem,70vh)] space-y-2 overflow-y-auto"> |
| 168 | align="center" | ||
| 169 | width="md" | ||
| 170 | viewportClassName="max-h-[min(28rem,70vh)]" | ||
| 171 | > | ||
| 172 | <div className="space-y-2"> | ||
| 173 | <PopoverTitle>Accessibility data</PopoverTitle> | 168 | <PopoverTitle>Accessibility data</PopoverTitle> |
| 174 | {accessibilityDetails ? ( | 169 | {accessibilityDetails ? ( |
| 175 | <SnapShotAccessibilityData | 170 | <SnapShotAccessibilityData |
apps/web/src/components/chat/TerminalContextInlineChip.tsx-2| ... | @@ -23,8 +23,6 @@ export function TerminalContextInlineChip(props: TerminalContextInlineChipProps) | ... | @@ -23,8 +23,6 @@ export function TerminalContextInlineChip(props: TerminalContextInlineChipProps) |
| 23 | icon={<TerminalIcon />} | 23 | icon={<TerminalIcon />} |
| 24 | label={label} | 24 | label={label} |
| 25 | accessibleLabel={`Terminal excerpt, ${label}`} | 25 | accessibleLabel={`Terminal excerpt, ${label}`} |
| 26 | popupClassName="w-[min(40rem,calc(100vw-2rem))]" | ||
| 27 | viewportClassName="overflow-hidden p-2" | ||
| 28 | > | 26 | > |
| 29 | <div className="overflow-hidden rounded-md border border-border/70 bg-background/80"> | 27 | <div className="overflow-hidden rounded-md border border-border/70 bg-background/80"> |
| 30 | <div className="flex items-center gap-2 border-b border-border/70 px-3 py-2"> | 28 | <div className="flex items-center gap-2 border-b border-border/70 px-3 py-2"> |
apps/web/src/components/contextChipParts.tsx+1-9| ... | @@ -8,7 +8,6 @@ import { | ... | @@ -8,7 +8,6 @@ import { |
| 8 | type ReactNode, | 8 | type ReactNode, |
| 9 | } from "react"; | 9 | } from "react"; |
| 10 | 10 | ||
| 11 | import { cn } from "~/lib/utils"; | ||
| 12 | import { PULL_REQUEST_STATE_PRESENTATION } from "~/components/pullRequest/pullRequestIcons"; | 11 | import { PULL_REQUEST_STATE_PRESENTATION } from "~/components/pullRequest/pullRequestIcons"; |
| 13 | import type { PullRequestContextDisplayState } from "~/lib/composerContextRecords"; | 12 | import type { PullRequestContextDisplayState } from "~/lib/composerContextRecords"; |
| 14 | import { PierreEntryIcon } from "./chat/PierreEntryIcon"; | 13 | import { PierreEntryIcon } from "./chat/PierreEntryIcon"; |
| ... | @@ -70,8 +69,6 @@ export function ContextChipPopover(props: { | ... | @@ -70,8 +69,6 @@ export function ContextChipPopover(props: { |
| 70 | copyMarkdown?: string; | 69 | copyMarkdown?: string; |
| 71 | accessibleLabel: string; | 70 | accessibleLabel: string; |
| 72 | children: ReactNode; | 71 | children: ReactNode; |
| 73 | popupClassName?: string; | ||
| 74 | viewportClassName?: string; | ||
| 75 | }) { | 72 | }) { |
| 76 | return ( | 73 | return ( |
| 77 | <Popover> | 74 | <Popover> |
| ... | @@ -88,12 +85,7 @@ export function ContextChipPopover(props: { | ... | @@ -88,12 +85,7 @@ export function ContextChipPopover(props: { |
| 88 | {props.icon} | 85 | {props.icon} |
| 89 | <ContextChipLabel>{props.label}</ContextChipLabel> | 86 | <ContextChipLabel>{props.label}</ContextChipLabel> |
| 90 | </PopoverTrigger> | 87 | </PopoverTrigger> |
| 91 | <PopoverPopup | 88 | <PopoverPopup side="top" width="lg" padding="compact"> |
| 92 | side="top" | ||
| 93 | width="lg" | ||
| 94 | className={props.popupClassName} | ||
| 95 | viewportClassName={cn("overflow-x-auto p-2", props.viewportClassName)} | ||
| 96 | > | ||
| 97 | <PopoverTitle className="sr-only">{props.accessibleLabel}</PopoverTitle> | 89 | <PopoverTitle className="sr-only">{props.accessibleLabel}</PopoverTitle> |
| 98 | {props.children} | 90 | {props.children} |
| 99 | </PopoverPopup> | 91 | </PopoverPopup> |
apps/web/src/components/preview/previewMiniPlayerLayout.ts+1-1| ... | @@ -11,7 +11,7 @@ import type { DeviceScreenSize } from "@t3tools/client-runtime/device/stream"; | ... | @@ -11,7 +11,7 @@ import type { DeviceScreenSize } from "@t3tools/client-runtime/device/stream"; |
| 11 | 11 | ||
| 12 | export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12; | 12 | export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12; |
| 13 | export const PREVIEW_MINI_PLAYER_CORNER_RADIUS = 12; | 13 | export const PREVIEW_MINI_PLAYER_CORNER_RADIUS = 12; |
| 14 | // The mini-player shell straddles this webview at 47 and 49; dialogs begin at 50. | 14 | // The mini-player shell straddles this webview at 47 and 49: above --z-sheet, under dialogs (50). |
| 15 | export const PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX = 48; | 15 | export const PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX = 48; |
| 16 | // A fresh player is the largest box at the source aspect ratio that fits here. | 16 | // A fresh player is the largest box at the source aspect ratio that fits here. |
| 17 | const PREVIEW_MINI_PLAYER_DEFAULT_BOX = { width: 320, height: 320 } as const; | 17 | const PREVIEW_MINI_PLAYER_DEFAULT_BOX = { width: 320, height: 320 } as const; |
apps/web/src/components/pullRequest/PullRequestCandidatePicker.tsx-1| ... | @@ -147,7 +147,6 @@ export function PullRequestCandidatePicker<T>({ | ... | @@ -147,7 +147,6 @@ export function PullRequestCandidatePicker<T>({ |
| 147 | index={index} | 147 | index={index} |
| 148 | value={keys[index]} | 148 | value={keys[index]} |
| 149 | disabled={disabled} | 149 | disabled={disabled} |
| 150 | contentClassName="flex min-w-0 items-center gap-2" | ||
| 151 | > | 150 | > |
| 152 | {children(candidate)} | 151 | {children(candidate)} |
| 153 | </ComboboxItem> | 152 | </ComboboxItem> |
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+1-6| ... | @@ -388,12 +388,7 @@ function PullRequestBaseFreshnessWarning({ | ... | @@ -388,12 +388,7 @@ function PullRequestBaseFreshnessWarning({ |
| 388 | {children} | 388 | {children} |
| 389 | <TriangleAlertIcon aria-hidden className={cn("size-3.5 shrink-0", iconClassName)} /> | 389 | <TriangleAlertIcon aria-hidden className={cn("size-3.5 shrink-0", iconClassName)} /> |
| 390 | </PopoverTrigger> | 390 | </PopoverTrigger> |
| 391 | <PopoverPopup | 391 | <PopoverPopup align="start" side="bottom" className="max-w-80" padding="compact"> |
| 392 | align="start" | ||
| 393 | side="bottom" | ||
| 394 | className="max-w-80" | ||
| 395 | viewportClassName="py-2.5 [--viewport-inline-padding:--spacing(3)]" | ||
| 396 | > | ||
| 397 | <p className="text-xs text-foreground">{summary}</p> | 392 | <p className="text-xs text-foreground">{summary}</p> |
| 398 | <p className="mt-0.5 text-xs text-muted-foreground">Changes can be cleanly merged.</p> | 393 | <p className="mt-0.5 text-xs text-muted-foreground">Changes can be cleanly merged.</p> |
| 399 | {/* Each way the host offers and this reader may take, as its own button: a split button | 394 | {/* Each way the host offers and this reader may take, as its own button: a split button |
apps/web/src/components/pullRequest/PullRequestReactions.tsx+1-1| ... | @@ -134,7 +134,7 @@ export function PullRequestReactionBar({ | ... | @@ -134,7 +134,7 @@ export function PullRequestReactionBar({ |
| 134 | > | 134 | > |
| 135 | <SmilePlusIcon aria-hidden className="size-3.5" /> | 135 | <SmilePlusIcon aria-hidden className="size-3.5" /> |
| 136 | </PopoverTrigger> | 136 | </PopoverTrigger> |
| 137 | <PopoverPopup align="start" side="top" viewportClassName="py-2"> | 137 | <PopoverPopup align="start" side="top" padding="compact"> |
| 138 | <div className="flex items-center gap-0.5"> | 138 | <div className="flex items-center gap-0.5"> |
| 139 | {PULL_REQUEST_REACTION_ORDER.map((content) => { | 139 | {PULL_REQUEST_REACTION_ORDER.map((content) => { |
| 140 | const reacted = | 140 | const reacted = |
apps/web/src/components/settings/SettingInheritance.tsx+1-5| ... | @@ -223,11 +223,7 @@ export function SettingInheritance({ | ... | @@ -223,11 +223,7 @@ export function SettingInheritance({ |
| 223 | </TooltipTrigger> | 223 | </TooltipTrigger> |
| 224 | <TooltipPopup side="top">{overrideSummary}</TooltipPopup> | 224 | <TooltipPopup side="top">{overrideSummary}</TooltipPopup> |
| 225 | </Tooltip> | 225 | </Tooltip> |
| 226 | <PopoverPopup | 226 | <PopoverPopup align="start" width="md" padding="none"> |
| 227 | align="start" | ||
| 228 | width="md" | ||
| 229 | viewportClassName="p-0 [--viewport-inline-padding:0px]" | ||
| 230 | > | ||
| 231 | <div className="divide-y divide-border/60"> | 227 | <div className="divide-y divide-border/60"> |
| 232 | {chains.map(({ target, environment, machine, layers }) => ( | 228 | {chains.map(({ target, environment, machine, layers }) => ( |
| 233 | <section | 229 | <section |
apps/web/src/components/ui/autocomplete.tsx+1-1| ... | @@ -30,7 +30,7 @@ function AutocompleteInput({ | ... | @@ -30,7 +30,7 @@ function AutocompleteInput({ |
| 30 | {startAddon && ( | 30 | {startAddon && ( |
| 31 | <div | 31 | <div |
| 32 | aria-hidden="true" | 32 | aria-hidden="true" |
| 33 | className="[&_svg]:-mx-0.5 pointer-events-none absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 has-[+[data-size=sm]]:ps-[calc(--spacing(2.5)-1px)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4" | 33 | className="[&_svg]:-mx-0.5 pointer-events-none has-[button]:pointer-events-auto absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 has-[+[data-size=sm]]:ps-[calc(--spacing(2.5)-1px)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4" |
| 34 | data-slot="autocomplete-start-addon" | 34 | data-slot="autocomplete-start-addon" |
| 35 | > | 35 | > |
| 36 | {startAddon} | 36 | {startAddon} |
apps/web/src/components/ui/combobox.tsx+6-10| ... | @@ -30,7 +30,6 @@ function Combobox<Value, Multiple extends boolean | undefined = false>( | ... | @@ -30,7 +30,6 @@ function Combobox<Value, Multiple extends boolean | undefined = false>( |
| 30 | 30 | ||
| 31 | function ComboboxInput({ | 31 | function ComboboxInput({ |
| 32 | className, | 32 | className, |
| 33 | inputClassName, | ||
| 34 | showTrigger = true, | 33 | showTrigger = true, |
| 35 | showClear = false, | 34 | showClear = false, |
| 36 | startAddon, | 35 | startAddon, |
| ... | @@ -38,7 +37,6 @@ function ComboboxInput({ | ... | @@ -38,7 +37,6 @@ function ComboboxInput({ |
| 38 | unstyled = false, | 37 | unstyled = false, |
| 39 | ...props | 38 | ...props |
| 40 | }: Omit<ComboboxPrimitive.Input.Props, "size"> & { | 39 | }: Omit<ComboboxPrimitive.Input.Props, "size"> & { |
| 41 | inputClassName?: string; | ||
| 42 | showTrigger?: boolean; | 40 | showTrigger?: boolean; |
| 43 | showClear?: boolean; | 41 | showClear?: boolean; |
| 44 | startAddon?: React.ReactNode; | 42 | startAddon?: React.ReactNode; |
| ... | @@ -71,7 +69,10 @@ function ComboboxInput({ | ... | @@ -71,7 +69,10 @@ function ComboboxInput({ |
| 71 | data-slot="combobox-input" | 69 | data-slot="combobox-input" |
| 72 | render={ | 70 | render={ |
| 73 | <Input | 71 | <Input |
| 74 | className={cn("has-disabled:opacity-100", inputClassName)} | 72 | className={cn( |
| 73 | "has-disabled:opacity-100", | ||
| 74 | unstyled && "rounded-none bg-transparent text-sm", | ||
| 75 | )} | ||
| 75 | nativeInput | 76 | nativeInput |
| 76 | size={sizeValue} | 77 | size={sizeValue} |
| 77 | unstyled={unstyled} | 78 | unstyled={unstyled} |
| ... | @@ -116,7 +117,6 @@ function ComboboxSearchInput(props: React.ComponentProps<typeof ComboboxInput>) | ... | @@ -116,7 +117,6 @@ function ComboboxSearchInput(props: React.ComponentProps<typeof ComboboxInput>) |
| 116 | <ComboboxInput | 117 | <ComboboxInput |
| 117 | {...props} | 118 | {...props} |
| 118 | className="[&_input]:h-6.5 [&_input]:ps-5 [&_input]:font-sans [&_input]:leading-6.5" | 119 | className="[&_input]:h-6.5 [&_input]:ps-5 [&_input]:font-sans [&_input]:leading-6.5" |
| 119 | inputClassName="rounded-none bg-transparent text-sm" | ||
| 120 | showTrigger={false} | 120 | showTrigger={false} |
| 121 | size="sm" | 121 | size="sm" |
| 122 | unstyled | 122 | unstyled |
| ... | @@ -185,12 +185,10 @@ function ComboboxPopup({ | ... | @@ -185,12 +185,10 @@ function ComboboxPopup({ |
| 185 | 185 | ||
| 186 | function ComboboxItem({ | 186 | function ComboboxItem({ |
| 187 | className, | 187 | className, |
| 188 | contentClassName, | ||
| 189 | children, | 188 | children, |
| 190 | hideIndicator: _hideIndicator = false, | 189 | hideIndicator: _hideIndicator = false, |
| 191 | ...props | 190 | ...props |
| 192 | }: ComboboxPrimitive.Item.Props & { | 191 | }: ComboboxPrimitive.Item.Props & { |
| 193 | contentClassName?: string; | ||
| 194 | hideIndicator?: boolean; | 192 | hideIndicator?: boolean; |
| 195 | }) { | 193 | }) { |
| 196 | return ( | 194 | return ( |
| ... | @@ -202,11 +200,9 @@ function ComboboxItem({ | ... | @@ -202,11 +200,9 @@ function ComboboxItem({ |
| 202 | data-slot="combobox-item" | 200 | data-slot="combobox-item" |
| 203 | {...props} | 201 | {...props} |
| 204 | > | 202 | > |
| 203 | {/* Children lay out as one row: a label that truncates, then any trailing meta. */} | ||
| 205 | <div | 204 | <div |
| 206 | className={cn( | 205 | className="flex min-w-0 flex-1 items-center gap-2 [&_svg:not([class*='text-'])]:text-muted-foreground" |
| 207 | "min-w-0 flex-1 [&_svg:not([class*='text-'])]:text-muted-foreground", | ||
| 208 | contentClassName, | ||
| 209 | )} | ||
| 210 | data-slot="combobox-item-content" | 206 | data-slot="combobox-item-content" |
| 211 | > | 207 | > |
| 212 | {children} | 208 | {children} |
apps/web/src/components/ui/command.tsx+2-10| ... | @@ -93,19 +93,11 @@ function Command({ | ... | @@ -93,19 +93,11 @@ function Command({ |
| 93 | 93 | ||
| 94 | function CommandInput({ | 94 | function CommandInput({ |
| 95 | className, | 95 | className, |
| 96 | wrapperClassName, | ||
| 97 | placeholder, | 96 | placeholder, |
| 98 | ...props | 97 | ...props |
| 99 | }: React.ComponentProps<typeof AutocompleteInput> & { | 98 | }: React.ComponentProps<typeof AutocompleteInput>) { |
| 100 | wrapperClassName?: string | undefined; | ||
| 101 | }) { | ||
| 102 | return ( | 99 | return ( |
| 103 | <div | 100 | <div className="px-[var(--command-shell-inset)] py-1.5 [&_[data-slot=autocomplete-start-addon]]:ps-[calc(var(--command-shell-inset)+0.0625rem)]"> |
| 104 | className={cn( | ||
| 105 | "px-[var(--command-shell-inset)] py-1.5 [&_[data-slot=autocomplete-start-addon]]:ps-[calc(var(--command-shell-inset)+0.0625rem)]", | ||
| 106 | wrapperClassName, | ||
| 107 | )} | ||
| 108 | > | ||
| 109 | <AutocompleteInput | 101 | <AutocompleteInput |
| 110 | autoFocus | 102 | autoFocus |
| 111 | className={cn( | 103 | className={cn( |
apps/web/src/components/ui/dialog.tsx+4-6| ... | @@ -61,24 +61,22 @@ function DialogPopup({ | ... | @@ -61,24 +61,22 @@ function DialogPopup({ |
| 61 | children, | 61 | children, |
| 62 | showCloseButton = true, | 62 | showCloseButton = true, |
| 63 | bottomStickOnMobile = true, | 63 | bottomStickOnMobile = true, |
| 64 | backdropClassName, | ||
| 65 | viewportClassName, | ||
| 66 | variant = "default", | 64 | variant = "default", |
| 67 | ...props | 65 | ...props |
| 68 | }: DialogPrimitive.Popup.Props & { | 66 | }: DialogPrimitive.Popup.Props & { |
| 69 | showCloseButton?: boolean; | 67 | showCloseButton?: boolean; |
| 70 | bottomStickOnMobile?: boolean; | 68 | bottomStickOnMobile?: boolean; |
| 71 | backdropClassName?: string; | ||
| 72 | viewportClassName?: string; | ||
| 73 | variant?: "default" | "media"; | 69 | variant?: "default" | "media"; |
| 74 | }) { | 70 | }) { |
| 75 | return ( | 71 | return ( |
| 76 | <DialogPortal> | 72 | <DialogPortal> |
| 77 | <DialogBackdrop className={backdropClassName} variant={variant} /> | 73 | {/* Media opens from inside other overlays (a composer chip, a popover), so it sits above them. */} |
| 74 | <DialogBackdrop className={variant === "media" ? "z-[60]" : undefined} variant={variant} /> | ||
| 78 | <DialogViewport | 75 | <DialogViewport |
| 79 | className={cn( | 76 | className={cn( |
| 80 | bottomStickOnMobile && "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12", | 77 | bottomStickOnMobile && "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12", |
| 81 | viewportClassName, | 78 | variant === "media" && |
| 79 | "z-[60] grid-rows-1 place-items-center px-4 py-6 [-webkit-app-region:no-drag]", | ||
| 82 | )} | 80 | )} |
| 83 | > | 81 | > |
| 84 | <DialogPrimitive.Popup | 82 | <DialogPrimitive.Popup |
apps/web/src/components/ui/popover.tsx+15-6| ... | @@ -25,10 +25,19 @@ const popoverPopupWidthClassName = { | ... | @@ -25,10 +25,19 @@ const popoverPopupWidthClassName = { |
| 25 | lg: "w-96", | 25 | lg: "w-96", |
| 26 | } as const; | 26 | } as const; |
| 27 | 27 | ||
| 28 | // The inset around the content. "compact" suits dense content (a list, a code excerpt, a | ||
| 29 | // row of reactions); "none" is for content that draws its own frame edge to edge. | ||
| 30 | const popoverViewportPaddingClassName = { | ||
| 31 | default: "py-4 [--viewport-inline-padding:--spacing(4)]", | ||
| 32 | compact: "py-2 [--viewport-inline-padding:--spacing(3)]", | ||
| 33 | // Rounded to the popup so edge-to-edge content clips to its corners. | ||
| 34 | none: "rounded-[calc(var(--radius-lg)-1px)] py-0 [--viewport-inline-padding:0px]", | ||
| 35 | } as const; | ||
| 36 | |||
| 28 | function PopoverPopup({ | 37 | function PopoverPopup({ |
| 29 | children, | 38 | children, |
| 30 | className, | 39 | className, |
| 31 | viewportClassName, | 40 | padding = "default", |
| 32 | width = "auto", | 41 | width = "auto", |
| 33 | side = "bottom", | 42 | side = "bottom", |
| 34 | align = "center", | 43 | align = "center", |
| ... | @@ -39,7 +48,7 @@ function PopoverPopup({ | ... | @@ -39,7 +48,7 @@ function PopoverPopup({ |
| 39 | anchor, | 48 | anchor, |
| 40 | ...props | 49 | ...props |
| 41 | }: PopoverPrimitive.Popup.Props & { | 50 | }: PopoverPrimitive.Popup.Props & { |
| 42 | viewportClassName?: string; | 51 | padding?: keyof typeof popoverViewportPaddingClassName; |
| 43 | side?: PopoverPrimitive.Positioner.Props["side"]; | 52 | side?: PopoverPrimitive.Positioner.Props["side"]; |
| 44 | align?: PopoverPrimitive.Positioner.Props["align"]; | 53 | align?: PopoverPrimitive.Positioner.Props["align"]; |
| 45 | sideOffset?: PopoverPrimitive.Positioner.Props["sideOffset"]; | 54 | sideOffset?: PopoverPrimitive.Positioner.Props["sideOffset"]; |
| ... | @@ -78,11 +87,11 @@ function PopoverPopup({ | ... | @@ -78,11 +87,11 @@ function PopoverPopup({ |
| 78 | > | 87 | > |
| 79 | <Viewport | 88 | <Viewport |
| 80 | className={cn( | 89 | className={cn( |
| 81 | "relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) py-4 [--viewport-inline-padding:--spacing(4)] has-data-[slot=calendar]:p-2 data-instant:transition-none **:data-current:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-ending-style:opacity-0 **:data-previous:data-starting-style:opacity-0 **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-previous:opacity-100 **:data-current:transition-opacity **:data-previous:transition-opacity", | 90 | "relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) has-data-[slot=calendar]:p-2 data-instant:transition-none **:data-current:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-ending-style:opacity-0 **:data-previous:data-starting-style:opacity-0 **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-previous:opacity-100 **:data-current:transition-opacity **:data-previous:transition-opacity", |
| 82 | tooltipStyle | 91 | tooltipStyle && padding === "default" |
| 83 | ? "py-1 [--viewport-inline-padding:--spacing(2)]" | 92 | ? "py-1 [--viewport-inline-padding:--spacing(2)]" |
| 84 | : "not-data-transitioning:overflow-y-auto", | 93 | : popoverViewportPaddingClassName[padding], |
| 85 | viewportClassName, | 94 | !tooltipStyle && "not-data-transitioning:overflow-y-auto", |
| 86 | )} | 95 | )} |
| 87 | data-slot="popover-viewport" | 96 | data-slot="popover-viewport" |
| 88 | > | 97 | > |
apps/web/src/components/ui/select.tsx-3| ... | @@ -102,7 +102,6 @@ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) { | ... | @@ -102,7 +102,6 @@ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) { |
| 102 | 102 | ||
| 103 | function SelectPopup({ | 103 | function SelectPopup({ |
| 104 | className, | 104 | className, |
| 105 | popupClassName, | ||
| 106 | children, | 105 | children, |
| 107 | side = "bottom", | 106 | side = "bottom", |
| 108 | sideOffset = 4, | 107 | sideOffset = 4, |
| ... | @@ -113,7 +112,6 @@ function SelectPopup({ | ... | @@ -113,7 +112,6 @@ function SelectPopup({ |
| 113 | anchor, | 112 | anchor, |
| 114 | ...props | 113 | ...props |
| 115 | }: SelectPrimitive.Popup.Props & { | 114 | }: SelectPrimitive.Popup.Props & { |
| 116 | popupClassName?: string; | ||
| 117 | side?: SelectPrimitive.Positioner.Props["side"]; | 115 | side?: SelectPrimitive.Positioner.Props["side"]; |
| 118 | sideOffset?: SelectPrimitive.Positioner.Props["sideOffset"]; | 116 | sideOffset?: SelectPrimitive.Positioner.Props["sideOffset"]; |
| 119 | align?: SelectPrimitive.Positioner.Props["align"]; | 117 | align?: SelectPrimitive.Positioner.Props["align"]; |
| ... | @@ -149,7 +147,6 @@ function SelectPopup({ | ... | @@ -149,7 +147,6 @@ function SelectPopup({ |
| 149 | className={cn( | 147 | className={cn( |
| 150 | "dropdown-glass relative h-full rounded-lg shadow-[0_16px_40px_-18px_rgb(0_0_0/55%)] dark:shadow-[0_18px_44px_-18px_rgb(0_0_0/80%)]", | 148 | "dropdown-glass relative h-full rounded-lg shadow-[0_16px_40px_-18px_rgb(0_0_0/55%)] dark:shadow-[0_18px_44px_-18px_rgb(0_0_0/80%)]", |
| 151 | matchTriggerWidth && "min-w-(--anchor-width)", | 149 | matchTriggerWidth && "min-w-(--anchor-width)", |
| 152 | popupClassName, | ||
| 153 | )} | 150 | )} |
| 154 | > | 151 | > |
| 155 | <SelectPrimitive.List | 152 | <SelectPrimitive.List |
apps/web/src/components/ui/sheet.tsx+10-12| ... | @@ -10,11 +10,13 @@ const Sheet = SheetPrimitive.Root; | ... | @@ -10,11 +10,13 @@ const Sheet = SheetPrimitive.Root; |
| 10 | 10 | ||
| 11 | const SheetPortal = SheetPrimitive.Portal; | 11 | const SheetPortal = SheetPrimitive.Portal; |
| 12 | 12 | ||
| 13 | // Sheets are docked panels, not dialogs: their layer (--z-sheet) sits under dialogs that open | ||
| 14 | // from inside them and under anything the app floats above panels. | ||
| 13 | function SheetBackdrop({ className, ...props }: SheetPrimitive.Backdrop.Props) { | 15 | function SheetBackdrop({ className, ...props }: SheetPrimitive.Backdrop.Props) { |
| 14 | return ( | 16 | return ( |
| 15 | <SheetPrimitive.Backdrop | 17 | <SheetPrimitive.Backdrop |
| 16 | className={cn( | 18 | className={cn( |
| 17 | "fixed inset-0 z-50 bg-background/60 backdrop-blur-xs transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0", | 19 | "fixed inset-0 z-(--z-sheet) bg-background/60 backdrop-blur-xs transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0", |
| 18 | className, | 20 | className, |
| 19 | )} | 21 | )} |
| 20 | data-slot="sheet-backdrop" | 22 | data-slot="sheet-backdrop" |
| ... | @@ -35,7 +37,7 @@ function SheetViewport({ | ... | @@ -35,7 +37,7 @@ function SheetViewport({ |
| 35 | return ( | 37 | return ( |
| 36 | <SheetPrimitive.Viewport | 38 | <SheetPrimitive.Viewport |
| 37 | className={cn( | 39 | className={cn( |
| 38 | "fixed inset-0 z-50 grid", | 40 | "fixed inset-0 z-(--z-sheet) grid", |
| 39 | side === "bottom" && "grid grid-rows-[1fr_auto] pt-12", | 41 | side === "bottom" && "grid grid-rows-[1fr_auto] pt-12", |
| 40 | side === "top" && "grid grid-rows-[auto_1fr] pb-12", | 42 | side === "top" && "grid grid-rows-[auto_1fr] pb-12", |
| 41 | side === "left" && "flex justify-start", | 43 | side === "left" && "flex justify-start", |
| ... | @@ -55,8 +57,6 @@ function SheetPopup({ | ... | @@ -55,8 +57,6 @@ function SheetPopup({ |
| 55 | showCloseButton = true, | 57 | showCloseButton = true, |
| 56 | keepMounted = false, | 58 | keepMounted = false, |
| 57 | transitionDurationMs, | 59 | transitionDurationMs, |
| 58 | backdropClassName, | ||
| 59 | viewportClassName, | ||
| 60 | side = "right", | 60 | side = "right", |
| 61 | variant = "default", | 61 | variant = "default", |
| 62 | style, | 62 | style, |
| ... | @@ -65,8 +65,6 @@ function SheetPopup({ | ... | @@ -65,8 +65,6 @@ function SheetPopup({ |
| 65 | showCloseButton?: boolean; | 65 | showCloseButton?: boolean; |
| 66 | keepMounted?: boolean; | 66 | keepMounted?: boolean; |
| 67 | transitionDurationMs?: number; | 67 | transitionDurationMs?: number; |
| 68 | backdropClassName?: string; | ||
| 69 | viewportClassName?: string; | ||
| 70 | side?: "right" | "left" | "top" | "bottom"; | 68 | side?: "right" | "left" | "top" | "bottom"; |
| 71 | variant?: "default" | "inset"; | 69 | variant?: "default" | "inset"; |
| 72 | }) { | 70 | }) { |
| ... | @@ -79,14 +77,14 @@ function SheetPopup({ | ... | @@ -79,14 +77,14 @@ function SheetPopup({ |
| 79 | return ( | 77 | return ( |
| 80 | <SheetPortal keepMounted={keepMounted}> | 78 | <SheetPortal keepMounted={keepMounted}> |
| 81 | <SheetBackdrop | 79 | <SheetBackdrop |
| 82 | className={cn( | 80 | className={ |
| 83 | instant && | 81 | instant |
| 84 | "transition-none! data-ending-style:opacity-100! data-starting-style:opacity-100!", | 82 | ? "transition-none! data-ending-style:opacity-100! data-starting-style:opacity-100!" |
| 85 | backdropClassName, | 83 | : undefined |
| 86 | )} | 84 | } |
| 87 | style={transitionStyle} | 85 | style={transitionStyle} |
| 88 | /> | 86 | /> |
| 89 | <SheetViewport className={viewportClassName} side={side} variant={variant}> | 87 | <SheetViewport side={side} variant={variant}> |
| 90 | <SheetPrimitive.Popup | 88 | <SheetPrimitive.Popup |
| 91 | className={cn( | 89 | className={cn( |
| 92 | "relative flex max-h-full min-h-0 w-full min-w-0 flex-col bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:before:hidden dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", | 90 | "relative flex max-h-full min-h-0 w-full min-w-0 flex-col bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:before:hidden dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", |
apps/web/src/index.css+3| ... | @@ -101,6 +101,9 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil | ... | @@ -101,6 +101,9 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil |
| 101 | --command-shell-inset: 0.5rem; | 101 | --command-shell-inset: 0.5rem; |
| 102 | --command-content-inset: 1rem; | 102 | --command-content-inset: 1rem; |
| 103 | --floating-content-inset: 0.75rem; | 103 | --floating-content-inset: 0.75rem; |
| 104 | /* App layer order: docked sheets, then the floating preview player (47–49, see | ||
| 105 | previewMiniPlayerLayout.ts), then dialogs and popovers (50 and up). */ | ||
| 106 | --z-sheet: 46; | ||
| 104 | --glass-blur: 12px; | 107 | --glass-blur: 12px; |
| 105 | --glass-opacity: 80%; | 108 | --glass-opacity: 80%; |
| 106 | --glass-saturation: 1.14; | 109 | --glass-saturation: 1.14; |
apps/web/src/rightPanelLayout.ts-2| ... | @@ -1,5 +1,3 @@ | ... | @@ -1,5 +1,3 @@ |
| 1 | export const RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 980px)"; | 1 | export const RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 980px)"; |
| 2 | // Applied only while a floating preview overlaps the compact sheet. | ||
| 3 | export const RIGHT_PANEL_SHEET_LAYER_CLASS_NAME = "z-[35]"; | ||
| 4 | export const RIGHT_PANEL_SHEET_CLASS_NAME = | 2 | export const RIGHT_PANEL_SHEET_CLASS_NAME = |
| 5 | "w-[min(42vw,28rem)] min-w-80 max-w-[28rem] p-0 max-[760px]:w-[min(88vw,24rem)] max-[760px]:min-w-0 wco:mt-[env(titlebar-area-height)] wco:h-[calc(100%-env(titlebar-area-height))] wco:max-h-[calc(100%-env(titlebar-area-height))]"; | 3 | "w-[min(42vw,28rem)] min-w-80 max-w-[28rem] p-0 max-[760px]:w-[min(88vw,24rem)] max-[760px]:min-w-0 wco:mt-[env(titlebar-area-height)] wco:h-[calc(100%-env(titlebar-area-height))] wco:max-h-[calc(100%-env(titlebar-area-height))]"; |
scripts/lint-restyle-ceiling.ts+1-1| ... | @@ -8,7 +8,7 @@ import * as NodeURL from "node:url"; | ... | @@ -8,7 +8,7 @@ import * as NodeURL from "node:url"; |
| 8 | // components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the | 8 | // components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the |
| 9 | // count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you | 9 | // count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you |
| 10 | // migrate a file, and delete this script when the rule becomes an error. | 10 | // migrate a file, and delete this script when the rule becomes an error. |
| 11 | export const RESTYLE_CEILING = 603; | 11 | export const RESTYLE_CEILING = 582; |
| 12 | 12 | ||
| 13 | const RULE = "shadcn(no-restyle)"; | 13 | const RULE = "shadcn(no-restyle)"; |
| 14 | 14 |