fix(web): align compact dialog titles (#1253)

This commit is contained in:
Ananovo
2026-07-31 18:17:57 +01:00
committed by GitHub
parent f985d56ba5
commit 39da5c4b8e
9 changed files with 142 additions and 9 deletions
+1
View File
@@ -1431,6 +1431,7 @@ export function NewSession(props: {
confirmingLabel={t('codexSync.duplicates.confirm.confirming')}
onConfirm={handleMergeDuplicateSessions}
isPending={isMergingDuplicateSessions}
centerTitle
/>
</div>
)
+4 -2
View File
@@ -59,8 +59,10 @@ export function RenameSessionDialog(props: RenameSessionDialogProps) {
return (
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
<DialogContent className="max-w-sm">
<DialogHeader>
<DialogTitle>{t('dialog.rename.title')}</DialogTitle>
<DialogHeader className="pr-0">
<DialogTitle className="min-h-6 px-10 text-center leading-6">
{t('dialog.rename.title')}
</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="mt-4 flex flex-col gap-4">
<input
@@ -0,0 +1,68 @@
import { render, screen, within } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { I18nProvider } from '@/lib/i18n-context'
import { ToastProvider } from '@/lib/toast-context'
import { RenameSessionDialog } from './RenameSessionDialog'
import { SessionExportDialog } from './SessionExportDialog'
import { UriConfirmDialog } from './UriConfirmDialog'
function renderWithProviders(content: React.ReactNode) {
return render(
<I18nProvider>
<ToastProvider>{content}</ToastProvider>
</I18nProvider>
)
}
function expectCenteredTitle(name: string) {
const dialog = screen.getByRole('dialog')
const title = within(dialog).getByRole('heading', { name })
expect(title.parentElement).toHaveClass('pr-0')
expect(title).toHaveClass('min-h-6', 'px-10', 'text-center', 'leading-6')
expect(within(dialog).getByRole('button', { name: 'Close' })).toHaveClass('top-3', 'h-8')
}
describe('session dialog title alignment', () => {
it('centers the rename dialog title on the close button centerline', () => {
renderWithProviders(
<RenameSessionDialog
isOpen={true}
onClose={vi.fn()}
currentName="Session"
onRename={vi.fn(async () => {})}
isPending={false}
/>
)
expectCenteredTitle('Rename Session')
})
it('centers the export dialog title on the close button centerline', () => {
renderWithProviders(
<SessionExportDialog
isOpen={true}
onClose={vi.fn()}
sessionId="session-1"
api={null}
/>
)
expectCenteredTitle('Export conversation')
})
it('centers the external-link dialog title on the close button centerline', () => {
renderWithProviders(
<UriConfirmDialog
open={true}
url="obsidian://open"
scheme="obsidian"
onCancel={vi.fn()}
onOpen={vi.fn()}
onAlwaysAllow={vi.fn()}
/>
)
expectCenteredTitle('Open this link?')
})
})
+4 -2
View File
@@ -101,8 +101,10 @@ export function SessionExportDialog(props: SessionExportDialogProps) {
return (
<Dialog open={props.isOpen} onOpenChange={(open) => !open && handleClose()}>
<DialogContent className="max-w-sm">
<DialogHeader>
<DialogTitle>{t('session.export.title')}</DialogTitle>
<DialogHeader className="pr-0">
<DialogTitle className="min-h-6 px-10 text-center leading-6">
{t('session.export.title')}
</DialogTitle>
<DialogDescription className="mt-2">
{t('session.export.description')}
</DialogDescription>
+3
View File
@@ -391,6 +391,7 @@ export function SessionHeader(props: {
confirmingLabel={t('dialog.reopen.dismiss')}
onConfirm={async () => setReopenError(null)}
isPending={false}
centerTitle
/>
) : null}
@@ -419,6 +420,7 @@ export function SessionHeader(props: {
onConfirm={archiveSession}
isPending={isPending}
destructive
centerTitle
/>
<ConfirmDialog
@@ -440,6 +442,7 @@ export function SessionHeader(props: {
onConfirm={handleDelete}
isPending={isPending}
destructive
centerTitle
/>
</>
)
+3
View File
@@ -886,6 +886,7 @@ function SessionItem(props: {
confirmingLabel={t('dialog.reopen.dismiss')}
onConfirm={async () => setReopenError(null)}
isPending={false}
centerTitle
/>
) : null}
@@ -919,6 +920,7 @@ function SessionItem(props: {
onConfirm={archiveSession}
isPending={isPending}
destructive
centerTitle
/>
) : null}
@@ -933,6 +935,7 @@ function SessionItem(props: {
onConfirm={deleteSession}
isPending={isPending}
destructive
centerTitle
/>
) : null}
</>
+4 -2
View File
@@ -38,8 +38,10 @@ export function UriConfirmDialog(props: UriConfirmDialogProps) {
return (
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onCancel()}>
<DialogContent className="max-w-md">
<DialogHeader>
<DialogTitle>{t('dialog.uri.title')}</DialogTitle>
<DialogHeader className="pr-0">
<DialogTitle className="min-h-6 px-10 text-center leading-6">
{t('dialog.uri.title')}
</DialogTitle>
</DialogHeader>
<DialogDescription className="mt-2">
{t('dialog.uri.description')}
@@ -0,0 +1,44 @@
import { render, screen, within } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { I18nProvider } from '@/lib/i18n-context'
import { ConfirmDialog } from './ConfirmDialog'
function renderDialog(centerTitle = false) {
render(
<I18nProvider>
<ConfirmDialog
isOpen={true}
onClose={vi.fn()}
title="Archive Session"
description="Archive this session?"
confirmLabel="Archive"
confirmingLabel="Archiving..."
onConfirm={vi.fn(async () => {})}
isPending={false}
centerTitle={centerTitle}
/>
</I18nProvider>
)
}
describe('ConfirmDialog', () => {
it('centers an opted-in title on the close button centerline', () => {
renderDialog(true)
const dialog = screen.getByRole('dialog')
const title = within(dialog).getByRole('heading', { name: 'Archive Session' })
expect(title.parentElement).toHaveClass('pr-0')
expect(title).toHaveClass('min-h-6', 'px-10', 'text-center', 'leading-6')
expect(within(dialog).getByRole('button', { name: 'Close' })).toHaveClass('top-3', 'h-8')
})
it('keeps the default dialog title layout when centering is not requested', () => {
renderDialog()
const title = screen.getByRole('heading', { name: 'Archive Session' })
expect(title.parentElement).toHaveClass('pr-12')
expect(title).not.toHaveClass('min-h-6', 'px-10', 'leading-6')
})
})
+11 -3
View File
@@ -19,6 +19,7 @@ type ConfirmDialogProps = {
onConfirm: () => Promise<void>
isPending: boolean
destructive?: boolean
centerTitle?: boolean
}
export function ConfirmDialog(props: ConfirmDialogProps) {
@@ -32,7 +33,8 @@ export function ConfirmDialog(props: ConfirmDialogProps) {
confirmingLabel,
onConfirm,
isPending,
destructive = false
destructive = false,
centerTitle = false
} = props
const [error, setError] = useState<string | null>(null)
@@ -61,8 +63,14 @@ export function ConfirmDialog(props: ConfirmDialogProps) {
return (
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
<DialogContent className="max-w-sm">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogHeader className={centerTitle ? 'pr-0' : undefined}>
<DialogTitle
className={centerTitle
? 'min-h-6 px-10 text-center leading-6'
: undefined}
>
{title}
</DialogTitle>
<DialogDescription className="mt-2 whitespace-pre-line">
{description}
</DialogDescription>