trptk-sanity/schemaTypes/blog-type.ts
2026-02-24 12:22:46 +01:00

203 lines
5.1 KiB
TypeScript

import {defineArrayMember, defineField, defineType} from 'sanity'
import {DocumentTextIcon} from '@sanity/icons'
import {blogAuthors, blogCategories} from './blog-options'
export const blogType = defineType({
name: 'blog',
title: 'Blog',
type: 'document',
icon: DocumentTextIcon,
groups: [
{name: 'main', title: 'Main', default: true},
{name: 'content', title: 'Content'},
{name: 'references', title: 'Related'},
],
fieldsets: [{name: 'details', title: 'Details', options: {columns: 2}}],
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
group: 'main',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'subtitle',
title: 'Subtitle',
type: 'string',
group: 'main',
}),
defineField({
name: 'featuredImage',
title: 'Featured Image',
type: 'image',
group: 'main',
options: {hotspot: true},
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
group: 'main',
fieldset: 'details',
options: {
source: 'title',
maxLength: 200,
},
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'author',
title: 'Author',
type: 'string',
group: 'main',
fieldset: 'details',
options: {
list: blogAuthors,
},
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'publishDate',
title: 'Publish Date',
type: 'date',
group: 'main',
fieldset: 'details',
description: 'Defaults to today. Override to backdate or schedule a post.',
initialValue: () => new Date().toISOString().split('T')[0],
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'category',
title: 'Category',
type: 'string',
group: 'main',
fieldset: 'details',
options: {
list: blogCategories,
},
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'content',
title: 'Content',
type: 'array',
group: 'content',
of: [
defineArrayMember({type: 'block'}),
defineArrayMember({
type: 'image',
options: {hotspot: true},
fields: [
defineField({
name: 'alt',
title: 'Alt text',
type: 'string',
description: 'Describe the image for accessibility.',
}),
defineField({
name: 'caption',
title: 'Caption',
type: 'string',
}),
],
}),
defineArrayMember({
type: 'object',
name: 'youtube',
title: 'YouTube Video',
fields: [
defineField({
name: 'url',
title: 'YouTube URL',
type: 'url',
validation: (Rule) =>
Rule.required()
.uri({scheme: ['https']})
.custom((url) => {
if (typeof url !== 'string') return true
if (
url.includes('youtube.com/watch') ||
url.includes('youtu.be/') ||
url.includes('youtube.com/embed/')
) {
return true
}
return 'Must be a valid YouTube URL'
}),
}),
],
preview: {
select: {url: 'url'},
prepare({url}) {
return {title: 'YouTube Video', subtitle: url}
},
},
}),
],
}),
defineField({
name: 'releases',
title: 'Related Release(s)',
type: 'array',
group: 'references',
of: [defineArrayMember({type: 'reference', to: [{type: 'release'}]})],
}),
defineField({
name: 'artists',
title: 'Related Artist(s)',
type: 'array',
group: 'references',
of: [defineArrayMember({type: 'reference', to: [{type: 'artist'}]})],
}),
defineField({
name: 'composers',
title: 'Related Composer(s)',
type: 'array',
group: 'references',
of: [defineArrayMember({type: 'reference', to: [{type: 'composer'}]})],
}),
defineField({
name: 'works',
title: 'Related Work(s)',
type: 'array',
group: 'references',
of: [defineArrayMember({type: 'reference', to: [{type: 'work'}]})],
}),
],
orderings: [
{
title: 'Publish Date (latest first)',
name: 'publishDateDesc',
by: [{field: 'publishDate', direction: 'desc'}],
},
{
title: 'Publish Date (oldest first)',
name: 'publishDateAsc',
by: [{field: 'publishDate', direction: 'asc'}],
},
],
preview: {
select: {
title: 'title',
author: 'author',
media: 'featuredImage',
category: 'category',
},
prepare({title, author, media, category}) {
return {
title: title || '(Untitled post)',
subtitle: [author, category].filter(Boolean).join(' · '),
media,
}
},
},
})