diff --git a/web/DeviceToggle.tsx b/web/DeviceToggle.tsx
index 24bc0e7..2c45c35 100644
--- a/web/DeviceToggle.tsx
+++ b/web/DeviceToggle.tsx
@@ -60,12 +60,20 @@ const OPTIONS: { value: DeviceName; Icon: typeof Monitor }[] = [
* choice legible without hovering for a tooltip.
*
* The label comes from DEVICES, which is also what the preview names in its own caption. One list.
+ *
+ * ── Narrow, it goes back to icons ──
+ *
+ * A CONTAINER query, not a screen one: this sits in a workspace panel whose width is a divider the
+ * user drags, so the window's width says nothing about the room there is. `@container` on the row
+ * makes the row itself the thing measured.
+ *
+ * The word is then the `title`, so the answer is still one hover away rather than gone.
*/
export const DeviceToggle = () => {
const [device, setDevice] = useDevice();
return (
-
+
{OPTIONS.map(({ value, Icon }) => (
))}
diff --git a/web/sections/LayoutPanel.tsx b/web/sections/LayoutPanel.tsx
index 3d5ce12..c01f003 100644
--- a/web/sections/LayoutPanel.tsx
+++ b/web/sections/LayoutPanel.tsx
@@ -1,6 +1,5 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
-import { useSearchParams } from 'react-router';
import { useClient } from 'hooks/useClient';
import { readableError } from '../errors';
import { useFlash } from '../useFlash';
@@ -110,6 +109,9 @@ const themeProperties = (draft: Layout): Record => ({
'--font-display': draft.font_display && `"${draft.font_display}", sans-serif`,
});
+/** Every section, open from the start. The values below must match the AccordionItems. */
+const SECTIONS_OPEN = ['colours', 'typefaces', 'padding'];
+
const COLOURS = [
{ key: 'background' as const, label: 'Background', fallback: '#ffffff' },
{ key: 'foreground' as const, label: 'Text', fallback: '#000000' },
@@ -124,23 +126,7 @@ export const LayoutPanel = () => {
const [stored, setStored] = useState(null);
const [draft, setDraft] = useState(null);
const [busy, setBusy] = useState(false);
- const [params, setParams] = useSearchParams();
const devPort = useDevPort();
- /** Controlled, because the grid stack below decides visibility rather than Radix unmounting. */
- /*
- The open tab, in the URL — `?tab=padding`.
-
- Same rule as the mode and the device: it is addressable. "Look at the typefaces" is a link somebody
- sends, and a reload that drops you back on Colours loses the place you were working in.
-
- Absent means Colours, the first one, so an ordinary link carries nothing.
- */
- const tab = params.get('tab') ?? 'colours';
- const setTab = (next: string) => {
- const search = new URLSearchParams(params);
- search.set('tab', next);
- setParams(search, { replace: true });
- };
const [error, setError] = useState(null);
const [saved, flashSaved] = useFlash();
@@ -263,7 +249,14 @@ export const LayoutPanel = () => {
}
setEditorRef.current(
-
+ /*
+ Every section open to begin with.
+
+ It opened on one, from `?tab=`, which is what a set of TABS wants — one at a time, and which
+ one is addressable. These are not tabs: they are the whole of what this screen decides, and a
+ column that starts collapsed asks somebody to go looking for the setting they came for.
+ */
+ Colors
@@ -357,7 +350,7 @@ export const LayoutPanel = () => {
);
- }, [draft, tab, device]);
+ }, [draft, device]);
// Cleared on unmount, or the panel goes on offering Layout's controls over somebody else's page.
useEffect(() => () => setEditorRef.current(null), []);