the mode is in the URL, and the controls are tabs
?mode=edit docs/navigation-audit.md draws the line: anything ADDRESSABLE goes in the URL, and whether you are editing a page or looking at it is exactly that. It survives a reload, it can be sent to somebody, and a link to a page being edited is a different thing from a link to the page. `mode`, not `view`. The parameter names the AXIS and the value names the state, so the pair reads `mode=edit` and `mode=view` rather than the tautological `view=view`. Absent means View — the default and the common case — so an ordinary link carries nothing and the parameter appears once somebody has chosen. The DEVICE deliberately stays in React state. It is a way of looking rather than a thing being looked at, and nobody has wanted to send one. Worth keeping that distinction deliberate rather than letting both drift into whichever place was convenient. COLOURS AND TYPEFACES ARE TABS. They were two stacked cards taking as much height as both together, and every pixel of it came off the preview — which is the thing being judged. One at a time costs a click and gives the page back most of the panel. The 55% cap on the controls is gone with them: one tab is short enough not to need capping, which is the other thing this bought. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { readableError } from '../errors';
|
||||
import { useFlash } from '../useFlash';
|
||||
@@ -24,7 +25,8 @@ import { SitePreview, useDevPort } from '../SitePreview';
|
||||
* content. A panel offering to rearrange them offers a power that should not exist, and every use of it
|
||||
* would be a decision made in the wrong place.
|
||||
*
|
||||
* What is left is the part that IS a content decision: the colours and the typefaces.
|
||||
* What is left is the part that IS a content decision: the colours and the typefaces, as tabs — one at
|
||||
* a time, so the preview keeps the height.
|
||||
*
|
||||
* ── The preview is the point ──
|
||||
*
|
||||
@@ -221,19 +223,28 @@ export const LayoutPanel = () => {
|
||||
<SitePreview port={devPort} path="layout" theme={themeProperties(draft)} onDocument={onDocument} />
|
||||
|
||||
{/*
|
||||
The controls, and only in Edit.
|
||||
The controls as TABS, and only in Edit.
|
||||
|
||||
`shrink-0` so they never give up height to the preview, `max-h-[55%]` so they can never take
|
||||
the whole panel either — on a short window the preview would otherwise be squeezed to nothing,
|
||||
which is the failure this whole change is about. Past that they scroll on their own rather than
|
||||
scrolling the preview off the top.
|
||||
They were two stacked cards, which took as much height as both of them together — and every
|
||||
pixel of it came off the preview, which is the thing being judged. One at a time costs a click
|
||||
and gives the page back most of the panel.
|
||||
|
||||
`shrink-0` so they never take height from the preview, and no `max-h` any more: one tab is short
|
||||
enough that it does not need capping, which is the other thing this bought.
|
||||
*/}
|
||||
{mode === 'edit' && (
|
||||
<div className="flex max-h-[55%] shrink-0 flex-col gap-4 overflow-auto">
|
||||
{/* ── Colours ──────────────────────────────────────────────────────────────────────────── */}
|
||||
<section className="flex flex-col gap-3 rounded-lg border border-border p-4">
|
||||
<h3 className="text-sm font-medium">Colours</h3>
|
||||
<Tabs defaultValue="colours" className="shrink-0 gap-2">
|
||||
<TabsList className="h-7">
|
||||
<TabsTrigger value="colours" className="text-xs">
|
||||
Colours
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="typefaces" className="text-xs">
|
||||
Typefaces
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="colours" className="rounded-lg border border-border p-4">
|
||||
<>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{COLOURS.map(({ key, label, fallback }) => (
|
||||
<div key={key} className="flex items-center gap-2">
|
||||
@@ -262,12 +273,11 @@ export const LayoutPanel = () => {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Typefaces ────────────────────────────────────────────────────────────────────────── */}
|
||||
<section className="flex flex-col gap-3 rounded-lg border border-border p-4">
|
||||
<h3 className="text-sm font-medium">Typefaces</h3>
|
||||
</>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="typefaces" className="rounded-lg border border-border p-4">
|
||||
<>
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{ROLES.map(({ key, label, hint }) => (
|
||||
<div key={key} className="flex flex-col gap-1">
|
||||
@@ -292,9 +302,11 @@ export const LayoutPanel = () => {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user