Files
shopify-react-editor-template/components/shopify/header.editor.tsx
T
2026-08-09 16:00:10 -04:00

90 lines
2.7 KiB
TypeScript

import { ComponentConfig } from '@reacteditor/core';
import { Menu } from 'lucide-react';
import Header from '@/components/shopify/header';
export type HeaderBlockProps = {
storeName?: string;
logoUrl?: string;
showAnnouncement?: 'yes' | 'no';
announcement?: string;
announcementUrl?: string;
links?: Array<{ label: string; url: string }>;
};
/**
* Content only: the store name, the logo, the announcement copy and the nav
* labels. Stickiness, backdrop blur, spacing and the cart/search/account
* affordances are the component's business, not the editor's.
*/
const headerEditor: ComponentConfig<HeaderBlockProps> = {
label: 'Header',
icon: <Menu size={16} />,
category: 'navigation',
// Shared across pages: edit it once and every page.json picks it up.
global: true,
defaultProps: {
storeName: 'Shop',
logoUrl: '',
showAnnouncement: 'yes',
announcement: 'Free shipping on orders over $100',
announcementUrl: '',
links: [
{ label: 'Products', url: '/' },
{ label: 'Collections', url: '/collections' },
],
},
fields: {
storeName: { label: 'Store name', type: 'text', contentEditable: true },
logoUrl: { label: 'Logo', type: 'image' },
showAnnouncement: {
label: 'Announcement bar',
type: 'radio',
options: [
{ label: 'Show', value: 'yes' },
{ label: 'Hide', value: 'no' },
],
},
announcement: {
label: 'Announcement',
type: 'text',
// Deliberately not `contentEditable`: an inline-edited field arrives as a
// ReactNode, which stays truthy once emptied, so the bar would linger as
// an empty band. Keeping it a plain string makes "blank hides it" work.
placeholder: 'Leave empty to hide the bar',
},
announcementUrl: { label: 'Announcement link', type: 'text' },
links: {
label: 'Navigation links',
type: 'array',
defaultItemProps: { label: 'Link', url: '/' },
getItemSummary: (item) => item?.label || 'Link',
arrayFields: {
label: { label: 'Label', type: 'text', contentEditable: true },
url: { label: 'Link', type: 'text' },
},
},
},
render: ({
storeName,
logoUrl,
showAnnouncement,
announcement,
announcementUrl,
links,
}) => (
<Header
storeName={storeName}
logoUrl={logoUrl}
links={links}
// Header decides visibility: blank copy hides the bar, and the toggle
// hides it regardless — needed because an inline-edited field is a node,
// which can't be inspected for emptiness.
showAnnouncement={showAnnouncement}
announcement={announcement}
announcementUrl={announcementUrl}
/>
),
};
export default headerEditor;