mirror of
https://github.com/vercel/commerce.git
synced 2025-05-12 12:47:50 +00:00
feat: implement accordion content type
Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
parent
a1d65a54c1
commit
e0da620ac9
@ -1,12 +1,8 @@
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
import IconWithTextBlock, { IconBlockPlaceholder } from 'components/page/icon-with-text-block';
|
||||
import ImageWithTextBlock from 'components/page/image-with-text-block';
|
||||
import TextBlock from 'components/page/text-block';
|
||||
import { getPage, getPageMetaObjects } from 'lib/shopify';
|
||||
import { PageContent, PageMetafieldKey } from 'lib/shopify/types';
|
||||
import PageContent from 'components/page/page-content';
|
||||
import { getPage } from 'lib/shopify';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { Suspense } from 'react';
|
||||
|
||||
export const runtime = 'edge';
|
||||
|
||||
@ -30,29 +26,11 @@ export async function generateMetadata({
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const contentMap: Record<PageMetafieldKey, (content: PageContent) => JSX.Element> = {
|
||||
page_icon_section: (content) => (
|
||||
<Suspense fallback={<IconBlockPlaceholder />}>
|
||||
<IconWithTextBlock content={content} />
|
||||
</Suspense>
|
||||
),
|
||||
page_image_content: (content) => <ImageWithTextBlock content={content} />,
|
||||
page_section: (content) => <TextBlock content={content} />
|
||||
};
|
||||
|
||||
export default async function Page({ params }: { params: { page: string } }) {
|
||||
const page = await getPage(params.page);
|
||||
|
||||
if (!page) return notFound();
|
||||
|
||||
const pageContents = (
|
||||
await Promise.allSettled(page.metafields.map((metafield) => getPageMetaObjects(metafield)))
|
||||
)
|
||||
.filter((result) => result.status === 'fulfilled')
|
||||
.map((result) => (result as PromiseFulfilledResult<PageContent | null>).value)
|
||||
.filter(Boolean) as PageContent[];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mx-auto mb-2 max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
@ -63,8 +41,10 @@ export default async function Page({ params }: { params: { page: string } }) {
|
||||
<main>
|
||||
<div className="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">
|
||||
<div className="flex flex-col space-y-16">
|
||||
{pageContents.map((content) => (
|
||||
<div key={content.id}>{contentMap[content.key](content)}</div>
|
||||
{page.metaobjects?.map((content) => (
|
||||
<div key={content.id}>
|
||||
<PageContent block={content} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
23
components/page/accordion-block-item.tsx
Normal file
23
components/page/accordion-block-item.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
'use client';
|
||||
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react';
|
||||
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
const AccordionBlockItem = ({ title, children }: { title: string; children: ReactNode }) => {
|
||||
return (
|
||||
<Disclosure as="div" className="pt-6">
|
||||
<dt>
|
||||
<DisclosureButton className="group flex w-full items-start justify-between text-left text-gray-900">
|
||||
<span className="text-lg font-semibold leading-7">{title}</span>
|
||||
<ChevronDownIcon className="size-5 group-data-[open]:rotate-180" />
|
||||
</DisclosureButton>
|
||||
</dt>
|
||||
<DisclosurePanel as="dd" className="mt-2 flex flex-col gap-4 py-4 text-base text-gray-800">
|
||||
{children}
|
||||
</DisclosurePanel>
|
||||
</Disclosure>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccordionBlockItem;
|
39
components/page/accordion-block.tsx
Normal file
39
components/page/accordion-block.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { getMetaobjectById, getMetaobjectsByIds } from 'lib/shopify';
|
||||
import { Metaobject } from 'lib/shopify/types';
|
||||
import AccordionBlockItem from './accordion-block-item';
|
||||
import PageContent from './page-content';
|
||||
|
||||
const AccordionItem = async ({ id }: { id: string }) => {
|
||||
const accordionObject = await getMetaobjectById(id);
|
||||
|
||||
if (!accordionObject) return null;
|
||||
|
||||
const content = await getMetaobjectsByIds(JSON.parse(accordionObject.accordion_content || '[]'));
|
||||
|
||||
return (
|
||||
<AccordionBlockItem title={accordionObject.title || 'Section Title'}>
|
||||
{content.map((block) => (
|
||||
<PageContent block={block} key={block.id} />
|
||||
))}
|
||||
</AccordionBlockItem>
|
||||
);
|
||||
};
|
||||
|
||||
const AccordionBlock = async ({ block }: { block: Metaobject }) => {
|
||||
const accordionItemIds = JSON.parse(block.accordion || '[]') as string[];
|
||||
|
||||
return (
|
||||
<div className="divide-y divide-gray-900/10">
|
||||
{block.title && (
|
||||
<h3 className="mb-7 text-xl font-semibold leading-6 text-gray-900">{block.title}</h3>
|
||||
)}
|
||||
<dl className="w-full space-y-6 divide-y divide-gray-900/10">
|
||||
{accordionItemIds.map((id) => (
|
||||
<AccordionItem key={id} id={id} />
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccordionBlock;
|
@ -1,7 +1,7 @@
|
||||
import Grid from 'components/grid';
|
||||
import DynamicHeroIcon from 'components/hero-icon';
|
||||
import { getMetaobjects, getMetaobjectsByIds } from 'lib/shopify';
|
||||
import { PageContent, ScreenSize } from 'lib/shopify/types';
|
||||
import { Metaobject, ScreenSize } from 'lib/shopify/types';
|
||||
|
||||
export const IconBlockPlaceholder = () => {
|
||||
return (
|
||||
@ -13,15 +13,10 @@ export const IconBlockPlaceholder = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const IconWithTextBlock = async ({ content }: { content: PageContent }) => {
|
||||
// for icon with text content, we only need the first metaobject as the array always contains only one element due to the metafield definition set up on Shopify
|
||||
const metaobject = content.metaobjects[0];
|
||||
|
||||
if (!metaobject) return null;
|
||||
|
||||
const IconWithTextBlock = async ({ block }: { block: Metaobject }) => {
|
||||
const [contentBlocks, layouts, screenSizes] = await Promise.all([
|
||||
getMetaobjectsByIds(metaobject.content ? JSON.parse(metaobject.content) : []),
|
||||
getMetaobjectsByIds(metaobject.layouts ? JSON.parse(metaobject.layouts) : []),
|
||||
getMetaobjectsByIds(block.content ? JSON.parse(block.content) : []),
|
||||
getMetaobjectsByIds(block.layouts ? JSON.parse(block.layouts) : []),
|
||||
getMetaobjects('screen_sizes')
|
||||
]);
|
||||
|
||||
@ -75,15 +70,18 @@ const IconWithTextBlock = async ({ content }: { content: PageContent }) => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5 px-4 md:px-0">
|
||||
<h3 className="text-xl font-semibold leading-6 text-gray-900">{metaobject.title}</h3>
|
||||
{block.title ? (
|
||||
<h3 className="text-xl font-semibold leading-6 text-gray-900">{block.title}</h3>
|
||||
) : null}
|
||||
|
||||
<Grid className={validClassnames}>
|
||||
{contentBlocks.map((block) => (
|
||||
<Grid.Item key={block.id} className="flex flex-col gap-2">
|
||||
{block.icon_name && (
|
||||
<DynamicHeroIcon icon={block.icon_name} className="w-16 text-secondary" />
|
||||
)}
|
||||
<div className="text-lg font-medium">{block.title}</div>
|
||||
<p className="text-base text-gray-800">{block.content}</p>
|
||||
{block.title && <div className="text-lg font-medium">{block.title}</div>}
|
||||
{block.content && <p className="text-base text-gray-800">{block.content}</p>}
|
||||
</Grid.Item>
|
||||
))}
|
||||
</Grid>
|
||||
|
@ -1,35 +1,34 @@
|
||||
import { PageContent } from 'lib/shopify/types';
|
||||
import { Metaobject } from 'lib/shopify/types';
|
||||
import { Suspense } from 'react';
|
||||
import ImageDisplay from './image-display';
|
||||
import RichTextDisplay from './rich-text-display';
|
||||
|
||||
const ImageWithTextBlock = ({ content }: { content: PageContent }) => {
|
||||
if (!content.metaobjects.length) return null;
|
||||
const ImageWithTextBlock = ({ block }: { block: Metaobject }) => {
|
||||
const description = block.description ? JSON.parse(block.description) : null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-10">
|
||||
{content.metaobjects.map((metaobject) => {
|
||||
const contentBlocks = JSON.parse(metaobject.description || '{}');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 px-4 md:px-0" key={metaobject.id}>
|
||||
<h3 className="text-xl font-semibold leading-6 text-gray-900">{metaobject.title}</h3>
|
||||
<div className="grid grid-cols-1 gap-5 md:grid-cols-3">
|
||||
<div className="relative col-span-1">
|
||||
<Suspense>
|
||||
<ImageDisplay
|
||||
title={metaobject.title as string}
|
||||
fileId={metaobject.file as string}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<RichTextDisplay contentBlocks={contentBlocks.children} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-6 px-4 md:px-0">
|
||||
{block.title && (
|
||||
<h3 className="text-xl font-semibold leading-6 text-gray-900">{block.title}</h3>
|
||||
)}
|
||||
{description ? (
|
||||
<div className="grid grid-cols-1 gap-5 md:grid-cols-3">
|
||||
<div className="relative col-span-1">
|
||||
<Suspense>
|
||||
<ImageDisplay title={block.title || 'Image Preview'} fileId={block.file as string} />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="col-span-2">
|
||||
<RichTextDisplay contentBlocks={description.children} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative w-full">
|
||||
<Suspense>
|
||||
<ImageDisplay title={block.title || 'Image Preview'} fileId={block.file as string} />
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
24
components/page/page-content.tsx
Normal file
24
components/page/page-content.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { Metaobject, PageType } from 'lib/shopify/types';
|
||||
import { Suspense } from 'react';
|
||||
import AccordionBlock from './accordion-block';
|
||||
import IconWithTextBlock, { IconBlockPlaceholder } from './icon-with-text-block';
|
||||
import ImageWithTextBlock from './image-with-text-block';
|
||||
import TextBlock from './text-block';
|
||||
|
||||
const PageContent = ({ block }: { block: Metaobject }) => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const contentMap: Record<PageType, (block: Metaobject) => JSX.Element> = {
|
||||
icon_content_section: (block) => (
|
||||
<Suspense fallback={<IconBlockPlaceholder />}>
|
||||
<IconWithTextBlock block={block} />
|
||||
</Suspense>
|
||||
),
|
||||
image: (block) => <ImageWithTextBlock block={block} />,
|
||||
page_section: (block) => <TextBlock block={block} />,
|
||||
accordion: (block) => <AccordionBlock block={block} />
|
||||
};
|
||||
|
||||
return contentMap[block.type as PageType](block);
|
||||
};
|
||||
|
||||
export default PageContent;
|
@ -1,10 +1,18 @@
|
||||
type Text = {
|
||||
type: 'text';
|
||||
value: string;
|
||||
bold?: boolean;
|
||||
};
|
||||
|
||||
type Content =
|
||||
| { type: 'paragraph'; children: Array<{ type: 'text'; value: string; bold?: boolean }> }
|
||||
| { type: 'paragraph'; children: Text[] }
|
||||
| Text
|
||||
| {
|
||||
type: 'text';
|
||||
value: string;
|
||||
bold?: boolean;
|
||||
};
|
||||
type: 'list';
|
||||
listType: 'bullet' | 'ordered';
|
||||
children: Array<{ type: 'listItem'; children: Text[] }>;
|
||||
}
|
||||
| { type: 'listItem'; children: Text[] };
|
||||
|
||||
const RichTextBlock = ({ block }: { block: Content }) => {
|
||||
if (block.type === 'text') {
|
||||
@ -15,6 +23,22 @@ const RichTextBlock = ({ block }: { block: Content }) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (block.type === 'listItem') {
|
||||
return block.children.map((child, index) => <RichTextBlock key={index} block={child} />);
|
||||
}
|
||||
|
||||
if (block.type === 'list' && block.listType === 'ordered') {
|
||||
return (
|
||||
<ol className="ml-10 list-decimal">
|
||||
{block.children.map((child, index) => (
|
||||
<li key={index}>
|
||||
<RichTextBlock block={child} />
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<p className="text-gray-800">
|
||||
{block.children.map((child, index) => (
|
||||
|
@ -1,21 +1,18 @@
|
||||
import { PageContent } from 'lib/shopify/types';
|
||||
import { Metaobject } from 'lib/shopify/types';
|
||||
import RichTextDisplay from './rich-text-display';
|
||||
|
||||
const TextBlock = ({ content }: { content: PageContent }) => {
|
||||
if (!content.metaobjects.length) return null;
|
||||
const TextBlock = ({ block }: { block: Metaobject }) => {
|
||||
const content = JSON.parse(block.content || '{}');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-8">
|
||||
{content.metaobjects.map((metaobject) => {
|
||||
const contentBlocks = JSON.parse(metaobject.content || '{}');
|
||||
<div className="flex flex-col gap-5 px-4 md:px-0">
|
||||
{block.title && (
|
||||
<h3 className="text-xl font-semibold leading-6 text-gray-900">{block.title}</h3>
|
||||
)}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5 px-4 md:px-0" key={metaobject.id}>
|
||||
<h3 className="text-xl font-semibold leading-6 text-gray-900">{metaobject.title}</h3>
|
||||
<RichTextDisplay contentBlocks={contentBlocks.children} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<RichTextDisplay contentBlocks={content.children} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ import {
|
||||
getCollectionsQuery
|
||||
} from './queries/collection';
|
||||
import { getMenuQuery } from './queries/menu';
|
||||
import { getMetaobjectsQuery } from './queries/metaobject';
|
||||
import { getMetaobjectQuery, getMetaobjectsQuery } from './queries/metaobject';
|
||||
import { getImageQuery, getMetaobjectsByIdsQuery } from './queries/node';
|
||||
import { getPageQuery, getPagesQuery } from './queries/page';
|
||||
import {
|
||||
@ -45,10 +45,8 @@ import {
|
||||
Menu,
|
||||
Metaobject,
|
||||
Money,
|
||||
PAGE_TYPES,
|
||||
Page,
|
||||
PageInfo,
|
||||
PageMetafield,
|
||||
Product,
|
||||
ProductVariant,
|
||||
ShopifyAddToCartOperation,
|
||||
@ -63,8 +61,8 @@ import {
|
||||
ShopifyImageOperation,
|
||||
ShopifyMenuOperation,
|
||||
ShopifyMetaobject,
|
||||
ShopifyMetaobjectOperation,
|
||||
ShopifyMetaobjectsOperation,
|
||||
ShopifyPage,
|
||||
ShopifyPageOperation,
|
||||
ShopifyPagesOperation,
|
||||
ShopifyProduct,
|
||||
@ -238,7 +236,7 @@ const reshapeFilters = (filters: ShopifyFilter[]): Filter[] => {
|
||||
};
|
||||
|
||||
const reshapeMetaobjects = (metaobjects: ShopifyMetaobject[]): Metaobject[] => {
|
||||
return metaobjects.map(({ fields, id }) => {
|
||||
return metaobjects.map(({ fields, id, type }) => {
|
||||
const groupedFieldsByKey = fields.reduce(
|
||||
(acc, field) => {
|
||||
return {
|
||||
@ -256,7 +254,7 @@ const reshapeMetaobjects = (metaobjects: ShopifyMetaobject[]): Metaobject[] => {
|
||||
}
|
||||
);
|
||||
|
||||
return { id, ...groupedFieldsByKey };
|
||||
return { id, type, ...groupedFieldsByKey };
|
||||
});
|
||||
};
|
||||
|
||||
@ -498,7 +496,10 @@ export async function getMetaobjects(type: string) {
|
||||
export async function getMetaobjectsByIds(ids: string[]) {
|
||||
if (!ids.length) return [];
|
||||
|
||||
const res = await shopifyFetch<ShopifyMetaobjectOperation>({
|
||||
const res = await shopifyFetch<{
|
||||
data: { nodes: ShopifyMetaobject[] };
|
||||
variables: { ids: string[] };
|
||||
}>({
|
||||
query: getMetaobjectsByIdsQuery,
|
||||
variables: { ids }
|
||||
});
|
||||
@ -506,31 +507,39 @@ export async function getMetaobjectsByIds(ids: string[]) {
|
||||
return reshapeMetaobjects(res.body.data.nodes);
|
||||
}
|
||||
|
||||
export async function getPageMetaObjects(metafield: PageMetafield) {
|
||||
let metaobjectIds = parseMetaFieldValue<string | string[]>(metafield) || metafield.value;
|
||||
export async function getMetaobjectById(id: string) {
|
||||
const res = await shopifyFetch<{
|
||||
data: { metaobject: ShopifyMetaobject };
|
||||
variables: { id: string };
|
||||
}>({
|
||||
query: getMetaobjectQuery,
|
||||
variables: { id }
|
||||
});
|
||||
|
||||
if (!metaobjectIds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
metaobjectIds = (Array.isArray(metaobjectIds) ? metaobjectIds : [metaobjectIds]) as string[];
|
||||
|
||||
const metaobjects = await getMetaobjectsByIds(metaobjectIds);
|
||||
|
||||
return { metaobjects, id: metafield.id, key: metafield.key };
|
||||
return res.body.data.metaobject ? reshapeMetaobjects([res.body.data.metaobject])[0] : null;
|
||||
}
|
||||
|
||||
export async function getPage(handle: string): Promise<Page> {
|
||||
const metafieldIdentifiers = PAGE_TYPES.map((key) => ({ key, namespace: 'custom' }));
|
||||
const res = await shopifyFetch<ShopifyPageOperation>({
|
||||
query: getPageQuery,
|
||||
variables: { handle, metafieldIdentifiers }
|
||||
variables: { handle, key: 'page_content', namespace: 'custom' }
|
||||
});
|
||||
|
||||
return res.body.data.pageByHandle;
|
||||
const page = res.body.data.pageByHandle;
|
||||
|
||||
if (page.metafield) {
|
||||
const metaobjectIds = parseMetaFieldValue<string[]>(page.metafield) || [];
|
||||
|
||||
const metaobjects = await getMetaobjectsByIds(metaobjectIds);
|
||||
|
||||
const { metafield, ...restPage } = page;
|
||||
return { ...restPage, metaobjects };
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
export async function getPages(): Promise<Page[]> {
|
||||
export async function getPages(): Promise<ShopifyPage[]> {
|
||||
const res = await shopifyFetch<ShopifyPagesOperation>({
|
||||
query: getPagesQuery
|
||||
});
|
||||
|
@ -18,3 +18,21 @@ export const getMetaobjectsQuery = /* GraphQL */ `
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getMetaobjectQuery = /* GraphQL */ `
|
||||
query getMetaobject($id: ID!) {
|
||||
metaobject(id: $id) {
|
||||
id
|
||||
type
|
||||
fields {
|
||||
reference {
|
||||
... on Metaobject {
|
||||
id
|
||||
}
|
||||
}
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -18,6 +18,7 @@ export const getMetaobjectsByIdsQuery = /* GraphQL */ `
|
||||
nodes(ids: $ids) {
|
||||
... on Metaobject {
|
||||
id
|
||||
type
|
||||
fields {
|
||||
reference {
|
||||
... on Metaobject {
|
||||
|
@ -19,12 +19,11 @@ const pageFragment = /* GraphQL */ `
|
||||
`;
|
||||
|
||||
export const getPageQuery = /* GraphQL */ `
|
||||
query getPage($handle: String!, $metafieldIdentifiers: [HasMetafieldsIdentifier!]!) {
|
||||
query getPage($handle: String!, $key: String!, $namespace: String) {
|
||||
pageByHandle(handle: $handle) {
|
||||
...page
|
||||
metafields(identifiers: $metafieldIdentifiers) {
|
||||
metafield(key: $key, namespace: $namespace) {
|
||||
value
|
||||
key
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -53,14 +53,13 @@ export type Money = {
|
||||
|
||||
export type PageMetafield = {
|
||||
id: string;
|
||||
key: PageMetafieldKey;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export const PAGE_TYPES = ['page_icon_section', 'page_section', 'page_image_content'] as const;
|
||||
export type PageMetafieldKey = (typeof PAGE_TYPES)[number];
|
||||
export const PAGE_TYPES = ['image', 'icon_content_section', 'page_section', 'accordion'] as const;
|
||||
export type PageType = (typeof PAGE_TYPES)[number];
|
||||
|
||||
export type Page = {
|
||||
export type ShopifyPage = {
|
||||
id: string;
|
||||
title: string;
|
||||
handle: string;
|
||||
@ -69,16 +68,15 @@ export type Page = {
|
||||
seo?: SEO;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
metafields: PageMetafield[];
|
||||
metafield: PageMetafield | null;
|
||||
};
|
||||
|
||||
export type MetafieldIdentifier = {
|
||||
key: string;
|
||||
namespace: string;
|
||||
export type Page = Omit<ShopifyPage, 'metafield'> & {
|
||||
metaobjects?: Metaobject[];
|
||||
};
|
||||
|
||||
export type ShopifyMetaobject = {
|
||||
id: string;
|
||||
type: string;
|
||||
fields: Array<{
|
||||
key: string;
|
||||
value: string;
|
||||
@ -90,6 +88,7 @@ export type ShopifyMetaobject = {
|
||||
|
||||
export type Metaobject = {
|
||||
id: string;
|
||||
type: string;
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
@ -296,8 +295,8 @@ export type ShopifyMenuOperation = {
|
||||
};
|
||||
|
||||
export type ShopifyPageOperation = {
|
||||
data: { pageByHandle: Page };
|
||||
variables: { handle: string; metafieldIdentifiers: MetafieldIdentifier[] };
|
||||
data: { pageByHandle: ShopifyPage };
|
||||
variables: { handle: string; key: string; namespace: string };
|
||||
};
|
||||
|
||||
export type ShopifyImageOperation = {
|
||||
@ -312,7 +311,7 @@ export type ShopifyMetaobjectsOperation = {
|
||||
|
||||
export type ShopifyPagesOperation = {
|
||||
data: {
|
||||
pages: Connection<Page>;
|
||||
pages: Connection<ShopifyPage>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -389,12 +388,6 @@ export type Filter = {
|
||||
}[];
|
||||
};
|
||||
|
||||
export type PageContent = {
|
||||
id: string;
|
||||
key: PageMetafieldKey;
|
||||
metaobjects: Metaobject[];
|
||||
};
|
||||
|
||||
export const SCREEN_SIZES = ['small', 'medium', 'large', 'extra_large'] as const;
|
||||
|
||||
export type ScreenSize = (typeof SCREEN_SIZES)[number];
|
||||
|
Loading…
x
Reference in New Issue
Block a user