Sifa professional network frontend (Next.js, React, TailwindCSS) sifa.id/
at main 65 lines 1.9 kB view raw
1'use client'; 2 3import { Children, useId, useState } from 'react'; 4 5import { CaretDown, CaretUp } from '@phosphor-icons/react'; 6import { useTranslations } from 'next-intl'; 7 8import { cn } from '@/lib/utils'; 9 10interface SectionOverflowProps { 11 /** Max items to show before "Show N more" button */ 12 maxVisible: number; 13 /** When true, show all items without disclosure (used for own profile editing) */ 14 disableOverflow?: boolean; 15 children: React.ReactNode; 16} 17 18export function SectionOverflow({ maxVisible, disableOverflow, children }: SectionOverflowProps) { 19 const [expanded, setExpanded] = useState(false); 20 const overflowId = useId(); 21 const t = useTranslations('sections'); 22 23 const items = Children.toArray(children); 24 25 if (items.length <= maxVisible || disableOverflow) { 26 return <>{items}</>; 27 } 28 29 const visible = items.slice(0, maxVisible); 30 const overflow = items.slice(maxVisible); 31 32 return ( 33 <> 34 {visible} 35 <div 36 id={overflowId} 37 className={cn( 38 'grid motion-safe:transition-[grid-template-rows] motion-safe:duration-200 motion-safe:ease-in-out', 39 expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]', 40 )} 41 > 42 <div className="overflow-hidden">{overflow}</div> 43 </div> 44 <button 45 type="button" 46 aria-expanded={expanded} 47 aria-controls={overflowId} 48 onClick={() => setExpanded((prev) => !prev)} 49 className="mt-3 flex items-center gap-1 text-sm font-medium text-muted-foreground hover:text-foreground motion-safe:transition-colors" 50 > 51 {expanded ? ( 52 <> 53 {t('showLess')} 54 <CaretUp size={16} aria-hidden="true" /> 55 </> 56 ) : ( 57 <> 58 {t('showMore', { count: overflow.length })} 59 <CaretDown size={16} aria-hidden="true" /> 60 </> 61 )} 62 </button> 63 </> 64 ); 65}