UNPKG

@vyuh/sanity-schema-marketing

Version:

The Sanity schema package for the Marketing content blocks

171 lines (159 loc) 4.61 kB
import { ContentDescriptor, ContentSchemaBuilder } from '@vyuh/sanity-schema-core'; import { TbArrowRight as Icon } from 'react-icons/tb'; import { defineField, defineType } from 'sanity'; /** * CTA (Call to Action) section schema for marketing pages * Based on common patterns from Tailwind UI CTA sections */ export class CTADescriptor extends ContentDescriptor { static readonly schemaName = 'marketing.cta'; constructor(props: Partial<CTADescriptor>) { super(CTADescriptor.schemaName, props); } } export class CTASchemaBuilder extends ContentSchemaBuilder { private schema = defineType({ name: CTADescriptor.schemaName, title: 'CTA Section', type: 'object', icon: Icon, fields: [ defineField({ name: 'title', title: 'Title', type: 'string', description: 'The main title for the CTA section', validation: (Rule) => Rule.required(), }), defineField({ name: 'subtitle', title: 'Subtitle', type: 'text', description: 'A supporting text that appears below the title', }), defineField({ name: 'image', title: 'Image', type: 'image', description: 'The main image or screenshot', options: { hotspot: true, }, }), defineField({ name: 'primaryAction', title: 'Primary Action', type: 'vyuh.action', validation: (Rule) => Rule.required(), }), defineField({ name: 'secondaryAction', title: 'Secondary Action', type: 'vyuh.action', }), defineField({ name: 'additionalInfo', title: 'Additional Information', type: 'text', description: 'Optional text that appears below the buttons (e.g., "No credit card required")', }), ], preview: { select: { title: 'title', subtitle: 'subtitle', primaryAction: 'primaryAction.title', secondaryAction: 'secondaryAction.title', }, prepare({ title, subtitle, primaryAction, secondaryAction }) { const subtitleText = []; if (primaryAction) { subtitleText.push(`Primary: ${primaryAction}`); } if (secondaryAction) { subtitleText.push(`Secondary: ${secondaryAction}`); } return { title: `CTA: ${title || 'Untitled'}`, subtitle: subtitleText.length > 0 ? subtitleText.join(' | ') : subtitle ? subtitle.substring(0, 50) : 'No content', media: Icon, }; }, }, }); constructor() { super(CTADescriptor.schemaName); } build(descriptors: ContentDescriptor[]) { return this.schema; } } export const defaultCTALayout = defineType({ name: `${CTADescriptor.schemaName}.layout.default`, title: 'Default', type: 'object', icon: Icon, fields: [ defineField({ name: 'variant', title: 'Variant', type: 'string', description: 'The style variant for the CTA section', options: { list: [ { title: 'Simple centered', value: 'simple-centered' }, { title: 'Split with image on right', value: 'split-image-right' }, ], }, initialValue: 'simple-centered', validation: (Rule) => Rule.required(), }), defineField({ name: 'background', title: 'Background', type: 'string', options: { list: [ { title: 'Light', value: 'light' }, { title: 'Brand', value: 'brand' }, { title: 'Neutral', value: 'neutral' }, { title: 'Accent', value: 'accent' }, { title: 'Default', value: 'default' }, ], }, initialValue: 'light', }), ], preview: { select: { variant: 'variant', background: 'background', bgType: 'background.type', }, prepare({ variant, background, bgType }) { // Format the variant name for display const variantDisplay = variant ? variant .split('-') .map((word: string) => word.charAt(0).toUpperCase() + word.slice(1)) .join(' ') : 'Simple Centered'; // Create a descriptive subtitle based on background settings let bgDisplay = background || 'Light'; if (bgType) { bgDisplay = `${bgDisplay}, ${bgType}`; } return { title: `CTA Layout: ${variantDisplay}`, subtitle: `Background: ${bgDisplay}`, media: Icon, }; }, }, });