the embedded file browser can name its own root crumb
`rootLabel` on FileBrowserApp, through to the breadcrumb. it defaults to the base folder's own name, which is right for /files and wrong for an embedder: a panel scoped to `<root>/media/originals` is called Media, and "originals" is an implementation detail of how that plugin lays out a directory. the person looking at it never chose that word and has no reason to recognise it. one prop rather than the plugin drawing its own breadcrumb — which is the same trade as embedding the browser at all: upload, delete, thumbnails and the context menu come from one maintained place, and this is the small thing that was missing to make that honest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -11,6 +11,8 @@ import { useFileBrowserApp } from './useFileBrowserApp';
|
|||||||
type FileBrowserAppProps = {
|
type FileBrowserAppProps = {
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
rootOverride?: string;
|
rootOverride?: string;
|
||||||
|
/** What the root crumb is called. Defaults to the base folder's own name. */
|
||||||
|
rootLabel?: string;
|
||||||
/** Put the current folder in `?path=`. Opt-in — only the /files screen is guaranteed one browser. */
|
/** Put the current folder in `?path=`. Opt-in — only the /files screen is guaranteed one browser. */
|
||||||
urlPath?: boolean;
|
urlPath?: boolean;
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +22,7 @@ type FileBrowserAppProps = {
|
|||||||
panelId?: string;
|
panelId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FileBrowserApp = ({ basePath = '/', rootOverride, urlPath, panelId }: FileBrowserAppProps) => {
|
export const FileBrowserApp = ({ basePath = '/', rootOverride, rootLabel, urlPath, panelId }: FileBrowserAppProps) => {
|
||||||
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId);
|
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId);
|
||||||
const { handleNavigate } = fileBrowserManager;
|
const { handleNavigate } = fileBrowserManager;
|
||||||
|
|
||||||
@@ -31,6 +33,7 @@ export const FileBrowserApp = ({ basePath = '/', rootOverride, urlPath, panelId
|
|||||||
path={fileBrowserManager.currentPath}
|
path={fileBrowserManager.currentPath}
|
||||||
onNavigate={handleNavigate}
|
onNavigate={handleNavigate}
|
||||||
basePath={basePath}
|
basePath={basePath}
|
||||||
|
rootLabel={rootLabel}
|
||||||
hrefForPath={fileBrowserManager.hrefForPath}
|
hrefForPath={fileBrowserManager.hrefForPath}
|
||||||
/>
|
/>
|
||||||
<UploadProgress fileBrowserManager={fileBrowserManager} />
|
<UploadProgress fileBrowserManager={fileBrowserManager} />
|
||||||
|
|||||||
+10
-2
@@ -5,6 +5,14 @@ type BreadcrumbProps = {
|
|||||||
path: string;
|
path: string;
|
||||||
onNavigate: (path: string) => void;
|
onNavigate: (path: string) => void;
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
|
/**
|
||||||
|
* What to call the root crumb.
|
||||||
|
*
|
||||||
|
* Defaults to the base folder's own name, which is right for `/files` and wrong for an embedder: a
|
||||||
|
* panel scoped to `<root>/media/originals` is called Media, and "originals" is an implementation
|
||||||
|
* detail of how that plugin lays out a directory. The person looking at it never chose that word.
|
||||||
|
*/
|
||||||
|
rootLabel?: string;
|
||||||
/**
|
/**
|
||||||
* Where a folder lives, when this browser owns the address bar. Given, the crumbs are real links and
|
* Where a folder lives, when this browser owns the address bar. Given, the crumbs are real links and
|
||||||
* cmd-click opens the folder in a new tab; absent (a dashboard panel, the widget) they stay buttons,
|
* cmd-click opens the folder in a new tab; absent (a dashboard panel, the widget) they stay buttons,
|
||||||
@@ -15,7 +23,7 @@ type BreadcrumbProps = {
|
|||||||
hrefForPath?: ((path: string) => { pathname: string; search: string }) | null;
|
hrefForPath?: ((path: string) => { pathname: string; search: string }) | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Breadcrumb = ({ path, onNavigate, basePath = '/', hrefForPath }: BreadcrumbProps) => {
|
export const Breadcrumb = ({ path, onNavigate, basePath = '/', hrefForPath, rootLabel }: BreadcrumbProps) => {
|
||||||
const relativePath = basePath !== '/' && path.startsWith(basePath) ? path.slice(basePath.length) : path;
|
const relativePath = basePath !== '/' && path.startsWith(basePath) ? path.slice(basePath.length) : path;
|
||||||
const segments = relativePath.split('/').filter(Boolean);
|
const segments = relativePath.split('/').filter(Boolean);
|
||||||
|
|
||||||
@@ -35,7 +43,7 @@ export const Breadcrumb = ({ path, onNavigate, basePath = '/', hrefForPath }: Br
|
|||||||
<nav className="flex items-center gap-1 text-sm flex-wrap">
|
<nav className="flex items-center gap-1 text-sm flex-wrap">
|
||||||
<Crumb to={basePath} className="flex items-center gap-1 text-duck-teal cursor-pointer font-medium">
|
<Crumb to={basePath} className="flex items-center gap-1 text-duck-teal cursor-pointer font-medium">
|
||||||
<Home className="h-4 w-4" />
|
<Home className="h-4 w-4" />
|
||||||
<span>{basePath === '/' ? 'home' : basePath.split('/').pop()}</span>
|
<span>{rootLabel ?? (basePath === '/' ? 'home' : basePath.split('/').pop())}</span>
|
||||||
</Crumb>
|
</Crumb>
|
||||||
|
|
||||||
{segments.map((segment, i) => {
|
{segments.map((segment, i) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user