Refactor UI components to use consistent button and icon styles across the application

This commit is contained in:
Richard R 2026-06-01 11:33:25 -06:00
parent fdceed6067
commit 4f1d8feda5
12 changed files with 233 additions and 87 deletions

View file

@ -176,7 +176,7 @@ export default function EPUBPage() {
href="/app" href="/app"
className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })} className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })}
> >
<svg className="w-4 h-4 text-soft" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg> </svg>
Back to Documents Back to Documents

View file

@ -258,7 +258,7 @@ export default function PDFViewerPage() {
onClick={handleBackToDocuments} onClick={handleBackToDocuments}
className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })} className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })}
> >
<svg className="w-4 h-4 text-soft" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg> </svg>
Back to Documents Back to Documents
@ -346,7 +346,7 @@ export default function PDFViewerPage() {
<button <button
type="button" type="button"
onClick={requestForceReparse} onClick={requestForceReparse}
className="inline-flex items-center rounded-md border border-line bg-surface px-3 py-1.5 text-xs font-medium text-foreground hover:text-accent transition-colors" className={buttonClass({ variant: 'secondary', size: 'sm' })}
> >
Retry Parse Retry Parse
</button> </button>

View file

@ -110,7 +110,7 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps)
size="xs" size="xs"
aria-label="Open system color picker" aria-label="Open system color picker"
> >
<PaletteIcon className="w-4 h-4 text-soft transform transition-transform duration-base ease-standard hover:text-accent" /> <PaletteIcon className="w-4 h-4 transform transition-transform duration-base ease-standard" />
</IconButton> </IconButton>
<input <input
ref={nativeRef} ref={nativeRef}

View file

@ -21,8 +21,8 @@ export function HomeContent() {
const appActions = ( const appActions = (
<div className="flex flex-col gap-0.5 w-full"> <div className="flex flex-col gap-0.5 w-full">
<SettingsTrigger <SettingsTrigger
variant="sidebar"
triggerLabel="Settings" triggerLabel="Settings"
className="w-full justify-start gap-2 px-2 py-1 text-[12px] border-transparent hover:border-accent"
onOpen={() => setSettingsOpen(true)} onOpen={() => setSettingsOpen(true)}
/> />
<UserMenu variant="sidebar" /> <UserMenu variant="sidebar" />

View file

@ -181,12 +181,27 @@ type AdminSubTab = 'providers' | 'features';
export function SettingsTrigger({ export function SettingsTrigger({
className = '', className = '',
triggerLabel, triggerLabel,
variant = 'button',
onOpen, onOpen,
}: { }: {
className?: string; className?: string;
triggerLabel?: string; triggerLabel?: string;
variant?: 'button' | 'sidebar';
onOpen: () => void; onOpen: () => void;
}) { }) {
if (variant === 'sidebar') {
return (
<SidebarNavItem
compact
onClick={onOpen}
className={className}
aria-label="Settings"
icon={<SettingsIcon className="w-3.5 h-3.5" />}
label={triggerLabel ?? 'Settings'}
/>
);
}
return ( return (
<Button <Button
variant="secondary" variant="secondary"
@ -959,16 +974,18 @@ export function SettingsModal({
}} }}
className="flex-1" className="flex-1"
/> />
<button <IconButton
onClick={() => setIsCustomExpanded(!isCustomExpanded)} onClick={() => setIsCustomExpanded(!isCustomExpanded)}
className="shrink-0 p-1.5 rounded-lg border border-line hover:border-accent-line transition-colors" tone="surface"
size="sm"
className="shrink-0"
style={{ color: colors.muted, backgroundColor: colors.base }} style={{ color: colors.muted, backgroundColor: colors.base }}
aria-label={isCustomExpanded ? 'Collapse color picker' : 'Expand color picker'} aria-label={isCustomExpanded ? 'Collapse color picker' : 'Expand color picker'}
> >
<svg className={`w-3.5 h-3.5 transition-transform duration-base ${isCustomExpanded ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}> <svg className={`w-3.5 h-3.5 transition-transform duration-base ${isCustomExpanded ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" /> <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
</svg> </svg>
</button> </IconButton>
</div> </div>
{isCustomExpanded && ( {isCustomExpanded && (

View file

@ -7,7 +7,7 @@ import { useAuthSession } from '@/hooks/useAuthSession';
import { getAuthClient } from '@/lib/client/auth-client'; import { getAuthClient } from '@/lib/client/auth-client';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { UserIcon } from '@/components/icons/Icons'; import { UserIcon } from '@/components/icons/Icons';
import { IconButton, buttonClass } from '@/components/ui'; import { IconButton, SidebarNavItem, SidebarNavLink, buttonClass } from '@/components/ui';
type UserMenuVariant = 'toolbar' | 'sidebar'; type UserMenuVariant = 'toolbar' | 'sidebar';
@ -31,21 +31,24 @@ export function UserMenu({
router.push('/signin'); router.push('/signin');
}; };
const rowClass =
'w-full inline-flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border border-transparent transition duration-base ease-standard text-left hover:border-accent hover:bg-accent-wash hover:text-accent';
if (!session || session.user.isAnonymous) { if (!session || session.user.isAnonymous) {
if (variant === 'sidebar') { if (variant === 'sidebar') {
return ( return (
<div className={`flex w-full flex-col gap-0.5 ${className}`}> <div className={`flex w-full flex-col gap-0.5 ${className}`}>
<Link href="/signin" className={rowClass}> <Link href="/signin" legacyBehavior passHref>
<UserIcon className="h-3.5 w-3.5 text-soft" /> <SidebarNavLink
<span className="truncate">Connect</span> compact
icon={<UserIcon className="h-3.5 w-3.5" />}
label="Connect"
/>
</Link> </Link>
{enableUserSignups && ( {enableUserSignups && (
<Link href="/signup" className={rowClass}> <Link href="/signup" legacyBehavior passHref>
<UserIcon className="h-3.5 w-3.5 text-soft" /> <SidebarNavLink
<span className="truncate">Create account</span> compact
icon={<UserIcon className="h-3.5 w-3.5" />}
label="Create account"
/>
</Link> </Link>
)} )}
</div> </div>
@ -72,20 +75,24 @@ export function UserMenu({
if (variant === 'sidebar') { if (variant === 'sidebar') {
return ( return (
<button <SidebarNavItem
compact
onClick={handleDisconnectAccount} onClick={handleDisconnectAccount}
className={`${rowClass} ${className}`} className={className}
title="Disconnect account" title="Disconnect account"
aria-label="Disconnect account" aria-label="Disconnect account"
icon={<UserIcon className="h-3.5 w-3.5" />}
label={session.user.email || 'Account'}
trailing={(
<svg className="h-3.5 w-3.5 shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
<polyline points="16 17 21 12 16 7"></polyline>
<line x1="21" y1="12" x2="9" y2="12"></line>
</svg>
)}
> >
<UserIcon className="h-3.5 w-3.5 text-soft" /> {session.user.email || 'Account'}
<span className="truncate flex-1">{session.user.email || 'Account'}</span> </SidebarNavItem>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
<polyline points="16 17 21 12 16 7"></polyline>
<line x1="21" y1="12" x2="9" y2="12"></line>
</svg>
</button>
); );
} }

View file

@ -182,6 +182,16 @@ function SidebarUploadLoader({
); );
} }
function DocumentListStateLoader() {
return (
<div
className="h-full w-full min-h-0 bg-surface-sunken animate-pulse"
aria-label="Loading documents"
aria-busy="true"
/>
);
}
function DocumentListInner({ brand, appActions }: DocumentListInnerProps) { function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
const cachedState = cachedDocumentListState; const cachedState = cachedDocumentListState;
const [sortBy, setSortBy] = useState<SortBy>(cachedState?.sortBy ?? DEFAULT_STATE.sortBy); const [sortBy, setSortBy] = useState<SortBy>(cachedState?.sortBy ?? DEFAULT_STATE.sortBy);
@ -670,7 +680,11 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
{isLoading ? ( {isLoading ? (
<div className="flex-1 min-h-0 overflow-hidden"> <div className="flex-1 min-h-0 overflow-hidden">
<DocumentListSkeleton viewMode={fallbackViewMode} iconSize={iconSize} /> {isInitialized ? (
<DocumentListSkeleton viewMode={fallbackViewMode} iconSize={iconSize} />
) : (
<DocumentListStateLoader />
)}
</div> </div>
) : allDocuments.length === 0 ? ( ) : allDocuments.length === 0 ? (
<div className="flex-1 min-h-0 flex items-center justify-center p-6"> <div className="flex-1 min-h-0 flex items-center justify-center p-6">

View file

@ -79,20 +79,20 @@ function FolderRow({
countClassName="group-hover/folder:-translate-x-6 group-focus-within/folder:-translate-x-6" countClassName="group-hover/folder:-translate-x-6 group-focus-within/folder:-translate-x-6"
isDropTarget={isDropTarget} isDropTarget={isDropTarget}
/> />
<button <IconButton
type="button"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
onDelete(); onDelete();
}} }}
className="absolute right-1 top-1/2 -translate-y-1/2 h-5 w-5 inline-flex items-center justify-center rounded text-soft opacity-0 group-hover/folder:opacity-100 group-focus-within/folder:opacity-100 hover:text-accent hover:bg-accent-wash transition" size="xs"
className="absolute right-1 top-1/2 -translate-y-1/2 opacity-0 group-hover/folder:opacity-100 group-focus-within/folder:opacity-100"
aria-label={`Delete ${folder.name}`} aria-label={`Delete ${folder.name}`}
title={`Delete ${folder.name}`} title={`Delete ${folder.name}`}
> >
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg> </svg>
</button> </IconButton>
</div> </div>
); );
} }

View file

@ -10,7 +10,7 @@ import {
HamburgerIcon, HamburgerIcon,
} from './finderIcons'; } from './finderIcons';
import { ChevronUpDownIcon } from '@/components/icons/Icons'; import { ChevronUpDownIcon } from '@/components/icons/Icons';
import { SearchField, Toolbar, ToolbarButton, ToolbarGroup, ToolbarSegment, listboxOptionClass, listboxOptionsClass, toolbarButtonStyles } from '@/components/ui'; import { SearchField, Toolbar, ToolbarButton, ToolbarGroup, ToolbarSegment, listboxCompactOptionClass, listboxCompactOptionsClass, toolbarButtonStyles } from '@/components/ui';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
interface FinderToolbarProps { interface FinderToolbarProps {
@ -146,17 +146,17 @@ export function FinderToolbar({
</ToolbarButton> </ToolbarButton>
<Listbox value={sortBy} onChange={onSortByChange}> <Listbox value={sortBy} onChange={onSortByChange}>
<ListboxButton <ListboxButton
className={toolbarButtonStyles({ className: 'gap-1 min-w-[90px] justify-between' })} className={toolbarButtonStyles({ className: 'gap-1 min-w-[86px] justify-between' })}
> >
<span>{currentSort.label}</span> <span>{currentSort.label}</span>
<ChevronUpDownIcon className="h-3 w-3 opacity-60" /> <ChevronUpDownIcon className="h-3 w-3 opacity-60" />
</ListboxButton> </ListboxButton>
<ListboxOptions anchor="bottom end" className={listboxOptionsClass}> <ListboxOptions anchor="bottom end" className={listboxCompactOptionsClass}>
{SORT_OPTIONS.map((opt) => ( {SORT_OPTIONS.map((opt) => (
<ListboxOption <ListboxOption
key={opt.value} key={opt.value}
value={opt.value} value={opt.value}
className={({ active, selected }) => listboxOptionClass(active || selected)} className={({ active, selected }) => listboxCompactOptionClass(active, selected)}
> >
{opt.label} {opt.label}
</ListboxOption> </ListboxOption>

View file

@ -8,7 +8,7 @@ import toast from 'react-hot-toast';
import { useTTS } from '@/contexts/TTSContext'; import { useTTS } from '@/contexts/TTSContext';
import { useConfig } from '@/contexts/ConfigContext'; import { useConfig } from '@/contexts/ConfigContext';
import { RefreshIcon, InfoIcon } from '@/components/icons/Icons'; import { RefreshIcon, InfoIcon } from '@/components/icons/Icons';
import { buttonClass } from '@/components/ui'; import { Button, IconButton, popoverPanelClass } from '@/components/ui';
import { ReaderSidebarShell } from '@/components/reader/ReaderSidebarShell'; import { ReaderSidebarShell } from '@/components/reader/ReaderSidebarShell';
import { compareSegmentLocators, locatorGroupKey, locatorIdentityKey } from '@/lib/shared/tts-locator'; import { compareSegmentLocators, locatorGroupKey, locatorIdentityKey } from '@/lib/shared/tts-locator';
import { buildSegmentKey, buildSegmentKeyPrefix } from '@/lib/shared/tts-segment-plan'; import { buildSegmentKey, buildSegmentKeyPrefix } from '@/lib/shared/tts-segment-plan';
@ -632,33 +632,27 @@ export function SegmentsSidebar({ isOpen, setIsOpen, documentId, epubBookRef }:
const headerActions = ( const headerActions = (
<> <>
<button <Button
type="button"
onClick={() => void handleClearCache()} onClick={() => void handleClearCache()}
aria-label="Clear segments cache" aria-label="Clear segments cache"
title="Clear cache for listed segments" title="Clear cache for listed segments"
disabled={isClearingSegments} disabled={isClearingSegments}
className={buttonClass({ variant="secondary"
variant: 'secondary', size="xs"
size: 'xs', className="h-8 px-2 text-soft"
className: 'h-8 px-2 text-soft',
})}
> >
{isClearingSegments ? 'Clearing…' : 'Clear'} {isClearingSegments ? 'Clearing…' : 'Clear'}
</button> </Button>
<button <IconButton
type="button"
onClick={handleRefresh} onClick={handleRefresh}
aria-label="Refresh segments" aria-label="Refresh segments"
title="Refresh" title="Refresh"
className={buttonClass({ tone="surface"
variant: 'secondary', size="md"
size: 'icon', className="h-8 w-8 text-soft"
className: 'h-8 w-8 text-soft',
})}
> >
<RefreshIcon className="w-3.5 h-3.5" /> <RefreshIcon className="w-3.5 h-3.5" />
</button> </IconButton>
</> </>
); );
@ -893,9 +887,10 @@ function SegmentMetadataPopover({ row }: { row: TTSSegmentRow }) {
return ( return (
<Popover className="relative shrink-0"> <Popover className="relative shrink-0">
<PopoverButton <PopoverButton
as={IconButton}
size="sm"
aria-label="Segment metadata" aria-label="Segment metadata"
title="Metadata" title="Metadata"
className="inline-flex items-center justify-center w-7 h-7 rounded-md border border-transparent text-soft hover:bg-accent-wash hover:border-line hover:text-accent transition-colors"
> >
<InfoIcon className="w-3.5 h-3.5" /> <InfoIcon className="w-3.5 h-3.5" />
</PopoverButton> </PopoverButton>
@ -910,7 +905,7 @@ function SegmentMetadataPopover({ row }: { row: TTSSegmentRow }) {
> >
<PopoverPanel <PopoverPanel
anchor="bottom end" anchor="bottom end"
className="z-[60] w-[300px] mt-1 rounded-lg border border-line bg-surface shadow-elev-3 p-3" className={`${popoverPanelClass} z-[60] w-[300px] mt-1`}
> >
<dl className="space-y-2"> <dl className="space-y-2">
<Row label="locator"> <Row label="locator">

View file

@ -13,6 +13,9 @@ export const listboxPanelClass =
export const listboxOptionsClass = export const listboxOptionsClass =
cn(listboxPanelClass, 'w-[var(--button-width)] [--anchor-gap:0.25rem]'); cn(listboxPanelClass, 'w-[var(--button-width)] [--anchor-gap:0.25rem]');
export const listboxCompactOptionsClass =
'z-50 min-w-[8rem] rounded-md bg-surface p-1 shadow-elev-2 ring-1 ring-line focus:outline-none [--anchor-gap:0.25rem]';
export const listboxOptionClass = (active: boolean, selected = false, inset: 'check' | 'none' = 'check') => export const listboxOptionClass = (active: boolean, selected = false, inset: 'check' | 'none' = 'check') =>
cn( cn(
'relative cursor-pointer select-none rounded-sm py-1.5 text-sm', 'relative cursor-pointer select-none rounded-sm py-1.5 text-sm',
@ -20,6 +23,16 @@ export const listboxOptionClass = (active: boolean, selected = false, inset: 'ch
selected ? 'bg-accent text-background font-medium' : active ? 'bg-accent-wash text-foreground' : 'text-foreground', selected ? 'bg-accent text-background font-medium' : active ? 'bg-accent-wash text-foreground' : 'text-foreground',
); );
export const listboxCompactOptionClass = (active: boolean, selected = false) =>
cn(
'relative cursor-pointer select-none rounded-sm px-2 py-1 text-xs',
active
? 'bg-accent-wash text-accent'
: selected
? 'bg-surface-sunken text-accent font-medium'
: 'text-foreground',
);
export function Select({ export function Select({
value, value,
onChange, onChange,

View file

@ -1,4 +1,4 @@
import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react'; import type { AnchorHTMLAttributes, ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
import { cn } from './cn'; import { cn } from './cn';
import { focusRing, motionColors } from './tokens'; import { focusRing, motionColors } from './tokens';
@ -50,6 +50,82 @@ export function SidebarNavGroup({
); );
} }
export function sidebarNavItemClass({
active = false,
compact = false,
isDropTarget = false,
className,
}: {
active?: boolean;
compact?: boolean;
isDropTarget?: boolean;
className?: string;
} = {}) {
return cn(
'group w-full min-w-0 border text-left font-medium',
'inline-flex items-center transition duration-base ease-standard',
focusRing,
motionColors,
compact ? 'gap-1.5 rounded-md px-2 py-1 text-xs' : 'gap-2 rounded-md px-2.5 py-1.5 text-sm',
active
? 'border-accent-line bg-surface-sunken text-accent'
: 'border-transparent bg-transparent text-foreground hover:border-accent-line hover:bg-accent-wash hover:text-accent',
isDropTarget ? 'ring-1 ring-accent-line' : '',
className,
);
}
export function sidebarNavIconClass({
active = false,
compact = false,
}: {
active?: boolean;
compact?: boolean;
} = {}) {
return cn(
'shrink-0 inline-flex items-center justify-center transition-colors duration-base',
compact ? 'h-4 w-4' : 'h-5 w-5',
active ? 'text-accent' : 'text-soft group-hover:text-accent',
);
}
function SidebarNavItemContent({
active = false,
icon,
label,
count,
countClassName,
trailing,
compact = false,
children,
}: {
active?: boolean;
icon?: ReactNode;
label?: ReactNode;
count?: number;
countClassName?: string;
trailing?: ReactNode;
compact?: boolean;
children?: ReactNode;
}) {
return (
<>
{icon ? (
<span className={sidebarNavIconClass({ active, compact })}>
{icon}
</span>
) : null}
{label ?? children ? <span className="min-w-0 flex-1 truncate">{label ?? children}</span> : null}
{typeof count === 'number' && count > 0 ? (
<span className={cn('text-[10px] text-soft tabular-nums transition-transform duration-base ease-standard', countClassName)}>
{count}
</span>
) : null}
{trailing}
</>
);
}
export function SidebarNavItem({ export function SidebarNavItem({
active = false, active = false,
icon, icon,
@ -76,38 +152,62 @@ export function SidebarNavItem({
return ( return (
<button <button
type={type} type={type}
className={cn( className={sidebarNavItemClass({ active, compact, isDropTarget, className })}
'group w-full min-w-0 border text-left font-medium',
'inline-flex items-center transition duration-base ease-standard',
focusRing,
motionColors,
compact ? 'gap-1.5 rounded-md px-2 py-1 text-xs' : 'gap-2 rounded-md px-2.5 py-1.5 text-sm',
active
? 'border-accent-line bg-surface-sunken text-accent'
: 'border-transparent bg-transparent text-foreground hover:border-accent-line hover:bg-accent-wash hover:text-accent',
isDropTarget ? 'ring-1 ring-accent-line' : '',
className,
)}
{...props} {...props}
> >
{icon ? ( <SidebarNavItemContent
<span active={active}
className={cn( compact={compact}
'shrink-0 inline-flex items-center justify-center transition-colors duration-base', icon={icon}
compact ? 'h-4 w-4' : 'h-5 w-5', label={label}
active ? 'text-accent' : 'text-soft group-hover:text-accent', count={count}
)} countClassName={countClassName}
> trailing={trailing}
{icon} >
</span> {children}
) : null} </SidebarNavItemContent>
{label ?? children ? <span className="min-w-0 flex-1 truncate">{label ?? children}</span> : null}
{typeof count === 'number' && count > 0 ? (
<span className={cn('text-[10px] text-soft tabular-nums transition-transform duration-base ease-standard', countClassName)}>
{count}
</span>
) : null}
{trailing}
</button> </button>
); );
} }
export function SidebarNavLink({
active = false,
icon,
label,
count,
countClassName,
trailing,
isDropTarget = false,
className,
compact = false,
children,
...props
}: AnchorHTMLAttributes<HTMLAnchorElement> & {
active?: boolean;
icon?: ReactNode;
label?: ReactNode;
count?: number;
countClassName?: string;
trailing?: ReactNode;
isDropTarget?: boolean;
compact?: boolean;
}) {
return (
<a
className={sidebarNavItemClass({ active, compact, isDropTarget, className })}
{...props}
>
<SidebarNavItemContent
active={active}
compact={compact}
icon={icon}
label={label}
count={count}
countClassName={countClassName}
trailing={trailing}
>
{children}
</SidebarNavItemContent>
</a>
);
}