From 1641333849250545be155d79be5bbe4916ce81d8 Mon Sep 17 00:00:00 2001 From: Harumi Jang Date: Tue, 25 Aug 2026 14:42:57 -0400 Subject: [PATCH 1/2] Pass in view mode to fetchPage if provided in all four templates --- astro/src/pages/[...slug].astro | 5 ++++- nextjs/app/[[...slug]]/page.tsx | 21 +++++++++++++++---- nuxt/app/pages/[...slug].vue | 6 +++++- nuxt/server/api/page.get.ts | 6 ++++-- tanstack-start/src/routes/$.tsx | 11 +++++++--- tanstack-start/src/server/canvas.functions.ts | 5 +++++ tanstack-start/src/server/canvas.server.ts | 9 ++++++++ 7 files changed, 52 insertions(+), 11 deletions(-) diff --git a/astro/src/pages/[...slug].astro b/astro/src/pages/[...slug].astro index 686f198..9e6cb3b 100644 --- a/astro/src/pages/[...slug].astro +++ b/astro/src/pages/[...slug].astro @@ -13,7 +13,10 @@ const path = `/${(slug ?? '') .split('/') .map(encodeURIComponent) .join('/')}`; -const result = await fetchPage(Astro, path); +const viewMode = Astro.url.searchParams.get('viewMode') ?? undefined; +const result = await fetchPage(Astro, path, { + ...(viewMode && { viewMode }), +}); if (result && isPageRedirect(result)) { return Astro.redirect(result.redirect.url, result.redirect.statusCode); diff --git a/nextjs/app/[[...slug]]/page.tsx b/nextjs/app/[[...slug]]/page.tsx index c973c76..d17edb4 100644 --- a/nextjs/app/[[...slug]]/page.tsx +++ b/nextjs/app/[[...slug]]/page.tsx @@ -12,9 +12,14 @@ export const dynamic = 'force-dynamic'; interface CatchAllPageProps { params: Promise<{ slug?: string[] }>; + searchParams: Promise<{ viewMode?: string | string[] }>; } -const getPage = cache((path: string) => fetchPage(path)); +const getPage = cache((path: string, viewMode?: string) => + fetchPage(path, { + ...(viewMode ? { viewMode } : {}), + }), +); async function getPath(params: CatchAllPageProps['params']) { const { slug } = await params; @@ -23,13 +28,21 @@ async function getPath(params: CatchAllPageProps['params']) { export async function generateMetadata({ params, + searchParams, }: CatchAllPageProps): Promise { - const page = await getPage(await getPath(params)); + const rawViewMode = (await searchParams).viewMode; + const viewMode = typeof rawViewMode === 'string' ? rawViewMode : undefined; + const page = await getPage(await getPath(params), viewMode); return page && !isPageRedirect(page) ? toNextMetadata(page.head) : {}; } -export default async function CatchAllPage({ params }: CatchAllPageProps) { - const page = await getPage(await getPath(params)); +export default async function CatchAllPage({ + params, + searchParams, +}: CatchAllPageProps) { + const rawViewMode = (await searchParams).viewMode; + const viewMode = typeof rawViewMode === 'string' ? rawViewMode : undefined; + const page = await getPage(await getPath(params), viewMode); if (!page) { notFound(); diff --git a/nuxt/app/pages/[...slug].vue b/nuxt/app/pages/[...slug].vue index cd805ed..e5be716 100644 --- a/nuxt/app/pages/[...slug].vue +++ b/nuxt/app/pages/[...slug].vue @@ -16,8 +16,12 @@ const slug = computed(() => const path = computed( () => `/${slug.value.split('/').map(encodeURIComponent).join('/')}`, ); +const viewMode = computed(() => { + const value = route.query.viewMode; + return typeof value === 'string' && value !== '' ? value : undefined; +}); const { data: result } = await useFetch('/api/page', { - query: { path }, + query: { path, viewMode }, }); const redirectResult = computed(() => diff --git a/nuxt/server/api/page.get.ts b/nuxt/server/api/page.get.ts index 18d2efd..bac2730 100644 --- a/nuxt/server/api/page.get.ts +++ b/nuxt/server/api/page.get.ts @@ -8,14 +8,16 @@ import { fetchPage } from '@drupal-canvas/headless-nuxt/server'; * null body so the page can render its own not-found state. */ export default defineEventHandler(async (event) => { - const path = getQuery(event).path; + const { path, viewMode } = getQuery(event); if (typeof path !== 'string' || !path.startsWith('/')) { setResponseStatus(event, 400); return null; } - const page = await fetchPage(event, path); + const page = await fetchPage(event, path, { + ...(typeof viewMode === 'string' && viewMode !== '' && { viewMode }), + }); if (!page) { setResponseStatus(event, 404); diff --git a/tanstack-start/src/routes/$.tsx b/tanstack-start/src/routes/$.tsx index 68c3ce9..e84dcf9 100644 --- a/tanstack-start/src/routes/$.tsx +++ b/tanstack-start/src/routes/$.tsx @@ -3,15 +3,20 @@ import { toTanStackHead } from '@drupal-canvas/headless-tanstack-start/head' import { isPageRedirect } from '@drupal-canvas/headless' import { createFileRoute, notFound, redirect } from '@tanstack/react-router' -import { getPageForPath } from '#/server/canvas.functions' +import { getPageForPathWithViewMode } from '#/server/canvas.functions' export const Route = createFileRoute('/$')({ - loader: async ({ params }) => { + loader: async ({ params, location }) => { const path = `/${(params._splat ?? '') .split('/') .map(encodeURIComponent) .join('/')}` - const result = await getPageForPath({ data: path }) + const viewMode = location.search + ? new URLSearchParams(location.search).get('viewMode') ?? undefined + : undefined + const result = await getPageForPathWithViewMode({ + data: { path, viewMode }, + }) if (!result) { throw notFound() } diff --git a/tanstack-start/src/server/canvas.functions.ts b/tanstack-start/src/server/canvas.functions.ts index 59f7faa..41115e8 100644 --- a/tanstack-start/src/server/canvas.functions.ts +++ b/tanstack-start/src/server/canvas.functions.ts @@ -11,6 +11,7 @@ import { readContentLists, readDraftSessionState, readPageForPath, + readPageForPathWithViewMode, } from '#/server/canvas.server' export const getDraftSessionState = createServerFn().handler(() => @@ -28,3 +29,7 @@ export const getContentLists = createServerFn().handler(() => export const getPageForPath = createServerFn() .validator((path: string) => path) .handler(({ data }) => readPageForPath(data)) + +export const getPageForPathWithViewMode = createServerFn() + .validator((data: { path: string; viewMode?: string }) => data) + .handler(({ data }) => readPageForPathWithViewMode(data.path, data.viewMode)) diff --git a/tanstack-start/src/server/canvas.server.ts b/tanstack-start/src/server/canvas.server.ts index de883d5..194ba9d 100644 --- a/tanstack-start/src/server/canvas.server.ts +++ b/tanstack-start/src/server/canvas.server.ts @@ -81,3 +81,12 @@ export async function readContentLists(): Promise { export function readPageForPath(path: string): Promise { return fetchPage(path) } + +export function readPageForPathWithViewMode( + path: string, + viewMode?: string, +): Promise { + return fetchPage(path, { + ...(viewMode ? { viewMode } : {}), + }) +} From bdf08e42ea0ef9a21179778f78c8a1067e594cf5 Mon Sep 17 00:00:00 2001 From: Harumi Jang Date: Tue, 25 Aug 2026 14:53:07 -0400 Subject: [PATCH 2/2] refactor: simplify tanstack viewMode page fetch --- tanstack-start/src/routes/$.tsx | 4 ++-- tanstack-start/src/server/canvas.functions.ts | 7 +------ tanstack-start/src/server/canvas.server.ts | 6 +----- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/tanstack-start/src/routes/$.tsx b/tanstack-start/src/routes/$.tsx index e84dcf9..0a71839 100644 --- a/tanstack-start/src/routes/$.tsx +++ b/tanstack-start/src/routes/$.tsx @@ -3,7 +3,7 @@ import { toTanStackHead } from '@drupal-canvas/headless-tanstack-start/head' import { isPageRedirect } from '@drupal-canvas/headless' import { createFileRoute, notFound, redirect } from '@tanstack/react-router' -import { getPageForPathWithViewMode } from '#/server/canvas.functions' +import { getPageForPath } from '#/server/canvas.functions' export const Route = createFileRoute('/$')({ loader: async ({ params, location }) => { @@ -14,7 +14,7 @@ export const Route = createFileRoute('/$')({ const viewMode = location.search ? new URLSearchParams(location.search).get('viewMode') ?? undefined : undefined - const result = await getPageForPathWithViewMode({ + const result = await getPageForPath({ data: { path, viewMode }, }) if (!result) { diff --git a/tanstack-start/src/server/canvas.functions.ts b/tanstack-start/src/server/canvas.functions.ts index 41115e8..b75445d 100644 --- a/tanstack-start/src/server/canvas.functions.ts +++ b/tanstack-start/src/server/canvas.functions.ts @@ -11,7 +11,6 @@ import { readContentLists, readDraftSessionState, readPageForPath, - readPageForPathWithViewMode, } from '#/server/canvas.server' export const getDraftSessionState = createServerFn().handler(() => @@ -27,9 +26,5 @@ export const getContentLists = createServerFn().handler(() => ) export const getPageForPath = createServerFn() - .validator((path: string) => path) - .handler(({ data }) => readPageForPath(data)) - -export const getPageForPathWithViewMode = createServerFn() .validator((data: { path: string; viewMode?: string }) => data) - .handler(({ data }) => readPageForPathWithViewMode(data.path, data.viewMode)) + .handler(({ data }) => readPageForPath(data.path, data.viewMode)) diff --git a/tanstack-start/src/server/canvas.server.ts b/tanstack-start/src/server/canvas.server.ts index 194ba9d..790e647 100644 --- a/tanstack-start/src/server/canvas.server.ts +++ b/tanstack-start/src/server/canvas.server.ts @@ -78,11 +78,7 @@ export async function readContentLists(): Promise { * Resolves a Drupal path through Drupal's routing (the SDK's fetchPage()), * carrying the live draft session's bearer token when there is one. */ -export function readPageForPath(path: string): Promise { - return fetchPage(path) -} - -export function readPageForPathWithViewMode( +export function readPageForPath( path: string, viewMode?: string, ): Promise {