@vyuh/sanity-schema-marketing
Version:
The Sanity schema package for the Marketing content blocks
154 lines (145 loc) • 4.1 kB
text/typescript
import {
ContentDescriptor,
ContentSchemaBuilder,
} from '@vyuh/sanity-schema-core';
import { TbFlag as Icon } from 'react-icons/tb';
import { defineField, defineType } from 'sanity';
export class BannerDescriptor extends ContentDescriptor {
static readonly schemaName = 'marketing.banner';
constructor(props: Partial<BannerDescriptor>) {
super(BannerDescriptor.schemaName, props);
}
}
/**
* Banner element schema for marketing pages
* Based on common patterns from Tailwind UI banner elements
*/
export const defaultBannerLayout = defineType({
name: `${BannerDescriptor.schemaName}.layout.default`,
title: 'Default',
type: 'object',
icon: Icon,
fields: [
defineField({
name: 'variant',
title: 'Variant',
type: 'string',
description: 'The style variant for the banner',
options: {
list: [
{ title: 'Simple', value: 'simple' },
{ title: 'Floating', value: 'floating' },
],
},
initialValue: 'simple',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'colorScheme',
title: 'Color Scheme',
type: 'string',
description: 'The color scheme for the banner',
options: {
list: [
{ title: 'Default', value: 'default' },
{ title: 'Info', value: 'info' },
{ title: 'Success', value: 'success' },
{ title: 'Warning', value: 'warning' },
{ title: 'Error', value: 'error' },
{ title: 'Brand', value: 'brand' },
],
},
initialValue: 'default',
}),
],
preview: {
select: {
variant: 'variant',
colorScheme: 'colorScheme',
},
prepare({ variant, colorScheme }) {
// Format the variant name for display
const variantDisplay = variant
? variant
.split('-')
.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
: 'Simple';
return {
title: `Banner Layout: ${variantDisplay}`,
subtitle: `Color: ${colorScheme || 'Default'}`,
media: Icon,
};
},
},
});
export class BannerSchemaBuilder extends ContentSchemaBuilder {
private schema = defineType({
name: 'marketing.banner',
title: 'Banner',
type: 'object',
icon: Icon,
fields: [
defineField({
name: 'text',
title: 'Banner Text',
type: 'string',
description: 'The main text to display in the banner',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'icon',
title: 'Icon',
type: 'string',
description: 'Optional icon name from your icon library',
}),
defineField({
name: 'action',
title: 'Action',
type: 'vyuh.action',
description: 'Call-to-action button for the banner',
}),
defineField({
name: 'dismissible',
title: 'Dismissible',
type: 'boolean',
description: 'Whether the banner can be dismissed by the user',
initialValue: false,
}),
defineField({
name: 'dismissText',
title: 'Dismiss Text',
type: 'string',
description: 'Text for the dismiss button (e.g., "Dismiss" or "Close")',
initialValue: 'Dismiss',
hidden: ({ parent }) => !parent?.dismissible,
}),
defineField({
name: 'cookieId',
title: 'Cookie ID',
type: 'string',
description: 'Unique identifier for storing dismiss state in cookies',
hidden: ({ parent }) => !parent?.dismissible,
}),
],
preview: {
select: {
title: 'text',
dismissible: 'dismissible',
},
prepare({ title, dismissible }) {
return {
title: `Banner: ${title || 'Untitled'}`,
subtitle: dismissible ? 'Dismissible' : undefined,
media: Icon,
};
},
},
});
constructor() {
super(BannerDescriptor.schemaName);
}
build(descriptors: ContentDescriptor[]) {
return this.schema;
}
}