diff --git a/client/src/pages/admin/FoldSummary.test.tsx b/client/src/pages/admin/FoldSummary.test.tsx new file mode 100644 index 000000000..319f9be12 --- /dev/null +++ b/client/src/pages/admin/FoldSummary.test.tsx @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { fireEvent, render, screen } from '../../../tests/helpers/render'; +import FoldSummary from './FoldSummary'; + +describe('FoldSummary', () => { + it('heads the fold with a turning chevron and its own label', () => { + const { container } = render( +
+ + More + +

inside

+
+ ); + const summary = container.querySelector('summary') as HTMLElement; + expect(summary).toContainElement(screen.getByText('More')); + const chevron = summary.querySelector('svg') as SVGElement; + expect(chevron).toHaveAttribute('aria-hidden', 'true'); + expect(chevron.getAttribute('class')).toContain('group-open:rotate-90'); + expect(summary.firstElementChild).toBe(chevron); + }); + + it('opens and closes the fold it heads', () => { + const { container } = render( +
+ More +

inside

+
+ ); + const details = container.querySelector('details') as HTMLDetailsElement; + expect(details.open).toBe(false); + fireEvent.click(container.querySelector('summary') as HTMLElement); + expect(details.open).toBe(true); + }); +}); diff --git a/client/src/pages/admin/FoldSummary.tsx b/client/src/pages/admin/FoldSummary.tsx new file mode 100644 index 000000000..6a8c10f76 --- /dev/null +++ b/client/src/pages/admin/FoldSummary.tsx @@ -0,0 +1,21 @@ +import { ChevronRight } from 'lucide-react'; +import React from 'react'; + +/** + * The clickable head of a native
fold on the admin settings page: a + * chevron that turns when the fold opens, then whatever the fold calls itself. + * The surrounding
needs the `group` class for the chevron to turn. + */ +export default function FoldSummary({ children }: { children: React.ReactNode }): React.ReactElement { + return ( + + + ); +} diff --git a/client/src/pages/admin/GoogleOptions.tsx b/client/src/pages/admin/GoogleOptions.tsx index 9fd1b039b..359227d46 100644 --- a/client/src/pages/admin/GoogleOptions.tsx +++ b/client/src/pages/admin/GoogleOptions.tsx @@ -1,7 +1,7 @@ import React from 'react' -import { ChevronRight } from 'lucide-react' import { fs } from '../../components/shared/DialogShell' import { StatusPill } from '../../components/Settings/settingsKit' +import FoldSummary from './FoldSummary' interface GoogleOptionsProps { /** "Google options" — the heading of the fold. */ @@ -27,20 +27,10 @@ interface GoogleOptionsProps { export default function GoogleOptions({ title, summary, children }: GoogleOptionsProps): React.ReactElement { return (
- - +
{children}
) diff --git a/client/src/pages/admin/TrekApiCard.tsx b/client/src/pages/admin/TrekApiCard.tsx index 35669e4f2..5722e2bac 100644 --- a/client/src/pages/admin/TrekApiCard.tsx +++ b/client/src/pages/admin/TrekApiCard.tsx @@ -1,8 +1,9 @@ import React from 'react' -import { Check, ChevronRight, Library, X } from 'lucide-react' +import { Check, Library, X } from 'lucide-react' import TrekMark from '../../components/shared/TrekMark' import { fs } from '../../components/shared/DialogShell' import { StatusPill } from '../../components/Settings/settingsKit' +import FoldSummary from './FoldSummary' import type { TranslationFn } from '../../types' import { TREK_API_SOURCES as SOURCES, trekApiFacts, trekApiFields } from '../../components/Admin/trekApiModel' @@ -72,20 +73,9 @@ export default function TrekApiCard({ t }: TrekApiCardProps): React.ReactElement
- - +
{/* The fields as chips rather than a paragraph. A list of what you get is something you scan, not something you read, and a sentence