diff --git a/webui/src/components/BreadcrumbLinks.tsx b/webui/src/components/BreadcrumbLinks.tsx
index 781af74..4a687f8 100644
--- a/webui/src/components/BreadcrumbLinks.tsx
+++ b/webui/src/components/BreadcrumbLinks.tsx
@@ -1,8 +1,7 @@
import { Link } from 'expo-router';
-// @ts-expect-error
-import CheckIcon from 'lucide-react/dist/esm/icons/check';
-import { ComponentProps, Fragment, PropsWithChildren, useCallback, useMemo, useState } from 'react';
+import { type ComponentProps, Fragment, useMemo } from 'react';
+import { FilePathMenu } from '~/components/FilePathMenu';
import {
Breadcrumb,
BreadcrumbItem,
@@ -11,8 +10,6 @@ import {
BreadcrumbPage,
BreadcrumbSeparator,
} from '~/ui/Breadcrumb';
-import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '~/ui/Menu';
-import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '~/ui/Tooltip';
import { type PartialAtlasBundle } from '~core/data/types';
type BreadcrumbLinksProps = {
@@ -41,11 +38,11 @@ export function BreadcrumbLinks(props: BreadcrumbLinksProps) {
{!link.href ? (
-
+
{link.label}
-
+
) : (
-
+
-
+
)}
@@ -64,56 +61,7 @@ export function BreadcrumbLinks(props: BreadcrumbLinksProps) {
);
}
-type BreadcrumbLinkMenuProps = PropsWithChildren<{
- bundle: PartialAtlasBundle;
- link: BreadcrumbLinkItem;
-}>;
-
-function BreadcrumbLinkMenu(props: BreadcrumbLinkMenuProps) {
- const [tooltipContent, setTooltipContent] = useState(null);
-
- const showCopyTooltip = useCallback((content: string) => {
- setTooltipContent(content);
- setTimeout(() => setTooltipContent(null), 2000);
- }, []);
-
- const onCopyRelativePath = useCallback(() => {
- navigator.clipboard.writeText(props.link.filePath);
- showCopyTooltip(`Relative ${props.link.type} path copied`);
- }, [props.link.type, props.link.filePath, showCopyTooltip]);
-
- const onCopyAbsolutePath = useCallback(() => {
- navigator.clipboard.writeText(`${props.bundle.sharedRoot}/${props.link.filePath}`);
- showCopyTooltip(`Absolute ${props.link.type} path copied`);
- }, [props.link.type, props.link.filePath, props.bundle.sharedRoot, showCopyTooltip]);
-
- return (
-
-
-
-
- {props.children}
-
-
- {tooltipContent}
-
-
-
-
- Copy relative {props.link.type} path
-
-
- Copy absolute {props.link.type} path
-
-
-
-
-
- );
-}
-
-type BreadcrumbLinkItem = {
- type: 'folder' | 'file';
+type BreadcrumbLinkItem = ComponentProps & {
key: string;
label: string;
filePath: string;
@@ -123,16 +71,23 @@ type BreadcrumbLinkItem = {
function getBreadcrumbLinks(props: BreadcrumbLinksProps): BreadcrumbLinkItem[] {
return props.path.split('/').map((label, index, breadcrumbs) => {
const isLastSegment = index === breadcrumbs.length - 1;
+ const filePath = breadcrumbs.slice(0, index + 1).join('/');
const breadcrumb: BreadcrumbLinkItem = {
- label,
- type: 'file',
key: `${index}-${label}`,
- filePath: breadcrumbs.slice(0, index + 1).join('/'),
+ label,
+ filePath,
+ relative: {
+ path: filePath,
+ label: isLastSegment ? 'Copy relative file path' : 'Copy relative folder path',
+ },
+ absolute: {
+ path: `${props.bundle.sharedRoot}/${filePath}`,
+ label: isLastSegment ? 'Copy absolute file path' : 'Copy absolute folder path',
+ },
};
// NOTE(cedric): a bit of a workaround to avoid linking to the current page, might need to change this
if (!isLastSegment || !label.includes('.')) {
- breadcrumb.type = 'folder';
breadcrumb.href = {
pathname: '/(atlas)/[bundle]/folders/[path]',
params: { bundle: props.bundle.id, path: breadcrumb.filePath },
diff --git a/webui/src/components/FilePathMenu.tsx b/webui/src/components/FilePathMenu.tsx
new file mode 100644
index 0000000..58a8689
--- /dev/null
+++ b/webui/src/components/FilePathMenu.tsx
@@ -0,0 +1,60 @@
+// @ts-expect-error
+import CheckIcon from 'lucide-react/dist/esm/icons/check';
+import { PropsWithChildren, useState, useCallback } from 'react';
+
+import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '~/ui/Menu';
+import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '~/ui/Tooltip';
+
+type FilePath = {
+ path: string;
+ label?: string;
+ copy?: string;
+};
+
+type FilePathMenuProps = PropsWithChildren<{
+ absolute: FilePath;
+ relative: FilePath;
+}>;
+
+export function FilePathMenu(props: FilePathMenuProps) {
+ const [tooltipContent, setTooltipContent] = useState(null);
+
+ const showCopyTooltip = useCallback((content: string) => {
+ setTooltipContent(content);
+ setTimeout(() => setTooltipContent(null), 2000);
+ }, []);
+
+ const onCopyRelativePath = useCallback(() => {
+ navigator.clipboard.writeText(props.relative.path);
+ showCopyTooltip(props.relative.copy ?? 'Relative path copied');
+ }, [props.relative.path, props.relative.copy, showCopyTooltip]);
+
+ const onCopyAbsolutePath = useCallback(() => {
+ navigator.clipboard.writeText(props.absolute.path);
+ showCopyTooltip(props.absolute.copy ?? 'Absolute path copied');
+ }, [props.absolute.path, props.absolute.copy, showCopyTooltip]);
+
+ return (
+
+
+
+
+ {props.children}
+
+
+ {tooltipContent}
+
+
+
+
+ {props.relative.label ?? 'Copy relative path'}
+
+
+ {props.absolute.label ?? 'Copy absolute path'}
+
+
+
+
+
+ );
+}