diff --git a/manifest.ts b/manifest.ts index e8fb4fa..152b776 100644 --- a/manifest.ts +++ b/manifest.ts @@ -35,7 +35,7 @@ import type { PluginManifest } from '@@/plugins/manifest'; */ export const manifest: PluginManifest = { publisher: 'officerdev', - version: '2026.08.29.22', + version: '2026.08.29.23', platform: '>=1.0.0', label: 'Fofos', diff --git a/web/DetailHeader.tsx b/web/DetailHeader.tsx new file mode 100644 index 0000000..176bb80 --- /dev/null +++ b/web/DetailHeader.tsx @@ -0,0 +1,33 @@ +import { useSearchParams } from 'react-router'; +import { DEFAULT_SECTION, isSectionKey, sectionFor } from './sections'; + +/** + * The detail panel's chrome header — the section's own name, not the word "Detail". + * + * ── Why this replaces a row inside the panel ── + * + * The panel used to draw its own header strip with the section label and its hint, UNDER the workspace's + * chrome header, which said "Detail". Two bars stacked, one of them saying nothing: the top of the panel + * was three rows of furniture before any content. + * + * A panel meta may supply its own `header`, which is the mechanism for exactly this — several plugins + * already do it. So the section's name goes where a panel's name goes, and the row inside is gone. + * + * ── The hint went with it ── + * + * "Photos and video the site is built from" is useful in the NAV, where somebody is choosing between + * ten sections. Repeated above the thing they chose, it is a caption for a decision already made. + */ +export const DetailHeader = () => { + const [params] = useSearchParams(); + const raw = params.get('section'); + const section = sectionFor(isSectionKey(raw) ? raw : DEFAULT_SECTION); + const Icon = section.icon; + + return ( + <> + + {section.label} + + ); +}; diff --git a/web/DetailPanel.tsx b/web/DetailPanel.tsx index 5219b27..3831a80 100644 --- a/web/DetailPanel.tsx +++ b/web/DetailPanel.tsx @@ -71,11 +71,6 @@ export const DetailPanel = () => { return (
-
-

{current.label}

- {current.hint} -
-
{Panel ? : }
); diff --git a/web/MediaPanel.tsx b/web/MediaPanel.tsx index cff6161..a8e1aec 100644 --- a/web/MediaPanel.tsx +++ b/web/MediaPanel.tsx @@ -91,10 +91,14 @@ export const MediaPanel = () => { `rootLabel` so the breadcrumb reads "Media" rather than "originals": the folder's name on disk is an implementation detail of how this plugin lays out a root, and the section is called Media. - `panelId` so the folder somebody is in survives a reload — without it every refresh drops them - back at the top, however deep they were. + `urlPath` puts the current folder in `?path=`, so a reload lands where you were and a link can be + sent to somebody. it is opt-in in the platform because a screen with TWO browsers would have them + fighting over one parameter — this screen has one, so it is safe here and not in general. + + `panelId` stays as well: it remembers the folder for a panel that is re-opened rather than reloaded, + which the URL cannot cover. */ - return ; + return ; }; const Notice = ({ icon: Icon, children }: { icon: typeof FolderOpen; children: React.ReactNode }) => ( diff --git a/web/panels.ts b/web/panels.ts index 4a5a23b..7c4f255 100644 --- a/web/panels.ts +++ b/web/panels.ts @@ -2,6 +2,7 @@ import type { AppRegistryMeta } from 'officerdev'; import { List, PanelRight } from 'lucide-react'; import { NavPanel } from './NavPanel'; import { DetailPanel } from './DetailPanel'; +import { DetailHeader } from './DetailHeader'; /** * Two panels: a nav, and whatever it selects. @@ -26,6 +27,9 @@ export const appRegistryMetas: AppRegistryMeta[] = [ name: 'Detail', icon: PanelRight, component: DetailPanel, + // The chrome header says which SECTION is open rather than the word "Detail" — see DetailHeader for + // why that replaced a second header row inside the panel. + header: DetailHeader, availableOnPanel: false, }, ];