From c9e14f3bce0191a500ba8bb091cf0709f27972f4 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 28 Jan 2026 23:32:51 -0800 Subject: [PATCH] Restructure share routes to fix client-side navigation - Change from [...shareId] catch-all to [slug]/[[...path]] structure - Layout with ShareProvider now persists across sub-route navigation - Add slug to ShareData context (separate from shareId UUID) - Links now use slug instead of UUID for proper routing - Remove unused ShareFooter and ShareHeader files Co-Authored-By: Claude Opus 4.5 --- src/app/share/ShareProvider.tsx | 11 ++++--- src/app/share/[...shareId]/ShareFooter.tsx | 23 ------------- src/app/share/[...shareId]/ShareHeader.tsx | 33 ------------------- src/app/share/[...shareId]/page.tsx | 13 -------- .../[[...path]]}/ShareNav.tsx | 4 +-- .../[[...path]]}/SharePage.tsx | 0 src/app/share/[slug]/[[...path]]/page.tsx | 5 +++ src/app/share/[slug]/layout.tsx | 13 ++++++++ 8 files changed, 26 insertions(+), 76 deletions(-) delete mode 100644 src/app/share/[...shareId]/ShareFooter.tsx delete mode 100644 src/app/share/[...shareId]/ShareHeader.tsx delete mode 100644 src/app/share/[...shareId]/page.tsx rename src/app/share/{[...shareId] => [slug]/[[...path]]}/ShareNav.tsx (97%) rename src/app/share/{[...shareId] => [slug]/[[...path]]}/SharePage.tsx (100%) create mode 100644 src/app/share/[slug]/[[...path]]/page.tsx create mode 100644 src/app/share/[slug]/layout.tsx diff --git a/src/app/share/ShareProvider.tsx b/src/app/share/ShareProvider.tsx index 5b0ca12e..9862a974 100644 --- a/src/app/share/ShareProvider.tsx +++ b/src/app/share/ShareProvider.tsx @@ -7,6 +7,7 @@ import type { WhiteLabel } from '@/lib/types'; export interface ShareData { shareId: string; + slug: string; websiteId: string; parameters: any; token: string; @@ -31,8 +32,8 @@ const ALL_SECTION_IDS = [ 'attribution', ]; -export function ShareProvider({ shareId, children }: { shareId: string; children: ReactNode }) { - const { share, isLoading, isFetching } = useShareTokenQuery(shareId); +export function ShareProvider({ slug, children }: { slug: string; children: ReactNode }) { + const { share, isLoading, isFetching } = useShareTokenQuery(slug); const router = useRouter(); const pathname = usePathname(); const path = pathname.split('/')[3]; @@ -48,9 +49,9 @@ export function ShareProvider({ shareId, children }: { shareId: string; children useEffect(() => { if (shouldRedirect) { - router.replace(`/share/${shareId}/${allowedSections[0]}`); + router.replace(`/share/${slug}/${allowedSections[0]}`); } - }, [shouldRedirect, shareId, allowedSections, router]); + }, [shouldRedirect, slug, allowedSections, router]); if (isFetching && isLoading) { return ; @@ -60,5 +61,5 @@ export function ShareProvider({ shareId, children }: { shareId: string; children return null; } - return {children}; + return {children}; } diff --git a/src/app/share/[...shareId]/ShareFooter.tsx b/src/app/share/[...shareId]/ShareFooter.tsx deleted file mode 100644 index 5348ac63..00000000 --- a/src/app/share/[...shareId]/ShareFooter.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Row, Text } from '@umami/react-zen'; -import { CURRENT_VERSION, HOMEPAGE_URL } from '@/lib/constants'; -import type { WhiteLabel } from '@/lib/types'; - -export function ShareFooter({ whiteLabel }: { whiteLabel?: WhiteLabel }) { - if (whiteLabel) { - return ( - - - {whiteLabel.name} - - - ); - } - - return ( - - - umami {`v${CURRENT_VERSION}`} - - - ); -} diff --git a/src/app/share/[...shareId]/ShareHeader.tsx b/src/app/share/[...shareId]/ShareHeader.tsx deleted file mode 100644 index abd8511d..00000000 --- a/src/app/share/[...shareId]/ShareHeader.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Icon, Row, Text, ThemeButton } from '@umami/react-zen'; -import { LanguageButton } from '@/components/input/LanguageButton'; -import { PreferencesButton } from '@/components/input/PreferencesButton'; -import { Logo } from '@/components/svg'; -import type { WhiteLabel } from '@/lib/types'; - -export function ShareHeader({ whiteLabel }: { whiteLabel?: WhiteLabel }) { - const logoUrl = whiteLabel?.url || 'https://umami.is'; - const logoName = whiteLabel?.name || 'umami'; - const logoImage = whiteLabel?.image; - - return ( - - - - {logoImage ? ( - {logoName} - ) : ( - - - - )} - {logoName} - - - - - - - - - ); -} diff --git a/src/app/share/[...shareId]/page.tsx b/src/app/share/[...shareId]/page.tsx deleted file mode 100644 index f21e1979..00000000 --- a/src/app/share/[...shareId]/page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ShareProvider } from '@/app/share/ShareProvider'; -import { SharePage } from './SharePage'; - -export default async function ({ params }: { params: Promise<{ shareId: string[] }> }) { - const { shareId } = await params; - const [slug] = shareId; - - return ( - - - - ); -} diff --git a/src/app/share/[...shareId]/ShareNav.tsx b/src/app/share/[slug]/[[...path]]/ShareNav.tsx similarity index 97% rename from src/app/share/[...shareId]/ShareNav.tsx rename to src/app/share/[slug]/[[...path]]/ShareNav.tsx index 171539ac..fa100b17 100644 --- a/src/app/share/[...shareId]/ShareNav.tsx +++ b/src/app/share/[slug]/[[...path]]/ShareNav.tsx @@ -10,13 +10,13 @@ export function ShareNav({ onItemClick }: { onItemClick?: () => void }) { const share = useShare(); const { formatMessage, labels } = useMessages(); const { pathname } = useNavigation(); - const { shareId, parameters, whiteLabel } = share; + const { slug, parameters, whiteLabel } = share; const logoUrl = whiteLabel?.url || 'https://umami.is'; const logoName = whiteLabel?.name || 'umami'; const logoImage = whiteLabel?.image; - const renderPath = (path: string) => `/share/${shareId}${path}`; + const renderPath = (path: string) => `/share/${slug}${path}`; const allItems = [ { diff --git a/src/app/share/[...shareId]/SharePage.tsx b/src/app/share/[slug]/[[...path]]/SharePage.tsx similarity index 100% rename from src/app/share/[...shareId]/SharePage.tsx rename to src/app/share/[slug]/[[...path]]/SharePage.tsx diff --git a/src/app/share/[slug]/[[...path]]/page.tsx b/src/app/share/[slug]/[[...path]]/page.tsx new file mode 100644 index 00000000..872cf267 --- /dev/null +++ b/src/app/share/[slug]/[[...path]]/page.tsx @@ -0,0 +1,5 @@ +import { SharePage } from './SharePage'; + +export default function () { + return ; +} diff --git a/src/app/share/[slug]/layout.tsx b/src/app/share/[slug]/layout.tsx new file mode 100644 index 00000000..7a5f4599 --- /dev/null +++ b/src/app/share/[slug]/layout.tsx @@ -0,0 +1,13 @@ +import { ShareProvider } from '@/app/share/ShareProvider'; + +export default async function ({ + params, + children, +}: { + params: Promise<{ slug: string }>; + children: React.ReactNode; +}) { + const { slug } = await params; + + return {children}; +}