/marketplace was a list of every plugin on the left and a preview on the right. that is a fine control panel and a poor shop: twenty-one rows sorted by nothing anybody cares about, where "something for my calendar" means reading all of them. now: tags down the left with counts, cards in a grid on the right, and clicking a card takes over the panel with a back link. three things about the shape. BOTH the filter and the selection are in the URL — ?tag= and ?selected=. a filter in component state is lost on Back, so filtering, opening a plugin and pressing Back would drop you in an unfiltered grid having lost your place. browser Back works for free for the same reason. selecting a tag also CLEARS the selection, because a detail for a plugin outside the new filter is a page the grid you are now looking at cannot return to. the detail REPLACES the grid rather than sitting beside it. a grid needs the width and a detail beside one gets half of it; neither reads well. the back link drops ?selected= and keeps ?tag=, which is the entire point of putting the filter there. the panel KEYS are unchanged though both components were replaced. a stored layout names them, and renaming would drop everyone back to the default arrangement for nothing — the key identifies a slot, not an implementation. two things found on the way. PluginItem and AvailablePlugin had no tags, so the api now carries them on both branches — from the manifest for a plugin that is here, from the catalogue for one that is not, same field either way. and the screen used useDashboardState, which persists the whole tree: the panels this ships would never have reached anyone who had opened it before. useAuthoredLayout takes the structure from source and persists only sizes, which is what an authored screen wants. 21/22 -> 22/78 as well: the left panel holds seven tags now, not twenty-one rows, and the width is worth more to the grid. verified: bundle contains the new panels, api returns tags for all 21 with none missing the field. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
17 lines
846 B
TypeScript
17 lines
846 B
TypeScript
import type { LayoutNode } from 'officerdev';
|
|
|
|
// List left, detail right — a master list with a live preview, which is why the selection is `?selected=`
|
|
// rather than a `/plugins/:appName` route: linking rows to the detail route would make it the whole page
|
|
// and destroy the side-by-side. See docs/navigation-audit.md.
|
|
export const defaultLayout: LayoutNode = {
|
|
type: 'group',
|
|
id: 'plugins-root',
|
|
direction: 'horizontal',
|
|
children: [
|
|
// 22/78, not 32/68. The left panel was a list of every plugin and needed the room; it is a list of
|
|
// seven tags now, and the grid on the right is what benefits from the width — one more card per row.
|
|
{ node: { type: 'panel', id: 'plugins-list', appType: 'plugins-list' }, size: 22 },
|
|
{ node: { type: 'panel', id: 'plugin-detail', appType: 'plugin-detail' }, size: 78 },
|
|
],
|
|
};
|