The editor no longer round-trips through /api/pages. Each route's editor/page.tsx imports its own `../page.json` and hands it to PageEditor as a prop, so the editor opens with the page already in hand — no fetch, no loading state, no undo history seeded from a placeholder. Globals still come from app.globals.json. Publishing moves from `PUT /api/pages` to a `publishPage` server action that writes the route's page.json with node:fs directly. The target path is still built from the lib/pages.ts registry rather than from the caller, so an unknown route key is rejected instead of escaping app/. Removes the customer account auth entirely: the httpOnly cookie session, the /api/account/* handlers, the customer service and GraphQL documents, the account-* blocks, and the /account/* routes. The template has no auth, so nothing reads a cookie now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STGDvL4X7FhHHnxdRE2ayo
65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
/**
|
|
* Every editor-driven route in the app.
|
|
*
|
|
* `key` is what the editor's page picker shows and what `onPublish` hands back;
|
|
* `dir` is the folder under `app/` holding that route's `page.json`. Keeping
|
|
* the list here means the publish action can validate a route key against it
|
|
* rather than trusting a path from the browser.
|
|
*/
|
|
export interface PageRoute {
|
|
key: string;
|
|
label: string;
|
|
/** Path under `app/`, relative and without a leading slash. */
|
|
dir: string;
|
|
}
|
|
|
|
export const PAGE_ROUTES: PageRoute[] = [
|
|
{ key: '/', label: 'Home', dir: '' },
|
|
{ key: '/about', label: 'About', dir: 'about' },
|
|
{ key: '/collections', label: 'Collections', dir: 'collections' },
|
|
{
|
|
key: '/collections/[handle]',
|
|
label: 'Collection detail',
|
|
dir: 'collections/[handle]',
|
|
},
|
|
{
|
|
key: '/products/[handle]',
|
|
label: 'Product detail',
|
|
dir: 'products/[handle]',
|
|
},
|
|
{ key: '/search', label: 'Search', dir: 'search' },
|
|
{ key: '/policies/[handle]', label: 'Policy', dir: 'policies/[handle]' },
|
|
];
|
|
|
|
export const ROUTE_KEYS = PAGE_ROUTES.map((route) => route.key);
|
|
|
|
export function findPageRoute(key: string): PageRoute | undefined {
|
|
return PAGE_ROUTES.find((route) => route.key === key);
|
|
}
|
|
|
|
/**
|
|
* URL of the editor for a route: every public route has an `/editor` child, so
|
|
* `/products/warrior-club-hoodie` is edited at
|
|
* `/products/warrior-club-hoodie/editor`.
|
|
*
|
|
* Dynamic segments are filled from `params` when the caller knows them. The
|
|
* page picker doesn't — switching to `/products/[handle]` there lands on the
|
|
* literal `[handle]`, where the blocks render their empty state until a product
|
|
* is picked. Opening the editor from a real product page is the path that
|
|
* gives them concrete params.
|
|
*/
|
|
export function editorHref(
|
|
routeKey: string,
|
|
params: Record<string, string | undefined> = {}
|
|
): string {
|
|
const base =
|
|
routeKey === '/'
|
|
? ''
|
|
: routeKey.replace(
|
|
/\[(\w+)\]/g,
|
|
(segment, name: string) => params[name] ?? segment
|
|
);
|
|
|
|
return `${base}/editor`;
|
|
}
|