From bffbe1b861d2ee6e87602eb1659499af4ec5c301 Mon Sep 17 00:00:00 2001 From: hanger Date: Thu, 4 Jun 2026 17:53:40 +0800 Subject: [PATCH] fix(web): add close button to dialog so modals are dismissable on mobile (#792) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(web): add close button to dialog so modals are dismissable on mobile The shared DialogContent had no close affordance — desktop users could press Escape or click the overlay, but on mobile (no Escape key, dialog spans calc(100vw-24px) leaving almost no tappable overlay) there was no way to dismiss it. Add a DialogPrimitive.Close X button in the top-right, fixing every dialog that uses this component at once. * fix(web): reserve header space for dialog close button Address review feedback: the absolutely-positioned close button overlaps the top-right of every dialog. Long/breaking titles (e.g. DiffView's break-all filename) could wrap underneath the 32px tap target. Add pr-12 to DialogHeader rather than padding DialogContent globally, so the title row clears the button while body content (code blocks, diffs) keeps full width. * fix(web): localize dialog close button aria-label Use the existing button.close locale string instead of a hardcoded "Close" so screen-reader users get the label in their language (zh-CN: 关闭). --- web/src/components/ui/dialog.tsx | 43 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/web/src/components/ui/dialog.tsx b/web/src/components/ui/dialog.tsx index fca364d3..f74cc10f 100644 --- a/web/src/components/ui/dialog.tsx +++ b/web/src/components/ui/dialog.tsx @@ -1,6 +1,8 @@ import * as React from 'react' import * as DialogPrimitive from '@radix-ui/react-dialog' import { cn } from '@/lib/utils' +import { CloseIcon } from '@/components/icons' +import { useTranslation } from '@/lib/use-translation' export const Dialog = DialogPrimitive.Root export const DialogTrigger = DialogPrimitive.Trigger @@ -8,23 +10,36 @@ export const DialogTrigger = DialogPrimitive.Trigger export const DialogContent = React.forwardRef< HTMLDivElement, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - -)) +>(({ className, children, ...props }, ref) => { + const { t } = useTranslation() + return ( + + + + {children} + + + + + + ) +}) DialogContent.displayName = 'DialogContent' export const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( -
+ // pr-12 reserves space for the absolutely-positioned close button (top-right) + // so long/breaking titles don't wrap underneath the tap target. +
) export const DialogTitle = React.forwardRef<