refactor(desktop): export DialogCloseButton for the boot-failure overlay
The overlay carried a byte-for-byte copy of DialogContent's close button.
This commit is contained in:
committed by
brooklyn!
parent
1b8569f41f
commit
6007b3ce4f
@@ -3,6 +3,7 @@ import { Dialog as DialogPrimitive } from 'radix-ui'
|
||||
import { type ComponentProps, lazy, type ReactNode, Suspense, useEffect, useState } from 'react'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { DialogCloseButton } from '@/components/ui/dialog'
|
||||
import { DialogPortalContainerContext } from '@/components/ui/dialog-portal-context'
|
||||
import { ErrorIcon } from '@/components/ui/error-state'
|
||||
import { Loader } from '@/components/ui/loader'
|
||||
@@ -12,17 +13,7 @@ import { useI18n } from '@/i18n'
|
||||
import { reestablishCloudAgentSession } from '@/lib/cloud-agent-session'
|
||||
import { DESKTOP_DOCS_URL } from '@/lib/docs'
|
||||
import { openExternalLink } from '@/lib/external-link'
|
||||
import {
|
||||
ChevronLeft,
|
||||
ExternalLink,
|
||||
FileText,
|
||||
Loader2,
|
||||
LogIn,
|
||||
RefreshCw,
|
||||
SlidersHorizontal,
|
||||
Wrench,
|
||||
X
|
||||
} from '@/lib/icons'
|
||||
import { ChevronLeft, ExternalLink, FileText, Loader2, LogIn, RefreshCw, SlidersHorizontal, Wrench } from '@/lib/icons'
|
||||
import { $desktopBoot } from '@/store/boot'
|
||||
import { notify, notifyError } from '@/store/notifications'
|
||||
import { $desktopOnboarding } from '@/store/onboarding'
|
||||
@@ -54,25 +45,6 @@ type RecoveryView = 'connect' | 'recovery'
|
||||
// re-establish the remote session. The detection + copy helpers live in
|
||||
// ./boot-failure-reauth so they're unit-testable without a React render.
|
||||
|
||||
// Radix Close routes through the modal's onOpenChange, same path as Escape.
|
||||
function DismissControl() {
|
||||
const { t } = useI18n()
|
||||
|
||||
return (
|
||||
<DialogPrimitive.Close asChild data-slot="dialog-close-button">
|
||||
<Button
|
||||
aria-label={t.common.close}
|
||||
className="absolute right-2.5 top-2.5 z-20 text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground"
|
||||
size="icon-xs"
|
||||
variant="ghost"
|
||||
>
|
||||
<X className="size-4" />
|
||||
<span className="sr-only">{t.common.close}</span>
|
||||
</Button>
|
||||
</DialogPrimitive.Close>
|
||||
)
|
||||
}
|
||||
|
||||
// Recovery surface for a hard boot failure (gateway never came up, backend
|
||||
// exited during startup, bootstrap latched, …). Without this the app shell
|
||||
// renders dead — "gateway offline", no composer, only a toast — with no way
|
||||
@@ -504,7 +476,7 @@ export function BootFailureOverlay() {
|
||||
return (
|
||||
<BootFailureModal onDismiss={dismiss} title={copy.gatewaySettings}>
|
||||
<div className="relative flex max-h-[86vh] w-full max-w-[46rem] flex-col overflow-hidden rounded-xl border border-(--stroke-nous) bg-(--ui-chat-bubble-background) shadow-nous">
|
||||
<DismissControl />
|
||||
<DialogCloseButton />
|
||||
{/* Subtle back affordance (projects/overlay idiom): muted → foreground
|
||||
on hover, no divider. */}
|
||||
<button
|
||||
@@ -528,7 +500,7 @@ export function BootFailureOverlay() {
|
||||
return (
|
||||
<BootFailureModal onDismiss={dismiss}>
|
||||
<div className="relative w-full max-w-[40rem] overflow-hidden rounded-xl border border-(--stroke-nous) bg-(--ui-chat-bubble-background) shadow-nous">
|
||||
<DismissControl />
|
||||
<DialogCloseButton />
|
||||
<div className="flex items-start gap-3 px-5 py-4 pr-12">
|
||||
<ErrorIcon className="mt-0.5" size="1.25rem" />
|
||||
<div>
|
||||
|
||||
@@ -69,6 +69,27 @@ export function preventCloseButtonAutoFocus(event: Event) {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
// The dialog's top-right X. Radix Close routes through the modal's
|
||||
// onOpenChange, same path as Escape. Exported for bespoke Radix shells (the
|
||||
// boot-failure overlay) that can't use DialogContent but want the same X.
|
||||
function DialogCloseButton() {
|
||||
const { t } = useI18n()
|
||||
|
||||
return (
|
||||
<DialogPrimitive.Close asChild data-slot="dialog-close-button">
|
||||
<Button
|
||||
aria-label={t.common.close}
|
||||
className="absolute right-2.5 top-2.5 z-20 text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground"
|
||||
size="icon-xs"
|
||||
variant="ghost"
|
||||
>
|
||||
<X className="size-4" />
|
||||
<span className="sr-only">{t.common.close}</span>
|
||||
</Button>
|
||||
</DialogPrimitive.Close>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogContent({
|
||||
className,
|
||||
bodyClassName,
|
||||
@@ -105,8 +126,6 @@ function DialogContent({
|
||||
banner?: React.ReactNode
|
||||
bannerTone?: DialogBannerTone
|
||||
}) {
|
||||
const { t } = useI18n()
|
||||
|
||||
const widthClass = fitContent ? 'w-auto max-w-[92vw]' : 'w-full max-w-lg'
|
||||
|
||||
// Publish the dialog's content node so popovers (Select / Popover /
|
||||
@@ -133,20 +152,8 @@ function DialogContent({
|
||||
// an input) is what most dialogs want. Dialogs with no input should pass
|
||||
// `onOpenAutoFocus={preventCloseButtonAutoFocus}` explicitly instead.
|
||||
|
||||
// No tip on the X — the glyph is the label. Keep aria-label / sr-only for a11y.
|
||||
const closeButton = showCloseButton ? (
|
||||
<DialogPrimitive.Close asChild data-slot="dialog-close-button">
|
||||
<Button
|
||||
aria-label={t.common.close}
|
||||
className="absolute right-2.5 top-2.5 z-20 text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground"
|
||||
size="icon-xs"
|
||||
variant="ghost"
|
||||
>
|
||||
<X className="size-4" />
|
||||
<span className="sr-only">{t.common.close}</span>
|
||||
</Button>
|
||||
</DialogPrimitive.Close>
|
||||
) : null
|
||||
// No tip on the X — the glyph is the label (DialogCloseButton keeps aria-label / sr-only).
|
||||
const closeButton = showCloseButton ? <DialogCloseButton /> : null
|
||||
|
||||
// With a banner, the border can't live on the scroll/clip box (it would draw a
|
||||
// line around the banner too). The white body keeps its own bottom radius and
|
||||
@@ -314,6 +321,7 @@ function DialogDescription({ className, ...props }: React.ComponentProps<typeof
|
||||
export {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogCloseButton,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
|
||||
Reference in New Issue
Block a user