From a1e51b0b97728a2a449c720add77e2a70871515d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 31 Aug 2026 05:02:36 +0100 Subject: [PATCH] the device is in the URL too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ?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) --- web/ViewMode.tsx | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/web/ViewMode.tsx b/web/ViewMode.tsx index 5c56f0d..9e00694 100644 --- a/web/ViewMode.tsx +++ b/web/ViewMode.tsx @@ -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('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.