one padding value, for the device on the toggle

The three columns became one select. Which breakpoint it writes comes from the device control above it,
so the value you see is the value for the view you are looking at.
This commit is contained in:
2026-09-01 04:02:37 +01:00
parent 89380a69d6
commit ed900bc2d3
+13 -38
View File
@@ -1,3 +1,4 @@
import { useDevice } from '../DeviceToggle';
/** /**
* The site's horizontal gutter: how far the content sits from the edge of the window. * The site's horizontal gutter: how far the content sits from the edge of the window.
* *
@@ -23,17 +24,8 @@
export type Gutter = Partial<Record<'base' | 'md' | 'lg', number>>; export type Gutter = Partial<Record<'base' | 'md' | 'lg', number>>;
/** /** The device toggle's names, and the breakpoint each one writes. */
* The three widths, smallest first, with the name the admin uses for each. const BREAKPOINT = { desktop: 'lg', tablet: 'md', mobile: 'base' } as const;
*
* Smallest first because that is the direction they cascade: `md` inherits from `base`, `lg` from `md`.
* Read left to right, the row is the progression.
*/
const WIDTHS = [
{ key: 'base' as const, label: 'Mobile', hint: 'every width' },
{ key: 'md' as const, label: 'Tablet', hint: '768 and up' },
{ key: 'lg' as const, label: 'Desktop', hint: '1024 and up' },
];
/** What a width falls back to: the nearest smaller one that has a value. */ /** What a width falls back to: the nearest smaller one that has a value. */
const inherited = (gutter: Gutter, key: 'base' | 'md' | 'lg'): number | null => { const inherited = (gutter: Gutter, key: 'base' | 'md' | 'lg'): number | null => {
@@ -55,53 +47,36 @@ export const GutterTab = ({
steps: number[]; steps: number[];
onChange: (gutter: Gutter) => void; onChange: (gutter: Gutter) => void;
}) => { }) => {
const set = (key: 'base' | 'md' | 'lg', value: string) => { const [device] = useDevice();
const key = BREAKPOINT[device];
const set = (value: string) => {
const next = { ...gutter }; const next = { ...gutter };
// Removed rather than stored as null: an absence is what "inherit" means, and a marker for it would // Removed rather than stored as null: an absence is what "inherit" means.
// leave two ways to say the same thing.
if (value === '') delete next[key]; if (value === '') delete next[key];
else next[key] = Number(value); else next[key] = Number(value);
onChange(next); onChange(next);
}; };
return (
<div className="flex flex-col gap-3">
<div className="flex flex-wrap items-baseline gap-2">
<h4 className="text-xs font-medium">Horizontal padding</h4>
<span className="text-[10px] text-muted-foreground">
The space between the content and the edge of the window — the header, the page and the footer
</span>
</div>
<div className="grid grid-cols-3 gap-3 sm:grid-cols-4">
{WIDTHS.map(({ key, label, hint }) => {
const own = gutter[key]; const own = gutter[key];
const from = inherited(gutter, key); const from = inherited(gutter, key);
return ( return (
<div key={key} className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<label className="text-xs">{label}</label> <label className="text-xs">Horizontal padding</label>
<select <select
value={own === undefined ? '' : String(own)} value={own === undefined ? '' : String(own)}
onChange={(event) => set(key, event.currentTarget.value)} onChange={(event) => set(event.currentTarget.value)}
className="h-8 rounded-md border border-input bg-transparent px-2 text-xs" className="h-8 rounded-md border border-input bg-transparent px-2 text-xs"
> >
{/* Mobile is the smallest, so there is nothing below it to inherit from and the empty {/* Mobile is the smallest, so there is nothing below it to inherit from. */}
option means what it actually does there: none. */} <option value="">{key === 'base' ? 'None' : from === null ? 'Inherit (none)' : `Inherit (${from})`}</option>
<option value="">
{key === 'base' ? 'None' : from === null ? 'Inherit (none)' : `Inherit (${from})`}
</option>
{steps.map((step) => ( {steps.map((step) => (
<option key={step} value={String(step)}> <option key={step} value={String(step)}>
{step} {step}
</option> </option>
))} ))}
</select> </select>
<span className="truncate text-[10px] text-muted-foreground">{hint}</span>
</div>
);
})}
</div>
</div> </div>
); );
}; };