mirror of
https://github.com/vernu/textbee.git
synced 2026-07-30 17:07:46 -04:00
community-links was the only file in the app still wrapping a Button in a Link, four times, producing an anchor around a button: invalid markup and a nested interactive control that assistive tech announces twice. Everywhere else already uses Button asChild. Two whole Card blocks sat commented out, with an icon imported solely for that dead code. community/page.tsx was the only dashboard section that never got the mobile pass, keeping p-6 with no p-4 step and an unconditional text-3xl. It was also the only section missing from the 375px overflow guard, which is presumably how it was missed. Extracting the shared PageHeader, which the messaging, webhooks and account layouts all repeated by hand, fixes that outlier by construction. Both billing limit grids and the promo modal were locked to two columns at every width, so the meter captions had no room on a phone. window.open kept a live opener handle back to the app in four places. Browsers imply noopener for anchor targets but not for window.open. The share dialog grid moves to 3 columns then 7. Worth stating plainly: this is not an overflow fix. I expected 7 icons at grid-cols-4 to overflow at 375px and the extended guard proved they do not. It was only an awkward 4 + 3 split. The overflow guard now covers 12 routes instead of 6 and opens a dialog, since the densest layouts in the app only exist inside modals. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
import type { ComponentType, ReactNode } from 'react'
|
|
|
|
type PageHeaderProps = {
|
|
title: string
|
|
description?: string
|
|
icon?: ComponentType<{ className?: string }>
|
|
actions?: ReactNode
|
|
}
|
|
|
|
/**
|
|
* Section heading shared by the dashboard's route layouts.
|
|
*
|
|
* The same icon plus heading plus description block was written out four
|
|
* times, and community/page.tsx had drifted: it kept an unconditional
|
|
* text-3xl and no mobile padding step while every other section had moved to
|
|
* a responsive size. One definition makes that class of drift impossible.
|
|
*/
|
|
export default function PageHeader({
|
|
title,
|
|
description,
|
|
icon: Icon,
|
|
actions,
|
|
}: PageHeaderProps) {
|
|
return (
|
|
<div className='mb-4 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between'>
|
|
<div className='space-y-1'>
|
|
<div className='flex items-center space-x-2'>
|
|
{Icon && <Icon className='h-6 w-6 text-primary' />}
|
|
<h2 className='text-2xl font-bold tracking-tight sm:text-3xl'>
|
|
{title}
|
|
</h2>
|
|
</div>
|
|
{description && (
|
|
<p className='text-muted-foreground'>{description}</p>
|
|
)}
|
|
</div>
|
|
{actions}
|
|
</div>
|
|
)
|
|
}
|