the device is in the URL too

?mode=edit&device=mobile

I had argued this one should stay in React state — a way of LOOKING rather than a thing being looked at
— and the distinction did not survive contact with the obvious use. "Here is what it does on a phone"
is exactly the link somebody wants to send, and a URL that drops the width sends them the desktop.

docs/navigation-audit.md already said addressable state goes in the URL. Both of these are addressable.
The rule was right; my exception was not.

Absent means desktop, as absent means view: an ordinary link carries neither parameter, and each
appears once somebody has chosen it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-31 05:02:36 +01:00
co-authored by Claude Opus 5
parent 8d5c4797ad
commit a1e51b0b97
+25 -6
View File
@@ -19,12 +19,15 @@ import { useSearchParams } from 'react-router';
* So the bar shows these only when the open section says it has a preview, the same way Save renders
* nothing when there is nothing to save.
*
* ── Where each piece of state lives ──
* ── Both live in the URL ──
*
* The MODE is in the URL: it is addressable, and a link to a page being edited is a different thing
* from a link to the page. The DEVICE is not, yet — it is a way of looking rather than a thing being
* looked at, and nobody has wanted to send one. That distinction is worth keeping deliberate rather
* than letting both drift into whichever place was convenient.
* `?mode=edit&device=mobile`. I had argued the device should stay in React state — a way of LOOKING
* rather than a thing being looked at — and that distinction did not survive contact with the obvious
* use: "here is what it does on a phone" is exactly the link somebody wants to send, and a URL that
* drops the width sends them the desktop.
*
* docs/navigation-audit.md says addressable state goes in the URL, and both of these are addressable.
* The rule was already right; the exception was not.
*/
export type Mode = 'edit' | 'view';
@@ -104,7 +107,23 @@ export const ViewModeProvider = ({ children }: { children: ReactNode }) => {
[params, setParams],
);
const [device, setDevice] = useState<DeviceName>('desktop');
/*
The device, alongside the mode, for the same reason.
Absent means desktop — the default and the common case — so an ordinary link carries neither
parameter and each appears only once somebody has chosen it.
*/
const raw = params.get('device');
const device: DeviceName = raw === 'tablet' || raw === 'mobile' ? raw : 'desktop';
const setDevice = useCallback(
(next: DeviceName) => {
const search = new URLSearchParams(params);
search.set('device', next);
setParams(search, { replace: true });
},
[params, setParams],
);
const [previewable, setPreviewable] = useState(false);
// Stable, so the effect in `usePreviewable` is not re-run by this provider re-rendering.