the preview and the editor are a workspace inside a panel
`1 | [1 | 1]`, and the brackets are a real container this time. Nesting them as a GROUP was the first attempt and looked identical — a horizontal group inside a horizontal group renders three columns, because that is what it is. All it bought was which divider moved what, which is invisible until you drag one. So the pair is a panel whose component hosts its own WorkspaceView, the way DashboardPreview does. It has its own chrome, its own divider and its own persisted sizes, and the root layout has two children rather than three: the shape on screen is now the shape in the file. `useAuthoredLayout` rather than `useDashboardState`, and its own key beside the root's. The structure is the author's and comes from source every render; only sizes are the user's. Sharing one key would have the inner and outer trees persisting over each other's sizes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import type { LayoutNode } from 'officerdev';
|
||||
import { WorkspaceView } from 'officerdev';
|
||||
import { useAuthoredLayout } from 'state/useAuthoredLayout';
|
||||
|
||||
/**
|
||||
* The preview and its editor, as a workspace inside one panel.
|
||||
*
|
||||
* ── Why not two more panels in the root layout ──
|
||||
*
|
||||
* They were, and nesting them as a GROUP looked identical: a horizontal group inside a horizontal group
|
||||
* renders three columns, because that is what it is. All the nesting bought was which divider moved
|
||||
* what, which is invisible until you drag one.
|
||||
*
|
||||
* A workspace inside a panel is a real container. The pair sits in one panel with its own chrome, its
|
||||
* own dividers and its own persisted sizes, and the outer layout has two children rather than three —
|
||||
* so the shape on screen is the shape in the file.
|
||||
*
|
||||
* ── Its structure is the author's; only the sizes are yours ──
|
||||
*
|
||||
* `useAuthoredLayout`, not `useDashboardState`. The latter persists the whole tree, which is right for
|
||||
* a dashboard somebody arranged and wrong here: the structure would freeze at whatever it was the first
|
||||
* time this screen was opened, and a change shipped later would never reach anybody who had already
|
||||
* looked. Sizes and zoom persist; the shape comes from this file every render.
|
||||
*
|
||||
* ── Its own key ──
|
||||
*
|
||||
* `screens/plugin/fofos-admin/work`, beside the root's `screens/plugin/fofos-admin`. Two layouts, two
|
||||
* keys: sharing one would have the inner and outer trees persisting over each other's sizes.
|
||||
*/
|
||||
const workLayout: LayoutNode = {
|
||||
type: 'group',
|
||||
id: 'fofos-admin-work',
|
||||
direction: 'horizontal',
|
||||
children: [
|
||||
{ node: { type: 'panel', id: 'fofos-admin-detail', appType: 'fofos-admin-detail' }, size: 70 },
|
||||
{ node: { type: 'panel', id: 'fofos-admin-editor', appType: 'fofos-admin-editor' }, size: 30 },
|
||||
],
|
||||
};
|
||||
|
||||
const ALLOWED = ['fofos-admin-detail', 'fofos-admin-editor'];
|
||||
|
||||
export const WorkPanel = () => {
|
||||
const workspace = useAuthoredLayout('screens/plugin/fofos-admin/work', workLayout);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
{/* `locked`, like the screen around it: this arrangement is the plugin author's design, not a
|
||||
workspace to rearrange. `allowed` pins it to these two, so a persisted layout naming anything
|
||||
else falls back rather than rendering some other plugin's panel in here. */}
|
||||
<WorkspaceView workspace={workspace} locked appTypes={{ allowed: ALLOWED, fallback: ALLOWED[0]! }} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
+8
-20
@@ -3,16 +3,15 @@ import type { LayoutNode } from 'officerdev';
|
||||
/**
|
||||
* A nav down the left, and beside it the pair that does the work.
|
||||
*
|
||||
* ── Why the preview and the editor are a GROUP ──
|
||||
* ── Two children, not three ──
|
||||
*
|
||||
* They were three siblings — nav, preview, editor — and the nesting is the whole difference. With three
|
||||
* in a row every divider is between two of them, so widening the editor took from the preview and
|
||||
* dragging the nav re-proportioned all three: three panels that can only be sized against each other.
|
||||
* The preview and its editor are a WORKSPACE INSIDE A PANEL — see WorkPanel — rather than two more
|
||||
* children here. Nesting them as a group was tried first and looked identical: a horizontal group in a
|
||||
* horizontal group renders three columns, because that is what it is, and all the nesting bought was
|
||||
* which divider moved what.
|
||||
*
|
||||
* Nested, the outer divider moves the nav against THE WORK, and the inner one splits the work between
|
||||
* looking and changing. Those are the two questions somebody actually has — "give me more room to
|
||||
* work" and "I need more of the controls right now" — and each is now one drag that leaves the other
|
||||
* answer alone.
|
||||
* A panel is a real container. The pair has its own chrome, its own dividers and its own persisted
|
||||
* sizes, and this file has two children — so the shape on screen is the shape in the file.
|
||||
*
|
||||
* ── The nav is the narrow one ──
|
||||
*
|
||||
@@ -35,17 +34,6 @@ export const defaultLayout: LayoutNode = {
|
||||
direction: 'horizontal',
|
||||
children: [
|
||||
{ node: { type: 'panel', id: 'fofos-admin-nav', appType: 'fofos-admin-nav' }, size: 22 },
|
||||
{
|
||||
node: {
|
||||
type: 'group',
|
||||
id: 'fofos-admin-work',
|
||||
direction: 'horizontal',
|
||||
children: [
|
||||
{ node: { type: 'panel', id: 'fofos-admin-detail', appType: 'fofos-admin-detail' }, size: 70 },
|
||||
{ node: { type: 'panel', id: 'fofos-admin-editor', appType: 'fofos-admin-editor' }, size: 30 },
|
||||
],
|
||||
},
|
||||
size: 78,
|
||||
},
|
||||
{ node: { type: 'panel', id: 'fofos-admin-work', appType: 'fofos-admin-work' }, size: 78 },
|
||||
],
|
||||
};
|
||||
|
||||
+16
-1
@@ -1,9 +1,10 @@
|
||||
import type { AppRegistryMeta } from 'officerdev';
|
||||
import { List, PanelRight, SlidersHorizontal } from 'lucide-react';
|
||||
import { Columns2, List, PanelRight, SlidersHorizontal } from 'lucide-react';
|
||||
import { NavPanel } from './NavPanel';
|
||||
import { DetailPanel } from './DetailPanel';
|
||||
import { DetailHeader } from './DetailHeader';
|
||||
import { EditorPanel } from './EditorPanel';
|
||||
import { WorkPanel } from './WorkPanel';
|
||||
|
||||
/**
|
||||
* Three panels: a nav, whatever it selects, and where an editor opens.
|
||||
@@ -33,6 +34,20 @@ export const appRegistryMetas: AppRegistryMeta[] = [
|
||||
header: DetailHeader,
|
||||
availableOnPanel: false,
|
||||
},
|
||||
{
|
||||
/*
|
||||
The container the root layout points at: a workspace holding the preview and its editor.
|
||||
|
||||
Registered like any other panel because the outer WorkspaceView resolves by appType, and listed in
|
||||
the root's allow-list. The two it contains stay registered too — the INNER workspace resolves them
|
||||
the same way.
|
||||
*/
|
||||
key: 'fofos-admin-work',
|
||||
name: 'Work',
|
||||
icon: Columns2,
|
||||
component: WorkPanel,
|
||||
availableOnPanel: false,
|
||||
},
|
||||
{
|
||||
key: 'fofos-admin-editor',
|
||||
name: 'Editor',
|
||||
|
||||
Reference in New Issue
Block a user