| 1 | "use client"; |
| 2 | |
| 3 | import { useState, type ReactNode } from "react"; |
| 4 | |
| 5 | |
| 6 | export function ShowMore({ |
| 7 | items, |
| 8 | pageSize = 50, |
| 9 | controlWrapper = "div", |
| 10 | noun = "more", |
| 11 | }: { |
| 12 | items: ReactNode[]; |
| 13 | pageSize?: number; |
| 14 | controlWrapper?: "div" | "li"; |
| 15 | noun?: string; |
| 16 | }) { |
| 17 | const [shown, setShown] = useState(pageSize); |
| 18 | const visible = items.slice(0, shown); |
| 19 | const remaining = items.length - shown; |
| 20 | |
| 21 | const control = |
| 22 | remaining > 0 ? ( |
| 23 | <div className="flex items-center justify-between gap-3 px-4 py-3"> |
| 24 | <span className="label text-ash-2"> |
| 25 | Showing {shown.toLocaleString()} of {items.length.toLocaleString()} |
| 26 | </span> |
| 27 | <button |
| 28 | type="button" |
| 29 | onClick={() => setShown((n) => n + pageSize)} |
| 30 | className="focus-ring label inline-flex min-h-[40px] items-center rounded-[3px] border border-line px-3 text-ash underline underline-offset-4 transition-colors hover:border-paper hover:text-paper" |
| 31 | > |
| 32 | Show {Math.min(pageSize, remaining).toLocaleString()} {noun} |
| 33 | </button> |
| 34 | </div> |
| 35 | ) : null; |
| 36 | |
| 37 | return ( |
| 38 | <> |
| 39 | {visible} |
| 40 | {control |
| 41 | ? controlWrapper === "li" |
| 42 | ? <li>{control}</li> |
| 43 | : control |
| 44 | : null} |
| 45 | </> |
| 46 | ); |
| 47 | } |