SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
4 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%
1.6 KB · 38 lines tsx
Raw Blame History
1"use client";23import { ChevronDown } from "lucide-react";4import { useState, type ReactNode } from "react";5import { fmtInt } from "@/lib/format";6import { cn } from "./cn";78/** Rows kept visible while collapsed (matches `.dci-collapse` nth-child rule in globals.css). */9export const COLLAPSE_ROWS = 10;1011/**12 * Mobile-only "Show all N" for long server-rendered lists (tables, <ol>/<ul>): under 640 px only the13 * first COLLAPSE_ROWS rows are shown until the user expands. Purely CSS-driven (data attribute), so the14 * children stay server components and nothing but serialisable props crosses the boundary.15 * On ≥ 640 px every row is visible and the toggle is hidden.16 */17export function CollapsibleRows({ total, label = "rows", children, className }: { total: number; label?: string; children: ReactNode; className?: string }) {18  const [open, setOpen] = useState(false);19  const collapsible = total > COLLAPSE_ROWS + 2;20  const collapsed = collapsible && !open;21  return (22    <div className={cn("dci-collapse", className)} data-collapsed={collapsed ? "" : undefined}>23      {children}24      {collapsible && (25        <button26          type="button"27          onClick={() => setOpen((o) => !o)}28          aria-expanded={!collapsed}29          className="mt-1 flex h-11 w-full items-center justify-center gap-1.5 rounded-sm border border-hair bg-surface text-[12.5px] font-medium text-ink-2 hover:text-ink sm:hidden"30        >31          {collapsed ? `Show all ${fmtInt(total)} ${label}` : "Show fewer"}32          <ChevronDown className={cn("size-3.5 transition-transform", !collapsed && "rotate-180")} strokeWidth={1.75} aria-hidden />33        </button>34      )}35    </div>36  );37}38