import { Children, type ReactNode, isValidElement, useId, useState } from 'react' import ToggleSwitch from '../Settings/ToggleSwitch' import { fs } from '../shared/DialogShell' import { ChevronDown } from 'lucide-react' import { useTranslation } from '../../i18n' /** How many of the shelf's rows are switched on, read from the rows' own `enabled`. */ function enabledRows(rows: ReactNode[]): number { return rows.filter((row) => isValidElement<{ enabled?: boolean }>(row) && row.props.enabled === true).length } /** * One addon in its type's card: a row like the bag sidebar's (#2541), with the * icon tile on the left, name and description beside it and the switch on the * right. Its sub-features sit under it in a grey inset box of hairline rows. * * The on/off state rides on the icon tile and the switch: a switched-off addon * greys its tile and its description, but keeps its name at full strength. The * name is the tile's identity, not its state; greying it out reads as "broken" * rather than "not enabled". * * The row is not a click target, only the switches are. No lift, no pointer * cursor, no `role="button"`. * * A shelf of more than one row starts folded behind a bar that says how many * options there are and how many are on, so a page of addons stays short and * the options are still plain to see. */ export default function AddonTile({ icon, name, description, enabled, onToggle, children, }: { icon: ReactNode name: string description?: string enabled: boolean onToggle: () => void /** The sub-shelf: `` children. */ children?: ReactNode }) { const { t } = useTranslation() const shelfId = useId() const [open, setOpen] = useState(false) const rows = Children.toArray(children) const foldable = rows.length > 1 const active = enabledRows(rows) return (
{icon}

{name}

{description}

{rows.length > 0 && (
{foldable && ( )} {/* Sitting inside the parent on its own fill is enough to say these belong to it: no rail, no indent guides. */} {(!foldable || open) && (
    {children}
)}
)}
) }