Add React editor project
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import PageEditor from '@/components/page-editor';
|
||||
|
||||
// Editor for /collections/[handle]. Sitting under the route it edits means the preview
|
||||
// resolves the same params the public page gets.
|
||||
export default function EditorPage() {
|
||||
return <PageEditor routeKey="/collections/[handle]" />;
|
||||
}
|
||||
@@ -1,194 +1,38 @@
|
||||
{
|
||||
"root": {
|
||||
"props": {
|
||||
"title": "Collection — Pulse",
|
||||
"headerFont": "Archivo Black",
|
||||
"headerFontWeight": "400",
|
||||
"bodyFont": "Inter",
|
||||
"primaryColor": "#111111",
|
||||
"secondaryColor": "#707072",
|
||||
"accentColor": "#f5f5f5",
|
||||
"bgColor": "#ffffff",
|
||||
"fgColor": "#111111",
|
||||
"mutedColor": "#f5f5f5",
|
||||
"radius": "xl",
|
||||
"buttonRadius": "full",
|
||||
"shadow": "none",
|
||||
"maxWidth": "2xl"
|
||||
"title": "Collection",
|
||||
"description": "Shop the collection.",
|
||||
"ogImage": ""
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"type": "header",
|
||||
"props": {
|
||||
"id": "nav-collection",
|
||||
"brand": "PULSE",
|
||||
"links": [
|
||||
{
|
||||
"label": "Run",
|
||||
"href": "/collections/run"
|
||||
},
|
||||
{
|
||||
"label": "Train",
|
||||
"href": "/collections/train"
|
||||
},
|
||||
{
|
||||
"label": "Recover",
|
||||
"href": "/collections/recover"
|
||||
},
|
||||
{
|
||||
"label": "Sale",
|
||||
"href": "/collections/sale"
|
||||
},
|
||||
{
|
||||
"label": "About",
|
||||
"href": "/about"
|
||||
}
|
||||
],
|
||||
"showSearch": "yes",
|
||||
"showAccount": "yes",
|
||||
"showCart": "yes",
|
||||
"sticky": "yes",
|
||||
"tone": "default"
|
||||
}
|
||||
"id": "header"
|
||||
},
|
||||
"synced": true
|
||||
},
|
||||
{
|
||||
"type": "collection",
|
||||
"type": "collection-detail",
|
||||
"props": {
|
||||
"id": "collection-detail",
|
||||
"collection": null,
|
||||
"showDescription": "yes",
|
||||
"showCoverImage": "yes",
|
||||
"customCoverImage": "",
|
||||
"columns": "4",
|
||||
"limit": 24,
|
||||
"defaultSort": "BEST_SELLING",
|
||||
"showAvailability": "yes",
|
||||
"showPriceRange": "yes",
|
||||
"showProductType": "yes",
|
||||
"productTypeOptions": [
|
||||
{
|
||||
"label": "Tops"
|
||||
},
|
||||
{
|
||||
"label": "Shorts"
|
||||
},
|
||||
{
|
||||
"label": "Tights"
|
||||
},
|
||||
{
|
||||
"label": "Outerwear"
|
||||
},
|
||||
{
|
||||
"label": "Shoes"
|
||||
},
|
||||
{
|
||||
"label": "Accessories"
|
||||
}
|
||||
],
|
||||
"showVendor": "no",
|
||||
"vendorOptions": [],
|
||||
"showTags": "no",
|
||||
"tagOptions": [],
|
||||
"showColor": "yes",
|
||||
"colorOptions": [
|
||||
{
|
||||
"label": "Black",
|
||||
"color": "#111111"
|
||||
},
|
||||
{
|
||||
"label": "White",
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"label": "Grey",
|
||||
"color": "#707072"
|
||||
},
|
||||
{
|
||||
"label": "Volt",
|
||||
"color": "#d6ff3f"
|
||||
},
|
||||
{
|
||||
"label": "Sodium",
|
||||
"color": "#fa5400"
|
||||
}
|
||||
],
|
||||
"showStyle": "no",
|
||||
"styleOptions": [],
|
||||
"showSize": "yes",
|
||||
"sizeOptions": [
|
||||
{
|
||||
"label": "XS"
|
||||
},
|
||||
{
|
||||
"label": "S"
|
||||
},
|
||||
{
|
||||
"label": "M"
|
||||
},
|
||||
{
|
||||
"label": "L"
|
||||
},
|
||||
{
|
||||
"label": "XL"
|
||||
},
|
||||
{
|
||||
"label": "XXL"
|
||||
}
|
||||
],
|
||||
"showMaterial": "no",
|
||||
"materialOptions": [],
|
||||
"metafieldFilters": []
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "footer",
|
||||
"props": {
|
||||
"id": "footer-collection",
|
||||
"brand": "PULSE",
|
||||
"tagline": "Performance gear for athletes who break their kit before they break themselves.",
|
||||
"columns": [
|
||||
{
|
||||
"title": "Shop",
|
||||
"links": [
|
||||
{
|
||||
"label": "All gear",
|
||||
"href": "/search"
|
||||
},
|
||||
{
|
||||
"label": "New",
|
||||
"href": "/collections/new"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Help",
|
||||
"links": [
|
||||
{
|
||||
"label": "Shipping",
|
||||
"href": "/help/shipping"
|
||||
},
|
||||
{
|
||||
"label": "Returns",
|
||||
"href": "/help/returns"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"social": [
|
||||
{
|
||||
"label": "Instagram",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Strava",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"showNewsletter": "no",
|
||||
"newsletterHeading": "",
|
||||
"newsletterEndpoint": "",
|
||||
"copyright": "© 2026 Pulse. Built to be replaced when used up."
|
||||
"id": "footer"
|
||||
},
|
||||
"synced": true
|
||||
},
|
||||
{
|
||||
"type": "store-assistant",
|
||||
"props": {
|
||||
"id": "store-assistant"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
import PageRender from "@/components/page-render";
|
||||
import page from "./page.json";
|
||||
import type { Metadata } from 'next';
|
||||
import PageRender from '@/components/page-render';
|
||||
import { pageMetadata } from '@/lib/page-metadata';
|
||||
import { getCollectionProductsPage } from '@/services/shopify/catalog';
|
||||
import { truncate } from '@/lib/utils';
|
||||
import page from './page.json';
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ handle: string }>;
|
||||
}): Promise<Metadata> {
|
||||
const { handle } = await params;
|
||||
|
||||
// No collection-only query exists, so ask for the smallest page of products
|
||||
// and use just the collection node off it.
|
||||
const { collection } = await getCollectionProductsPage(handle, {
|
||||
first: 1,
|
||||
}).catch(() => ({ collection: null }));
|
||||
|
||||
// The blocks fetch client-side and render their own empty state, so a failed
|
||||
// lookup falls back to the page.json tags rather than a 500.
|
||||
if (!collection) return pageMetadata(page);
|
||||
|
||||
return pageMetadata(page, {
|
||||
title: collection.title,
|
||||
description: collection.description
|
||||
? truncate(collection.description, 160)
|
||||
: `Shop the ${collection.title} collection.`,
|
||||
image: collection.image?.url,
|
||||
path: `/collections/${collection.handle}`,
|
||||
});
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
return <PageRender page={page} />;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import PageEditor from '@/components/page-editor';
|
||||
|
||||
// Editor for /collections. Sitting under the route it edits means the preview
|
||||
// resolves the same params the public page gets.
|
||||
export default function EditorPage() {
|
||||
return <PageEditor routeKey="/collections" />;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"root": {
|
||||
"props": {
|
||||
"title": "Collections",
|
||||
"description": "Browse every collection in the store.",
|
||||
"ogImage": ""
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"type": "header",
|
||||
"props": {
|
||||
"id": "header"
|
||||
},
|
||||
"synced": true
|
||||
},
|
||||
{
|
||||
"type": "collections",
|
||||
"props": {
|
||||
"id": "collections-grid",
|
||||
"title": "Our Collections",
|
||||
"subtitle": "Discover our carefully crafted worlds"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "footer",
|
||||
"props": {
|
||||
"id": "footer"
|
||||
},
|
||||
"synced": true
|
||||
},
|
||||
{
|
||||
"type": "store-assistant",
|
||||
"props": {
|
||||
"id": "store-assistant"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import PageRender from '@/components/page-render';
|
||||
import { pageMetadata } from '@/lib/page-metadata';
|
||||
import page from './page.json';
|
||||
|
||||
export const metadata = pageMetadata(page, { path: '/collections' });
|
||||
|
||||
export default function Page() {
|
||||
return <PageRender page={page} />;
|
||||
}
|
||||
Reference in New Issue
Block a user