Разработка кастомных схем (Schemas) Sanity
Схема в Sanity — TypeScript-описание структуры документа. Поля, типы, валидация, группы — всё в коде. Sanity Studio генерирует форму редактора автоматически из схемы.
Типы документов и их регистрация
// sanity/schema.ts
import { postType } from './schemas/postType'
import { authorType } from './schemas/authorType'
import { categoryType } from './schemas/categoryType'
import { productType } from './schemas/productType'
import { siteSettingsType } from './schemas/siteSettingsType'
export const schema = {
types: [postType, authorType, categoryType, productType, siteSettingsType],
}
Полная схема товара
// schemas/productType.ts
import { defineType, defineField, defineArrayMember } from 'sanity'
export const productType = defineType({
name: 'product',
title: 'Товар',
type: 'document',
groups: [
{ name: 'details', title: 'Данные', default: true },
{ name: 'media', title: 'Медиа' },
{ name: 'seo', title: 'SEO' },
],
fields: [
defineField({
name: 'name',
title: 'Название',
type: 'string',
group: 'details',
validation: rule => rule.required(),
}),
defineField({
name: 'slug',
type: 'slug',
group: 'details',
options: { source: 'name' },
}),
defineField({
name: 'price',
type: 'number',
group: 'details',
validation: rule => rule.required().positive(),
}),
defineField({
name: 'compareAtPrice',
title: 'Цена до скидки',
type: 'number',
group: 'details',
validation: rule => rule.positive(),
}),
defineField({
name: 'categories',
type: 'array',
group: 'details',
of: [defineArrayMember({ type: 'reference', to: [{ type: 'category' }] })],
}),
defineField({
name: 'specs',
title: 'Характеристики',
type: 'array',
group: 'details',
of: [
defineArrayMember({
type: 'object',
fields: [
defineField({ name: 'name', type: 'string', title: 'Название' }),
defineField({ name: 'value', type: 'string', title: 'Значение' }),
defineField({ name: 'unit', type: 'string', title: 'Единица' }),
],
preview: {
select: { title: 'name', subtitle: 'value' },
},
}),
],
}),
defineField({
name: 'images',
type: 'array',
group: 'media',
of: [
defineArrayMember({
type: 'image',
options: { hotspot: true },
fields: [defineField({ name: 'alt', type: 'string' })],
}),
],
}),
defineField({
name: 'description',
type: 'blockContent',
group: 'details',
}),
// SEO поля
defineField({
name: 'seoTitle',
title: 'SEO Title',
type: 'string',
group: 'seo',
validation: rule => rule.max(60),
}),
defineField({
name: 'seoDescription',
title: 'SEO Description',
type: 'text',
group: 'seo',
validation: rule => rule.max(160),
}),
// Статус
defineField({
name: 'status',
type: 'string',
options: {
list: [
{ title: 'Активен', value: 'active' },
{ title: 'Архив', value: 'archived' },
{ title: 'Черновик', value: 'draft' },
],
layout: 'radio',
},
initialValue: 'active',
}),
],
})
Portable Text (richtext) схема
// schemas/blockContent.ts
import { defineType, defineArrayMember } from 'sanity'
export const blockContentType = defineType({
name: 'blockContent',
title: 'Block Content',
type: 'array',
of: [
defineArrayMember({
type: 'block',
styles: [
{ title: 'Normal', value: 'normal' },
{ title: 'H2', value: 'h2' },
{ title: 'H3', value: 'h3' },
{ title: 'Quote', value: 'blockquote' },
],
marks: {
decorators: [
{ title: 'Bold', value: 'strong' },
{ title: 'Italic', value: 'em' },
{ title: 'Code', value: 'code' },
],
annotations: [
{
name: 'link',
type: 'object',
fields: [
defineField({ name: 'href', type: 'url' }),
defineField({ name: 'blank', type: 'boolean', title: 'Open in new tab' }),
],
},
],
},
}),
// Встроенные изображения
defineArrayMember({
type: 'image',
options: { hotspot: true },
fields: [
defineField({ name: 'alt', type: 'string' }),
defineField({ name: 'caption', type: 'string' }),
],
}),
// Кастомный блок — цитата с автором
defineArrayMember({
type: 'object',
name: 'callout',
title: 'Callout',
fields: [
defineField({ name: 'text', type: 'text' }),
defineField({
name: 'type',
type: 'string',
options: { list: ['info', 'warning', 'tip'], layout: 'radio' },
}),
],
}),
],
})
Singleton документ (настройки сайта)
// schemas/siteSettingsType.ts
export const siteSettingsType = defineType({
name: 'siteSettings',
title: 'Настройки сайта',
type: 'document',
fields: [
defineField({ name: 'siteName', type: 'string', validation: r => r.required() }),
defineField({ name: 'logo', type: 'image' }),
defineField({ name: 'favicon', type: 'image' }),
defineField({
name: 'socialLinks',
type: 'array',
of: [defineArrayMember({
type: 'object',
fields: [
defineField({ name: 'platform', type: 'string' }),
defineField({ name: 'url', type: 'url' }),
],
})],
}),
],
preview: { select: { title: 'siteName', media: 'logo' } },
})
Сроки
Разработка 4–6 схем с Portable Text, связями и валидацией — 2–3 дня.







