From 7a12e6c09aca04392c93cdb1d0d46537475b24ed Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Feb 2026 21:09:22 +0000 Subject: [PATCH] . --- frontend/src/components/ui/Header.tsx | 28 ++++++++------------------- frontend/src/hooks/useMapData.ts | 3 ++- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/ui/Header.tsx b/frontend/src/components/ui/Header.tsx index e55ec2e..7c666f7 100644 --- a/frontend/src/components/ui/Header.tsx +++ b/frontend/src/components/ui/Header.tsx @@ -1,6 +1,7 @@ import { useState, useCallback, useEffect } from 'react'; import type { AuthUser } from '../../hooks/useAuth'; import { shortenUrl } from '../../lib/api'; +import { copyToClipboard } from '../../lib/clipboard'; import { DownloadIcon } from './icons/DownloadIcon'; import { BookmarkIcon } from './icons/BookmarkIcon'; import { LogoIcon } from './icons/LogoIcon'; @@ -63,42 +64,29 @@ export default function Header({ if (!isMobile) setMenuOpen(false); }, [isMobile]); - const copyToClipboard = useCallback((text: string) => { - const onSuccess = () => { + const doCopy = useCallback((text: string) => { + copyToClipboard(text, () => { setCopied(true); setTimeout(() => setCopied(false), 2000); - }; - if (navigator.clipboard?.writeText) { - navigator.clipboard.writeText(text).then(onSuccess); - } else { - const ta = document.createElement('textarea'); - ta.value = text; - ta.style.position = 'fixed'; - ta.style.opacity = '0'; - document.body.appendChild(ta); - ta.select(); - document.execCommand('copy'); - document.body.removeChild(ta); - onSuccess(); - } + }); }, []); const handleShare = useCallback(async () => { const params = window.location.search.replace(/^\?/, ''); if (!params) { - copyToClipboard(window.location.href); + doCopy(window.location.href); return; } setSharing(true); try { const shortUrl = await shortenUrl(params); - copyToClipboard(shortUrl); + doCopy(shortUrl); } catch { - copyToClipboard(window.location.href); + doCopy(window.location.href); } finally { setSharing(false); } - }, [copyToClipboard]); + }, [doCopy]); const tabClass = (page: Page) => `px-3 py-1.5 rounded text-sm font-medium transition-colors ${ diff --git a/frontend/src/hooks/useMapData.ts b/frontend/src/hooks/useMapData.ts index 27f2b50..80e0fb6 100644 --- a/frontend/src/hooks/useMapData.ts +++ b/frontend/src/hooks/useMapData.ts @@ -76,12 +76,13 @@ export function useMapData({ ); // Build the travel param string from entries with destinations - // Format: mode:slug|mode:slug or mode:slug:min:max|mode:slug + // Format: mode:slug|mode:slug:best or mode:slug:min:max|mode:slug:best:min:max const travelParam = useMemo((): string => { const segments: string[] = []; for (const entry of travelTimeEntries) { if (!entry.slug) continue; let seg = `${entry.mode}:${entry.slug}`; + if (entry.useBest) seg += ':best'; if (entry.timeRange) { seg += `:${entry.timeRange[0]}:${entry.timeRange[1]}`; }