From 26f614b1c8bb8fb78ecbc8ac5ffbebcd557da610 Mon Sep 17 00:00:00 2001 From: Cedric van Putten Date: Sun, 25 Aug 2024 22:37:07 +0200 Subject: [PATCH] feature(webui): show path copy confirmation through tooltip --- webui/src/components/BreadcrumbLinks.tsx | 49 +++++++++++++++++++----- webui/src/ui/Tooltip.tsx | 2 +- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/webui/src/components/BreadcrumbLinks.tsx b/webui/src/components/BreadcrumbLinks.tsx index 061a4b2..781af74 100644 --- a/webui/src/components/BreadcrumbLinks.tsx +++ b/webui/src/components/BreadcrumbLinks.tsx @@ -1,5 +1,7 @@ import { Link } from 'expo-router'; -import { ComponentProps, Fragment, PropsWithChildren, useCallback, useMemo } from 'react'; +// @ts-expect-error +import CheckIcon from 'lucide-react/dist/esm/icons/check'; +import { ComponentProps, Fragment, PropsWithChildren, useCallback, useMemo, useState } from 'react'; import { Breadcrumb, @@ -10,6 +12,7 @@ import { 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 = { @@ -67,26 +70,50 @@ type BreadcrumbLinkMenuProps = PropsWithChildren<{ }>; 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); - }, [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}`); - }, [props.link.filePath, props.bundle.sharedRoot]); + showCopyTooltip(`Absolute ${props.link.type} path copied`); + }, [props.link.type, props.link.filePath, props.bundle.sharedRoot, showCopyTooltip]); return ( - - {props.children} - - Copy relative path - Copy absolute path - - + + + + + {props.children} + + + {tooltipContent} + + + + + Copy relative {props.link.type} path + + + Copy absolute {props.link.type} path + + + + + ); } type BreadcrumbLinkItem = { + type: 'folder' | 'file'; key: string; label: string; filePath: string; @@ -98,12 +125,14 @@ function getBreadcrumbLinks(props: BreadcrumbLinksProps): BreadcrumbLinkItem[] { const isLastSegment = index === breadcrumbs.length - 1; const breadcrumb: BreadcrumbLinkItem = { label, + type: 'file', key: `${index}-${label}`, filePath: breadcrumbs.slice(0, index + 1).join('/'), }; // 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/ui/Tooltip.tsx b/webui/src/ui/Tooltip.tsx index 9daff07..6d19877 100644 --- a/webui/src/ui/Tooltip.tsx +++ b/webui/src/ui/Tooltip.tsx @@ -18,7 +18,7 @@ export const TooltipContent = forwardRef< ref={ref} sideOffset={sideOffset} className={cx( - 'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground', + 'z-50 px-3 py-2 overflow-hidden rounded-md bg-default text-secondary border border-secondary max-w-80 shadow-md leading-6 text-xs', 'animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95', 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', className