diff --git a/web/src/routes/sessions/file.tsx b/web/src/routes/sessions/file.tsx index 01b68bec..054f0fd5 100644 --- a/web/src/routes/sessions/file.tsx +++ b/web/src/routes/sessions/file.tsx @@ -5,6 +5,7 @@ import type { GitCommandResponse } from '@/types/api' import { FileIcon } from '@/components/FileIcon' import { useAppContext } from '@/lib/app-context' import { useAppGoBack } from '@/hooks/useAppGoBack' +import { usePlatform } from '@/hooks/usePlatform' import { queryKeys } from '@/lib/query-keys' import { langAlias, useShikiHighlighter } from '@/lib/shiki' @@ -119,8 +120,55 @@ function extractCommandError(result: GitCommandResponse | undefined): string | n return result.error ?? result.stderr ?? 'Failed to load diff' } +function safeCopyToClipboard(text: string): Promise { + if (navigator.clipboard?.writeText) { + return navigator.clipboard.writeText(text) + } + return Promise.reject(new Error('Clipboard API not available')) +} + +function CopyIcon(props: { className?: string }) { + return ( + + + + + ) +} + +function CheckIcon(props: { className?: string }) { + return ( + + + + ) +} + export default function FilePage() { const { api } = useAppContext() + const { haptic } = usePlatform() const goBack = useAppGoBack() const { sessionId } = useParams({ from: '/sessions/$sessionId/file' }) const search = useSearch({ from: '/sessions/$sessionId/file' }) @@ -170,6 +218,18 @@ export default function FilePage() { const highlighted = useShikiHighlighter(decodedContent, language) const [displayMode, setDisplayMode] = useState<'diff' | 'file'>('diff') + const [copied, setCopied] = useState(false) + + const handleCopyPath = async () => { + try { + await safeCopyToClipboard(filePath) + haptic.notification('success') + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } catch { + haptic.notification('error') + } + } useEffect(() => { if (diffSuccess && !diffContent) { @@ -209,7 +269,15 @@ export default function FilePage() {
- {filePath} + {filePath} +