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 = {
|
||||
basePath?: 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. */
|
||||
urlPath?: boolean;
|
||||
/**
|
||||
@@ -20,7 +22,7 @@ type FileBrowserAppProps = {
|
||||
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 { handleNavigate } = fileBrowserManager;
|
||||
|
||||
@@ -31,6 +33,7 @@ export const FileBrowserApp = ({ basePath = '/', rootOverride, urlPath, panelId
|
||||
path={fileBrowserManager.currentPath}
|
||||
onNavigate={handleNavigate}
|
||||
basePath={basePath}
|
||||
rootLabel={rootLabel}
|
||||
hrefForPath={fileBrowserManager.hrefForPath}
|
||||
/>
|
||||
<UploadProgress fileBrowserManager={fileBrowserManager} />
|
||||
|
||||
+10
-2
@@ -5,6 +5,14 @@ type BreadcrumbProps = {
|
||||
path: string;
|
||||
onNavigate: (path: string) => void;
|
||||
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
|
||||
* 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;
|
||||
};
|
||||
|
||||
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 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">
|
||||
<Crumb to={basePath} className="flex items-center gap-1 text-duck-teal cursor-pointer font-medium">
|
||||
<Home className="h-4 w-4" />
|
||||
<span>{basePath === '/' ? 'home' : basePath.split('/').pop()}</span>
|
||||
<span>{rootLabel ?? (basePath === '/' ? 'home' : basePath.split('/').pop())}</span>
|
||||
</Crumb>
|
||||
|
||||
{segments.map((segment, i) => {
|
||||
|
||||
Reference in New Issue
Block a user