diff --git a/web/src/components/NewSession/index.tsx b/web/src/components/NewSession/index.tsx index 7287e77b..fb81c7f1 100644 --- a/web/src/components/NewSession/index.tsx +++ b/web/src/components/NewSession/index.tsx @@ -1431,6 +1431,7 @@ export function NewSession(props: { confirmingLabel={t('codexSync.duplicates.confirm.confirming')} onConfirm={handleMergeDuplicateSessions} isPending={isMergingDuplicateSessions} + centerTitle /> ) diff --git a/web/src/components/RenameSessionDialog.tsx b/web/src/components/RenameSessionDialog.tsx index 38178243..a9203178 100644 --- a/web/src/components/RenameSessionDialog.tsx +++ b/web/src/components/RenameSessionDialog.tsx @@ -59,8 +59,10 @@ export function RenameSessionDialog(props: RenameSessionDialogProps) { return ( !open && onClose()}> - - {t('dialog.rename.title')} + + + {t('dialog.rename.title')} +
+ {content} + + ) +} + +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( + {})} + isPending={false} + /> + ) + + expectCenteredTitle('Rename Session') + }) + + it('centers the export dialog title on the close button centerline', () => { + renderWithProviders( + + ) + + expectCenteredTitle('Export conversation') + }) + + it('centers the external-link dialog title on the close button centerline', () => { + renderWithProviders( + + ) + + expectCenteredTitle('Open this link?') + }) +}) diff --git a/web/src/components/SessionExportDialog.tsx b/web/src/components/SessionExportDialog.tsx index b81509ac..ab04a6d0 100644 --- a/web/src/components/SessionExportDialog.tsx +++ b/web/src/components/SessionExportDialog.tsx @@ -101,8 +101,10 @@ export function SessionExportDialog(props: SessionExportDialogProps) { return ( !open && handleClose()}> - - {t('session.export.title')} + + + {t('session.export.title')} + {t('session.export.description')} diff --git a/web/src/components/SessionHeader.tsx b/web/src/components/SessionHeader.tsx index 7f5adb10..c1276291 100644 --- a/web/src/components/SessionHeader.tsx +++ b/web/src/components/SessionHeader.tsx @@ -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 /> ) diff --git a/web/src/components/SessionList.tsx b/web/src/components/SessionList.tsx index 28645f7e..7531895b 100644 --- a/web/src/components/SessionList.tsx +++ b/web/src/components/SessionList.tsx @@ -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} diff --git a/web/src/components/UriConfirmDialog.tsx b/web/src/components/UriConfirmDialog.tsx index 1457d16b..ca0430d3 100644 --- a/web/src/components/UriConfirmDialog.tsx +++ b/web/src/components/UriConfirmDialog.tsx @@ -38,8 +38,10 @@ export function UriConfirmDialog(props: UriConfirmDialogProps) { return ( !isOpen && onCancel()}> - - {t('dialog.uri.title')} + + + {t('dialog.uri.title')} + {t('dialog.uri.description')} diff --git a/web/src/components/ui/ConfirmDialog.test.tsx b/web/src/components/ui/ConfirmDialog.test.tsx new file mode 100644 index 00000000..d80f2283 --- /dev/null +++ b/web/src/components/ui/ConfirmDialog.test.tsx @@ -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( + + {})} + isPending={false} + centerTitle={centerTitle} + /> + + ) +} + +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') + }) +}) diff --git a/web/src/components/ui/ConfirmDialog.tsx b/web/src/components/ui/ConfirmDialog.tsx index e998d1a3..8d2e0674 100644 --- a/web/src/components/ui/ConfirmDialog.tsx +++ b/web/src/components/ui/ConfirmDialog.tsx @@ -19,6 +19,7 @@ type ConfirmDialogProps = { onConfirm: () => Promise 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(null) @@ -61,8 +63,14 @@ export function ConfirmDialog(props: ConfirmDialogProps) { return ( !open && onClose()}> - - {title} + + + {title} + {description}