SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%
2.8 KB · 59 lines tsx
Raw Blame History
1"use client";2import * as React from "react";3import { cn } from "@/lib/utils";45/**6 * Section header shared by every settings page. On phones the layout renders the back bar with the7 * section title, so we only show the description there; on desktop the title + description stand at8 * the top of the content column.9 */10export function SettingsSection({ title, description, actions, children, className }: { title: string; description?: React.ReactNode; actions?: React.ReactNode; children: React.ReactNode; className?: string }) {11  return (12    <div className={cn("space-y-4", className)}>13      <div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">14        <div className="min-w-0">15          <h2 className="hidden text-[15px] font-semibold tracking-tight md:block">{title}</h2>16          {description ? <p className="text-[13px] leading-5 text-fg-muted">{description}</p> : null}17        </div>18        {actions ? <div className="flex shrink-0 gap-2">{actions}</div> : null}19      </div>20      {children}21    </div>22  );23}2425/** Grouped rows with hairlines (iOS-style list) — used for toggles and key/value rows on every breakpoint. */26export function SettingsGroup({ title, description, children, className, footer }: { title?: React.ReactNode; description?: React.ReactNode; children: React.ReactNode; className?: string; footer?: React.ReactNode }) {27  return (28    <section className={cn("min-w-0", className)}>29      {title ? (30        <header className="mb-2 px-1">31          <h3 className="text-[13px] font-semibold tracking-tight">{title}</h3>32          {description ? <p className="mt-0.5 text-[12px] leading-4 text-fg-muted">{description}</p> : null}33        </header>34      ) : null}35      <div className="panel divide-y divide-hairline overflow-hidden">{children}</div>36      {footer ? <p className="mt-2 px-1 text-[11px] leading-4 text-fg-subtle">{footer}</p> : null}37    </section>38  );39}4041/** One row: label + optional description on the left, control on the right. min-h 44 px. */42export function SettingsRow({ label, description, children, htmlFor, className }: { label: React.ReactNode; description?: React.ReactNode; children?: React.ReactNode; htmlFor?: string; className?: string }) {43  return (44    <div className={cn("flex min-h-[52px] items-center justify-between gap-4 px-4 py-3", className)}>45      <div className="min-w-0">46        {htmlFor ? (47          <label htmlFor={htmlFor} className="block text-[14px] font-medium leading-5">48            {label}49          </label>50        ) : (51          <p className="text-[14px] font-medium leading-5">{label}</p>52        )}53        {description ? <p className="mt-0.5 text-[12px] leading-4 text-fg-muted">{description}</p> : null}54      </div>55      {children ? <div className="shrink-0">{children}</div> : null}56    </div>57  );58}59