Trade strip: smaller pills, four visible, scroll hint
The pills were sized for a form, not a dense strip: at px-4 py-3 only two and a bit fitted across a 390px phone, so the trade filter read as a two-trade list rather than a scrollable set. - Chip gains a `size` prop. 'sm' (px-3 py-1.5, text-meta) is for horizontal strips; 'md' stays the default everywhere a chip is a primary choice, so nothing else moves. - Four trades now fit with the fifth cut at the edge, which is what tells you the row scrolls. - Added a right-edge fade. The scrollbar is hidden, so without it a row that simply ends at the bezel reads as the whole list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -66,23 +66,37 @@ export function ShowcaseDeck({
|
|||||||
the drag gesture and never has to stay legible on a bright image. */}
|
the drag gesture and never has to stay legible on a bright image. */}
|
||||||
<div className="min-w-0 shrink-0 px-4 pt-[3.25rem]">
|
<div className="min-w-0 shrink-0 px-4 pt-[3.25rem]">
|
||||||
{selected ? (
|
{selected ? (
|
||||||
<Chip selected onClick={() => setCategoryId(null)}>
|
<Chip selected size="sm" onClick={() => setCategoryId(null)}>
|
||||||
{selected.name}
|
{selected.name}
|
||||||
<X className="h-4 w-4" aria-hidden />
|
<X className="h-3.5 w-3.5" aria-hidden />
|
||||||
<span className="sr-only">Show all trades</span>
|
<span className="sr-only">Show all trades</span>
|
||||||
</Chip>
|
</Chip>
|
||||||
) : (
|
) : (
|
||||||
|
// The strip scrolls sideways through every trade. The right-hand fade
|
||||||
|
// is the only affordance saying so — the scrollbar is hidden, and a
|
||||||
|
// row that simply ends at the bezel reads as the whole list.
|
||||||
|
<div className="relative -mx-4">
|
||||||
<div
|
<div
|
||||||
className="-mx-4 flex gap-2 overflow-x-auto px-4 pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
className="flex gap-1.5 overflow-x-auto px-4 pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
||||||
role="group"
|
role="group"
|
||||||
aria-label="Filter by trade"
|
aria-label="Filter by trade"
|
||||||
>
|
>
|
||||||
{categories.map((c) => (
|
{categories.map((c) => (
|
||||||
<Chip key={c.id} className="shrink-0" onClick={() => setCategoryId(c.id)}>
|
<Chip
|
||||||
|
key={c.id}
|
||||||
|
size="sm"
|
||||||
|
className="shrink-0"
|
||||||
|
onClick={() => setCategoryId(c.id)}
|
||||||
|
>
|
||||||
{c.name}
|
{c.name}
|
||||||
</Chip>
|
</Chip>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
aria-hidden
|
||||||
|
className="pointer-events-none absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-page to-transparent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -9,18 +9,28 @@ import { cn } from '@/lib/utils';
|
|||||||
*/
|
*/
|
||||||
export function Chip({
|
export function Chip({
|
||||||
selected = false,
|
selected = false,
|
||||||
|
size = 'md',
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ButtonHTMLAttributes<HTMLButtonElement> & { selected?: boolean }) {
|
}: React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||||
|
selected?: boolean;
|
||||||
|
/**
|
||||||
|
* 'sm' is for dense horizontal strips — the trade filter has to fit four
|
||||||
|
* trades across a 390px phone before the fifth is cut off as a scroll hint.
|
||||||
|
* 'md' stays the default everywhere a chip is a primary choice.
|
||||||
|
*/
|
||||||
|
size?: 'sm' | 'md';
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-pressed={selected}
|
aria-pressed={selected}
|
||||||
{...props}
|
{...props}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-1.5 rounded-pill border-[1.5px] px-4 py-3 text-body-sm',
|
'inline-flex items-center rounded-pill border-[1.5px]',
|
||||||
'transition-[color,background-color,border-color] duration-[120ms] ease-standard',
|
'transition-[color,background-color,border-color] duration-[120ms] ease-standard',
|
||||||
|
size === 'sm' ? 'gap-1 px-3 py-1.5 text-meta' : 'gap-1.5 px-4 py-3 text-body-sm',
|
||||||
'disabled:pointer-events-none disabled:opacity-45',
|
'disabled:pointer-events-none disabled:opacity-45',
|
||||||
selected
|
selected
|
||||||
? 'border-brand-500 bg-brand-100 font-semibold text-ink-950'
|
? 'border-brand-500 bg-brand-100 font-semibold text-ink-950'
|
||||||
@@ -28,7 +38,7 @@ export function Chip({
|
|||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{selected && <Check className="h-4 w-4" aria-hidden />}
|
{selected && <Check className={size === 'sm' ? 'h-3.5 w-3.5' : 'h-4 w-4'} aria-hidden />}
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user