feat(ui): the six native selects become the house controls

Owner's pick from the S7 mockups (2026-09-19): a short fixed set is a SegmentedToggle — the live
search's result count, the table's rows per page, a download profile's mode (on its own row, so the
three worded choices fit a phone) and audio format — and a longer set or the user's own list is a
FilterSelect: the profile's quality (seven heights) and the download dialog's profile.

A lint rule refuses a native <select> from now on (the canonical "FE control" row). The px-frozen
size rules also caught up with a fraction: `text-[9.5px]` had slipped past the integer-only pattern
in the Glass tuner, which is rem now.
This commit is contained in:
2026-09-19 17:53:22 +02:00
parent 17a26894b0
commit 0ef25a8037
9 changed files with 171 additions and 84 deletions
+15 -16
View File
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { hasPagerContent, pageCount } from "./pagerContent";
import { FocusSafeButton } from "./FocusSafeButton";
import SegmentedToggle from "./SegmentedToggle";
// The Prev / page-input / Next + "N per page" cluster, lifted out of DataTable so a non-table view
// (the channel manager's card layout) can paginate the same way. Controlled: the caller owns page +
@@ -93,24 +94,22 @@ export default function Pager({
</div>
)}
{total > 0 && (
<label className="flex items-center gap-2 text-muted">
{sizeLabel}
<select
value={size}
onChange={(e) => {
onSizeChange(Number(e.target.value));
<div className="flex items-center gap-2 text-muted">
<span aria-hidden="true">{sizeLabel}</span>
{/* A handful of fixed sizes plus "All": segmented, the house control for a short fixed set. */}
<SegmentedToggle
ariaLabel={sizeLabel}
value={String(size)}
onChange={(v) => {
onSizeChange(Number(v));
scrollListToTop();
}}
className="bg-surface border border-border rounded-md px-1.5 py-1 text-xs focus:outline-hidden focus:ring-2 focus:ring-accent/40"
>
{pageSizeOptions.map((n) => (
<option key={n} value={n}>
{n}
</option>
))}
<option value={0}>{t("datatable.all")}</option>
</select>
</label>
options={[
...pageSizeOptions.map((n) => ({ value: String(n), label: String(n) })),
{ value: "0", label: t("datatable.all") },
]}
/>
</div>
)}
</div>
);