mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
Ported sanity studio to Next js app
This commit is contained in:
50
lib/sanity/schemas/objects/banner.ts
Normal file
50
lib/sanity/schemas/objects/banner.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import {defineField} from 'sanity'
|
||||
import { validateImage } from '../../utils/validation'
|
||||
|
||||
export default defineField({
|
||||
name: 'banner',
|
||||
type: 'object',
|
||||
title: 'Banner',
|
||||
description: 'Normally used in the top of a page to display current page information.',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
description: 'What do you want to convey?',
|
||||
validation: Rule => [
|
||||
Rule.required(),
|
||||
Rule.max(50).warning('Shorter titles are usually better.')
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
title: 'Text',
|
||||
rows: 5,
|
||||
description: 'Small text below title.'
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
type: 'mainImage',
|
||||
title: 'Image',
|
||||
validation: (Rule) => validateImage(Rule, true)
|
||||
},
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
image: 'image',
|
||||
text: 'text'
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, image, text} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
subtitle: `Banner`,
|
||||
media: image
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
132
lib/sanity/schemas/objects/blurbSection.tsx
Normal file
132
lib/sanity/schemas/objects/blurbSection.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import {defineField} from 'sanity'
|
||||
import {CommentIcon} from '@sanity/icons'
|
||||
|
||||
export default defineField({
|
||||
name: 'blurbSection',
|
||||
type: 'object',
|
||||
title: 'Blurb section',
|
||||
icon: CommentIcon,
|
||||
fieldsets: [
|
||||
{
|
||||
name: 'layoutSettings',
|
||||
title: 'Layout settings',
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
title: 'Disabled?',
|
||||
description: 'Set to true to disable this section.',
|
||||
initialValue: 'false',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
description: 'Text displayed above blurbs.',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'mobileLayout',
|
||||
type: 'string',
|
||||
title: 'Mobile layout',
|
||||
initialValue: 'stacked',
|
||||
fieldset: 'layoutSettings',
|
||||
description: 'Display blurbs stacked on top of each other or in a slider.',
|
||||
validation: (Rule) => Rule.required(),
|
||||
options: {
|
||||
list: [
|
||||
{
|
||||
title: 'Vertical (1 column)',
|
||||
value: 'vertical',
|
||||
},
|
||||
{
|
||||
title: 'Horizontal (1 row with scroll)',
|
||||
value: 'horizontal',
|
||||
},
|
||||
],
|
||||
layout: 'radio',
|
||||
direction: 'horizontal',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'desktopLayout',
|
||||
type: 'string',
|
||||
title: 'Desktop layout',
|
||||
initialValue: '3-column',
|
||||
fieldset: 'layoutSettings',
|
||||
description: 'Display blurbs in a 2- 3- or 4-column layout.',
|
||||
validation: (Rule) => Rule.required(),
|
||||
options: {
|
||||
list: [
|
||||
{
|
||||
title: '2 columns',
|
||||
value: '2-column',
|
||||
},
|
||||
{
|
||||
title: '3 columns',
|
||||
value: '3-column',
|
||||
},
|
||||
{
|
||||
title: '4 columns',
|
||||
value: '4-column',
|
||||
},
|
||||
],
|
||||
layout: 'radio',
|
||||
direction: 'horizontal',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'imageFormat',
|
||||
type: 'string',
|
||||
title: 'Blurb image format',
|
||||
initialValue: 'square',
|
||||
description: 'Choose format to display blurb images in.',
|
||||
validation: (Rule) => Rule.required(),
|
||||
fieldset: 'layoutSettings',
|
||||
options: {
|
||||
list: [
|
||||
{title: 'Square (1:1)', value: 'square'},
|
||||
{title: 'Portrait (3:4)', value: 'portrait'},
|
||||
{title: 'Landscape (16:9)', value: 'landscape'},
|
||||
],
|
||||
layout: 'radio',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blurbs',
|
||||
type: 'array',
|
||||
title: 'Blurbs',
|
||||
description: 'Create blurbs or refer to existing blurbs.',
|
||||
of: [
|
||||
{
|
||||
type: 'reference',
|
||||
to: [
|
||||
{
|
||||
type: 'blurb',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
],
|
||||
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
disabled: 'disabled',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, disabled} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
subtitle: `Blurb section ${disabled ? '(⚠️ Disabled)' : ''}`,
|
||||
media: CommentIcon,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
70
lib/sanity/schemas/objects/filteredProductList.ts
Normal file
70
lib/sanity/schemas/objects/filteredProductList.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {defineField} from 'sanity'
|
||||
import {FilterIcon} from '@sanity/icons'
|
||||
|
||||
export default defineField({
|
||||
name: 'filteredProductList',
|
||||
type: 'object',
|
||||
title: 'Filtered product list',
|
||||
icon: FilterIcon,
|
||||
fields: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
title: 'Disabled?',
|
||||
description: 'Set to true to disable this section.',
|
||||
initialValue: 'false',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
description: 'Text displayed above product list.'
|
||||
},
|
||||
{
|
||||
name: 'productCategories',
|
||||
type: 'array',
|
||||
title: 'Product categories',
|
||||
description: 'Select category/categories to display products from.',
|
||||
of: [
|
||||
{
|
||||
type: 'reference',
|
||||
to: [{
|
||||
type: 'category',
|
||||
}],
|
||||
options: {
|
||||
disableNew: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'itemsToShow',
|
||||
type: 'number',
|
||||
title: 'Number of products',
|
||||
initialValue: 4,
|
||||
description: 'Amount of products to be displayed.',
|
||||
validation: (Rule) => Rule.required(),
|
||||
options: {
|
||||
list: [4, 8, 12],
|
||||
layout: 'radio',
|
||||
},
|
||||
},
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
disabled: 'disabled'
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, disabled} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
subtitle: `Filtered product list ${disabled ? '(⚠️ Disabled)' : ''}`,
|
||||
media: FilterIcon
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
125
lib/sanity/schemas/objects/hero.ts
Normal file
125
lib/sanity/schemas/objects/hero.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import {defineField} from 'sanity'
|
||||
import {StarIcon} from '@sanity/icons'
|
||||
import { validateImage } from '../../utils/validation'
|
||||
|
||||
export default defineField({
|
||||
name: 'hero',
|
||||
type: 'object',
|
||||
title: 'Hero',
|
||||
icon: StarIcon,
|
||||
fieldsets: [
|
||||
{
|
||||
name: 'settings',
|
||||
title: 'Hero settings',
|
||||
description: 'Hero layout and semantic settings.',
|
||||
options: {
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
},
|
||||
}
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
title: 'Disabled?',
|
||||
description: 'Set to true to disable this section.',
|
||||
initialValue: false,
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'variant',
|
||||
type: 'string',
|
||||
title: 'Hero variant',
|
||||
initialValue: 'fullScreen',
|
||||
description: 'Choose display for larger screens: Full or half screen height.',
|
||||
validation: Rule => Rule.required(),
|
||||
fieldset: 'settings',
|
||||
options: {
|
||||
list: [
|
||||
{title: 'Full screen', value: 'fullScreen'},
|
||||
{title: '50% height', value: 'halfScreen'},
|
||||
],
|
||||
layout: 'radio',
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'headingLevel',
|
||||
type: 'string',
|
||||
title: 'Heading level',
|
||||
initialValue: 'h1',
|
||||
fieldset: 'settings',
|
||||
description: 'Set appropriate heading level depending on the current document structure.',
|
||||
options: {
|
||||
list: [
|
||||
{title: 'H1', value: 'h1'},
|
||||
{title: 'H2', value: 'h2'},
|
||||
],
|
||||
layout: 'radio',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'label',
|
||||
type: 'string',
|
||||
title: 'Label',
|
||||
description: 'Small text displayed above title.'
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
description: 'What you want to convey.',
|
||||
validation: Rule => [
|
||||
Rule.required(),
|
||||
Rule.max(50).warning('Shorter titles are usually better.')
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
title: 'Text',
|
||||
rows: 5,
|
||||
description: 'Short text displayed below title.',
|
||||
validation: Rule => [
|
||||
Rule.max(100).warning('Strive to be short, precise and on point.')
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
type: 'mainImage',
|
||||
title: 'Image',
|
||||
validation: Rule => validateImage(Rule, true),
|
||||
options: {
|
||||
hotspot: true,
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'link',
|
||||
type: 'linkInternal',
|
||||
title: 'Link',
|
||||
description: 'Link to internal page.',
|
||||
options: {
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
image: 'image',
|
||||
disabled: 'disabled'
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, image, disabled} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
media: image?.asset ? image : StarIcon,
|
||||
subtitle: `Hero ${disabled ? '(⚠️ Disabled)' : ''}`,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
54
lib/sanity/schemas/objects/linkExternal.ts
Normal file
54
lib/sanity/schemas/objects/linkExternal.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {EarthGlobeIcon} from '@sanity/icons'
|
||||
import {defineField} from 'sanity'
|
||||
|
||||
export default defineField({
|
||||
title: 'External Link',
|
||||
name: 'linkExternal',
|
||||
type: 'object',
|
||||
icon: EarthGlobeIcon,
|
||||
description: 'Link to content on external site.',
|
||||
fields: [
|
||||
// Title
|
||||
defineField({
|
||||
title: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
description: 'Descriptive text for the content on this link.'
|
||||
}),
|
||||
// URL
|
||||
defineField({
|
||||
name: 'url',
|
||||
title: 'URL',
|
||||
type: 'url',
|
||||
description: 'Link to websites, e-mail address or phone number.',
|
||||
validation: (Rule) => Rule.required().uri({scheme: ['http', 'https', 'mailto', 'tel']})
|
||||
}),
|
||||
// Open in a new window?
|
||||
defineField({
|
||||
title: 'Open in a new window?',
|
||||
name: 'newWindow',
|
||||
type: 'boolean',
|
||||
description: 'If set to true, opens the link in a new window.',
|
||||
initialValue: false,
|
||||
})
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
url: 'url',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, url} = selection
|
||||
|
||||
let subtitle = []
|
||||
if (url) {
|
||||
subtitle.push(`→ ${url}`)
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
subtitle: subtitle.join(' '),
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
56
lib/sanity/schemas/objects/linkInternal.ts
Normal file
56
lib/sanity/schemas/objects/linkInternal.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {LinkIcon} from '@sanity/icons'
|
||||
import {defineField} from 'sanity'
|
||||
import {PAGE_REFERENCES} from '../../constants'
|
||||
|
||||
export default defineField({
|
||||
title: 'Internal Link',
|
||||
name: 'linkInternal',
|
||||
type: 'object',
|
||||
description: 'Link to content on this site.',
|
||||
icon: LinkIcon,
|
||||
fields: [
|
||||
// Title
|
||||
defineField({
|
||||
title: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
description: 'If empty, displays the current reference title.'
|
||||
}),
|
||||
// Reference
|
||||
defineField({
|
||||
name: 'reference',
|
||||
type: 'reference',
|
||||
title: 'Content reference',
|
||||
description: 'Link to already created, internal content.',
|
||||
weak: true,
|
||||
to: PAGE_REFERENCES,
|
||||
}),
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
reference: 'reference',
|
||||
referenceTitle: 'reference.title',
|
||||
referenceType: 'reference._type',
|
||||
title: 'title',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {
|
||||
reference,
|
||||
referenceTitle,
|
||||
title,
|
||||
} = selection
|
||||
|
||||
let subtitle = []
|
||||
if (reference) {
|
||||
subtitle.push([`→ ${referenceTitle || reference?._id}`])
|
||||
} else {
|
||||
subtitle.push('(Nonexistent document reference)')
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
subtitle: subtitle.join(' '),
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
26
lib/sanity/schemas/objects/mainImage.ts
Normal file
26
lib/sanity/schemas/objects/mainImage.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineField, defineType } from "sanity"
|
||||
|
||||
export default defineType({
|
||||
name: 'mainImage',
|
||||
type: 'image',
|
||||
title: 'Main image',
|
||||
description: 'Select or upload image. Edit by using the `menu` icon. Modify by using the `crop` icon.',
|
||||
options: {
|
||||
hotspot: true,
|
||||
metadata: [
|
||||
'blurhash', // Default: included
|
||||
'lqip', // Default: included
|
||||
'palette', // Default: included
|
||||
'exif', // Default: not included
|
||||
'location', // Default: not included
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
defineField({
|
||||
name: 'alt',
|
||||
type: 'string',
|
||||
title: 'Alternative text',
|
||||
description: 'Note: Important for SEO and accessibility.',
|
||||
}),
|
||||
],
|
||||
})
|
34
lib/sanity/schemas/objects/menu.ts
Normal file
34
lib/sanity/schemas/objects/menu.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {MenuIcon} from '@sanity/icons'
|
||||
import {defineType, defineField} from 'sanity'
|
||||
|
||||
export default defineType({
|
||||
name: 'menu',
|
||||
title: 'Menu',
|
||||
type: 'object',
|
||||
icon: MenuIcon,
|
||||
groups: [],
|
||||
fields: [
|
||||
// Links
|
||||
defineField({
|
||||
name: 'links',
|
||||
title: 'Links',
|
||||
type: 'array',
|
||||
of: [
|
||||
{type: 'linkInternal'},
|
||||
{type: 'linkExternal'},
|
||||
],
|
||||
})
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title} = selection;
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
10
lib/sanity/schemas/objects/placeholderString.ts
Normal file
10
lib/sanity/schemas/objects/placeholderString.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import PlaceholderStringInput from '../../components/inputs/PlaceholderString'
|
||||
|
||||
export default {
|
||||
name: 'placeholderString',
|
||||
title: 'Title',
|
||||
type: 'string',
|
||||
components: {
|
||||
input: PlaceholderStringInput,
|
||||
},
|
||||
}
|
25
lib/sanity/schemas/objects/productOption.ts
Normal file
25
lib/sanity/schemas/objects/productOption.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {defineField} from 'sanity'
|
||||
|
||||
export default defineField({
|
||||
name: 'productOption',
|
||||
title: 'Product option',
|
||||
type: 'object',
|
||||
fields: [
|
||||
defineField({
|
||||
name: 'label',
|
||||
title: 'Label',
|
||||
type: 'string',
|
||||
validation: Rule => Rule.required(),
|
||||
description: 'Product option label.'
|
||||
}),
|
||||
defineField({
|
||||
name: 'hexColors',
|
||||
title: 'Color hex code',
|
||||
type: 'color',
|
||||
description: 'Hex color code for product option.',
|
||||
options: {
|
||||
disableAlpha: true
|
||||
}
|
||||
})
|
||||
],
|
||||
})
|
32
lib/sanity/schemas/objects/productOptions.ts
Normal file
32
lib/sanity/schemas/objects/productOptions.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import {defineField} from 'sanity'
|
||||
|
||||
export default defineField({
|
||||
name: 'productOptions',
|
||||
title: 'Product options',
|
||||
type: 'object',
|
||||
fields: [
|
||||
defineField({
|
||||
name: 'id',
|
||||
title: 'ID (string)',
|
||||
type: 'string',
|
||||
validation: Rule => Rule.required(),
|
||||
description: 'Unique product option ID.'
|
||||
}),
|
||||
defineField({
|
||||
name: 'displayName',
|
||||
title: 'Display name',
|
||||
type: 'string',
|
||||
description: 'Name displayed for this collection of product options.',
|
||||
validation: Rule => Rule.required(),
|
||||
}),
|
||||
defineField({
|
||||
name: 'values',
|
||||
title: 'Values',
|
||||
type: 'array',
|
||||
description: 'What kind of values are available?',
|
||||
of: [{type: 'productOption'}],
|
||||
options: {},
|
||||
validation: Rule => Rule.required(),
|
||||
}),
|
||||
],
|
||||
})
|
11
lib/sanity/schemas/objects/proxyString.ts
Normal file
11
lib/sanity/schemas/objects/proxyString.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import {defineField} from 'sanity'
|
||||
import ProxyStringInput from '../../components/inputs/ProxyString'
|
||||
|
||||
export default defineField({
|
||||
name: 'proxyString',
|
||||
title: 'Title',
|
||||
type: 'string',
|
||||
components: {
|
||||
input: ProxyStringInput,
|
||||
},
|
||||
})
|
54
lib/sanity/schemas/objects/reusableSection.tsx
Normal file
54
lib/sanity/schemas/objects/reusableSection.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import {defineField} from 'sanity'
|
||||
import {BlockElementIcon} from '@sanity/icons'
|
||||
|
||||
export default defineField({
|
||||
name: 'reusableSection',
|
||||
type: 'object',
|
||||
title: 'Reusable section',
|
||||
icon: BlockElementIcon,
|
||||
fields: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
title: 'Disabled?',
|
||||
description: 'Set to true to disable this section.',
|
||||
initialValue: 'false',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
},
|
||||
{
|
||||
name: 'section',
|
||||
type: 'object',
|
||||
title: 'Section',
|
||||
description: 'Reference to an existing section (only 1 allowed).',
|
||||
fields: [
|
||||
{
|
||||
title: 'Existing section',
|
||||
name: 'existingSection',
|
||||
type: 'reference',
|
||||
to: [{type: 'section'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
disabled: 'disabled',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, disabled} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
subtitle: `Reusable section ${disabled ? '(⚠️ Disabled)' : ''}`,
|
||||
media: BlockElementIcon,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
45
lib/sanity/schemas/objects/seo.tsx
Normal file
45
lib/sanity/schemas/objects/seo.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import {defineField} from 'sanity'
|
||||
import { validateImage } from '../../utils/validation'
|
||||
|
||||
export default defineField({
|
||||
name: 'seo',
|
||||
title: 'SEO',
|
||||
type: 'object',
|
||||
description: 'Optimise content for search engines.',
|
||||
options: {
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
},
|
||||
fields: [
|
||||
defineField({
|
||||
name: 'title',
|
||||
title: 'Title',
|
||||
type: 'string',
|
||||
validation: (Rule) =>
|
||||
Rule.max(50).warning('Longer titles may be truncated by search engines'),
|
||||
description: (
|
||||
<>
|
||||
A short and accurate title representative of the content on this page.<br />
|
||||
If empty, displays the current document title (<i>title</i>).
|
||||
</>
|
||||
),
|
||||
}),
|
||||
defineField({
|
||||
name: 'description',
|
||||
title: 'Description',
|
||||
type: 'text',
|
||||
rows: 2,
|
||||
validation: (Rule) =>
|
||||
Rule.max(150).warning('Longer descriptions may be truncated by search engines'),
|
||||
description: 'A brief description of the content on this page.'
|
||||
}),
|
||||
defineField({
|
||||
name: 'image',
|
||||
title: 'Image',
|
||||
type: 'mainImage',
|
||||
validation: Rule => validateImage(Rule, false),
|
||||
description: 'A representative image of the content on this page.'
|
||||
}),
|
||||
],
|
||||
validation: (Rule) => Rule.required(),
|
||||
})
|
97
lib/sanity/schemas/objects/slider.ts
Normal file
97
lib/sanity/schemas/objects/slider.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
import {defineField} from 'sanity'
|
||||
import {PackageIcon} from '@sanity/icons'
|
||||
import {TagIcon, NumberIcon} from '@sanity/icons'
|
||||
|
||||
export default defineField({
|
||||
name: 'slider',
|
||||
type: 'object',
|
||||
title: 'Slider',
|
||||
icon: NumberIcon,
|
||||
fields: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
title: 'Disabled?',
|
||||
description: 'Set to true to disable this section.',
|
||||
initialValue: 'false',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
description: 'Title displayed above slider items.',
|
||||
validation: Rule => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'sliderType',
|
||||
type: 'string',
|
||||
title: 'Slider type',
|
||||
initialValue: 'products',
|
||||
description: 'Select content type to display.',
|
||||
validation: Rule => Rule.required(),
|
||||
options: {
|
||||
list: [
|
||||
{title: 'Products', value: 'products'},
|
||||
{title: 'Categories', value: 'categories'},
|
||||
],
|
||||
layout: 'radio'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Products',
|
||||
name: 'products',
|
||||
type: 'array',
|
||||
description: 'Select products to display.',
|
||||
of: [
|
||||
{
|
||||
type: 'reference',
|
||||
to: [{type: 'product'}],
|
||||
},
|
||||
],
|
||||
validation: Rule => Rule.custom((x:any, context:any) => {
|
||||
if (context.parent.sliderType == 'products' && context?.parent?.products?.length < 3 || context?.parent?.products?.length > 8) {
|
||||
return 'Must have between 3 and 8 items'
|
||||
}
|
||||
return true
|
||||
}),
|
||||
hidden: ({ parent }) => parent?.sliderType !== "products"
|
||||
},
|
||||
{
|
||||
title: 'Categories',
|
||||
name: 'categories',
|
||||
type: 'array',
|
||||
description: 'Select categories to display.',
|
||||
of: [
|
||||
{
|
||||
type: 'reference',
|
||||
to: [{type: 'category'}],
|
||||
},
|
||||
],
|
||||
validation: Rule => Rule.custom((x:any, context:any) => {
|
||||
if (context.parent.sliderType == 'categories' && context?.parent?.categories?.length < 3 || context?.parent?.categories?.length > 8) {
|
||||
return 'Must have between 3 and 8 items'
|
||||
}
|
||||
return true
|
||||
}),
|
||||
hidden: ({ parent }) => parent?.sliderType !== "categories"
|
||||
},
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
sliderType: 'sliderType',
|
||||
disabled: 'disabled'
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, sliderType, disabled} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
media: sliderType === 'products' ? PackageIcon : TagIcon,
|
||||
subtitle: `${sliderType === 'products' ? 'Product' : 'Category'} slider ${disabled ? '(⚠️ Disabled)' : ''}`,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
63
lib/sanity/schemas/objects/uspSection.ts
Normal file
63
lib/sanity/schemas/objects/uspSection.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {defineField} from 'sanity'
|
||||
import {StarIcon} from '@sanity/icons'
|
||||
|
||||
export default defineField({
|
||||
name: 'uspSection',
|
||||
type: 'object',
|
||||
title: 'USP section',
|
||||
icon: StarIcon,
|
||||
fieldsets: [
|
||||
{
|
||||
name: 'layoutSettings',
|
||||
title: 'Layout settings'
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: 'disabled',
|
||||
type: 'boolean',
|
||||
title: 'Disabled?',
|
||||
description: 'Set to true to disable this section.',
|
||||
initialValue: 'false',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
title: 'Title',
|
||||
description: 'Title will only be used internally.',
|
||||
validation: (Rule) => Rule.required(),
|
||||
},
|
||||
{
|
||||
name: 'usps',
|
||||
type: 'array',
|
||||
title: 'USPs',
|
||||
description: 'Create USPs or refer to existing USP.',
|
||||
of: [
|
||||
{
|
||||
type: 'reference',
|
||||
to: [{
|
||||
type: 'usp',
|
||||
}],
|
||||
},
|
||||
],
|
||||
validation: (Rule) => Rule.required().min(2).max(4),
|
||||
},
|
||||
],
|
||||
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
disabled: 'disabled'
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title, disabled} = selection
|
||||
|
||||
return {
|
||||
title: `${title}`,
|
||||
subtitle: `USP section ${disabled ? '(⚠️ Disabled)' : ''}`,
|
||||
media: StarIcon,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
Reference in New Issue
Block a user