Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion astro/src/pages/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
21 changes: 17 additions & 4 deletions nextjs/app/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -23,13 +28,21 @@ async function getPath(params: CatchAllPageProps['params']) {

export async function generateMetadata({
params,
searchParams,
}: CatchAllPageProps): Promise<Metadata> {
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();
Expand Down
6 changes: 5 additions & 1 deletion nuxt/app/pages/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -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<PageResult | null>('/api/page', {
query: { path },
query: { path, viewMode },
});

const redirectResult = computed(() =>
Expand Down
6 changes: 4 additions & 2 deletions nuxt/server/api/page.get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 7 additions & 2 deletions tanstack-start/src/routes/$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import { createFileRoute, notFound, redirect } from '@tanstack/react-router'
import { getPageForPath } 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 getPageForPath({
data: { path, viewMode },
})
if (!result) {
throw notFound()
}
Expand Down
4 changes: 2 additions & 2 deletions tanstack-start/src/server/canvas.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ export const getContentLists = createServerFn().handler(() =>
)

export const getPageForPath = createServerFn()
.validator((path: string) => path)
.handler(({ data }) => readPageForPath(data))
.validator((data: { path: string; viewMode?: string }) => data)
.handler(({ data }) => readPageForPath(data.path, data.viewMode))
9 changes: 7 additions & 2 deletions tanstack-start/src/server/canvas.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ export async function readContentLists(): Promise<ContentLists> {
* 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<PageResult | null> {
return fetchPage(path)
export function readPageForPath(
path: string,
viewMode?: string,
): Promise<PageResult | null> {
return fetchPage(path, {
...(viewMode ? { viewMode } : {}),
})
}