finished navbar and blog. todo: finishing touches

This commit is contained in:
2025-08-21 02:03:21 +02:00
parent 519eb1ff2a
commit da67406b5f
49 changed files with 3260 additions and 626 deletions

View File

@@ -1,4 +1,4 @@
{
"generates": "../client-svelte/src/lib/sanity.types.ts",
"path": "./schemaTypes/*.ts"
}
"generates": "../client/src/lib/sanity.types.ts",
"path": "./schemaTypes/*.ts"
}

View File

@@ -1,6 +1,6 @@
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {ClipboardIcon, HomeIcon, MenuIcon, WrenchIcon} from '@sanity/icons'
import {ClipboardIcon, EditIcon, HomeIcon, MenuIcon, WrenchIcon} from '@sanity/icons'
import {schemaTypes} from './schemaTypes'
import {presentationTool} from 'sanity/presentation'
import {linkField} from 'sanity-plugin-link-field'
@@ -41,11 +41,36 @@ export default defineConfig({
.title('Custom pages')
.icon(ClipboardIcon)
.child(S.documentTypeList('custom').title('Content')),
S.listItem()
.title('Blog')
.icon(EditIcon)
.child(S.documentTypeList('blog').title('Blog')),
]),
}),
// @ts-ignore
linkField({
linkableSchemaTypes: ['custom'],
linkableSchemaTypes: ['custom', 'blog'],
customLinkTypes: [
{
title: 'Static pages',
value: 'static',
icon: ClipboardIcon,
options: [
{
title: 'Home',
value: '/',
},
{
title: 'Second page',
value: '/second',
},
{
title: 'Blog',
value: '/blog',
},
],
},
],
}),
presentationTool({
previewUrl: {

View File

@@ -41,6 +41,13 @@
},
"optional": true
},
"publishedAt": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"headerSection": {
"type": "objectAttribute",
"value": {
@@ -51,6 +58,524 @@
}
}
},
{
"name": "blog",
"type": "document",
"attributes": {
"_id": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "blog"
}
},
"_createdAt": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_updatedAt": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_rev": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"title": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"slug": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "slug"
},
"optional": true
},
"author": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"publishedAt": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"tags": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "string"
}
},
"optional": true
},
"excerpt": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"mainImage": {
"type": "objectAttribute",
"value": {
"type": "object",
"attributes": {
"asset": {
"type": "objectAttribute",
"value": {
"type": "object",
"attributes": {
"_ref": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "reference"
}
},
"_weak": {
"type": "objectAttribute",
"value": {
"type": "boolean"
},
"optional": true
}
},
"dereferencesTo": "sanity.imageAsset"
},
"optional": true
},
"media": {
"type": "objectAttribute",
"value": {
"type": "unknown"
},
"optional": true
},
"hotspot": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "sanity.imageHotspot"
},
"optional": true
},
"crop": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "sanity.imageCrop"
},
"optional": true
},
"alt": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "imageWithAlt"
}
}
}
},
"optional": true
},
"body": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "union",
"of": [
{
"type": "object",
"attributes": {
"children": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "object",
"attributes": {
"marks": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "string"
}
},
"optional": true
},
"text": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "span"
}
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
}
},
"optional": true
},
"style": {
"type": "objectAttribute",
"value": {
"type": "union",
"of": [
{
"type": "string",
"value": "normal"
},
{
"type": "string",
"value": "h1"
},
{
"type": "string",
"value": "h2"
},
{
"type": "string",
"value": "h3"
},
{
"type": "string",
"value": "h4"
},
{
"type": "string",
"value": "blockquote"
}
]
},
"optional": true
},
"listItem": {
"type": "objectAttribute",
"value": {
"type": "union",
"of": [
{
"type": "string",
"value": "bullet"
}
]
},
"optional": true
},
"markDefs": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "union",
"of": [
{
"type": "object",
"attributes": {
"href": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "link"
},
"optional": true
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "link"
}
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
},
{
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
},
"rest": {
"type": "inline",
"name": "textColor"
}
},
{
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
},
"rest": {
"type": "inline",
"name": "highlightColor"
}
}
]
}
},
"optional": true
},
"level": {
"type": "objectAttribute",
"value": {
"type": "number"
},
"optional": true
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "block"
}
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
},
{
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
},
"rest": {
"type": "inline",
"name": "button"
}
},
{
"type": "object",
"attributes": {
"asset": {
"type": "objectAttribute",
"value": {
"type": "object",
"attributes": {
"_ref": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "reference"
}
},
"_weak": {
"type": "objectAttribute",
"value": {
"type": "boolean"
},
"optional": true
}
},
"dereferencesTo": "sanity.imageAsset"
},
"optional": true
},
"media": {
"type": "objectAttribute",
"value": {
"type": "unknown"
},
"optional": true
},
"hotspot": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "sanity.imageHotspot"
},
"optional": true
},
"crop": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "sanity.imageCrop"
},
"optional": true
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "image"
}
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
},
{
"type": "object",
"attributes": {
"asset": {
"type": "objectAttribute",
"value": {
"type": "object",
"attributes": {
"_ref": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "reference"
}
},
"_weak": {
"type": "objectAttribute",
"value": {
"type": "boolean"
},
"optional": true
}
},
"dereferencesTo": "sanity.fileAsset"
},
"optional": true
},
"media": {
"type": "objectAttribute",
"value": {
"type": "unknown"
},
"optional": true
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "file"
}
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
}
]
}
},
"optional": true
}
}
},
{
"name": "faqSection",
"type": "type",
@@ -1151,6 +1676,270 @@
}
}
},
{
"name": "navbar",
"type": "document",
"attributes": {
"_id": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "navbar"
}
},
"_createdAt": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_updatedAt": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_rev": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"title": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"links": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "object",
"attributes": {
"text": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"link": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "link"
},
"optional": true
},
"sublinks": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "object",
"attributes": {
"type": {
"type": "objectAttribute",
"value": {
"type": "union",
"of": [
{
"type": "string",
"value": "auto"
},
{
"type": "string",
"value": "tag"
},
{
"type": "string",
"value": "manual"
}
]
},
"optional": true
},
"pageType": {
"type": "objectAttribute",
"value": {
"type": "union",
"of": [
{
"type": "string",
"value": "custom"
},
{
"type": "string",
"value": "blog"
}
]
},
"optional": true
},
"text": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"link": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "link"
},
"optional": true
},
"tagFilter": {
"type": "objectAttribute",
"value": {
"type": "object",
"attributes": {
"_ref": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "reference"
}
},
"_weak": {
"type": "objectAttribute",
"value": {
"type": "boolean"
},
"optional": true
}
},
"dereferencesTo": "tag"
},
"optional": true
},
"tagPageType": {
"type": "objectAttribute",
"value": {
"type": "union",
"of": [
{
"type": "string",
"value": "custom"
},
{
"type": "string",
"value": "blog"
}
]
},
"optional": true
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
}
},
"optional": true
}
},
"rest": {
"type": "object",
"attributes": {
"_key": {
"type": "objectAttribute",
"value": {
"type": "string"
}
}
}
}
}
},
"optional": true
}
}
},
{
"name": "tag",
"type": "document",
"attributes": {
"_id": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "tag"
}
},
"_createdAt": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_updatedAt": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_rev": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"title": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"slug": {
"type": "objectAttribute",
"value": {
"type": "inline",
"name": "slug"
},
"optional": true
},
"description": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
}
}
},
{
"name": "settings",
"type": "document",
@@ -2318,6 +3107,23 @@
},
"optional": true
},
"tags": {
"type": "objectAttribute",
"value": {
"type": "array",
"of": {
"type": "string"
}
},
"optional": true
},
"publishedAt": {
"type": "objectAttribute",
"value": {
"type": "string"
},
"optional": true
},
"body": {
"type": "objectAttribute",
"value": {

View File

@@ -1,250 +1,254 @@
import { LinkIcon, MenuIcon } from "@sanity/icons"
import { defineField, defineType, type Rule, type StringRule } from "sanity"
import { requiredLinkField } from "sanity-plugin-link-field"
import {LinkIcon, MenuIcon} from '@sanity/icons'
import {defineField, defineType, type Rule, type StringRule} from 'sanity'
import {requiredLinkField} from 'sanity-plugin-link-field'
export default defineType({
name: 'navbar',
title: 'Navigation',
type: 'document',
icon: MenuIcon,
fields: [
defineField({
name: 'title',
title: 'Titel',
type: 'string',
initialValue: 'Navigation',
readOnly: true,
hidden: true,
}),
defineField({
name: 'links',
title: 'Links',
icon: LinkIcon,
type: 'array',
initialValue: [
name: 'navbar',
title: 'Navigation',
type: 'document',
icon: MenuIcon,
fields: [
defineField({
name: 'title',
title: 'Titel',
type: 'string',
initialValue: 'Navigation',
readOnly: true,
hidden: true,
}),
defineField({
name: 'links',
title: 'Links',
icon: LinkIcon,
type: 'array',
initialValue: [
{
text: 'Home',
link: {
type: 'url',
value: '/',
},
},
{
text: 'Second Page',
link: {
type: 'url',
value: '/second',
},
},
{
text: 'Blog',
link: {
type: 'url',
value: '/blog',
},
sublinks: [
{
type: 'auto',
pageType: 'blog',
autoTitle: 'Latest Blog Posts',
},
],
},
],
of: [
{
type: 'object',
title: 'Link',
icon: LinkIcon,
fields: [
defineField({
name: 'text',
title: 'Text',
type: 'string',
validation: (Rule: StringRule) => Rule.required().error('Text is required'),
}),
defineField({
name: 'link',
title: 'Link',
type: 'link',
validation: (rule: Rule) => rule.custom((field: Rule) => requiredLinkField(field)),
}),
defineField({
name: 'sublinks',
title: 'Sublinks',
type: 'array',
validation: (Rule) => Rule.max(5).error('Maximum 5 sublinks allowed'),
of: [
{
text: 'Home',
link: {
type: 'url',
value: '/',
}
},
{
text: 'Second Page',
link: {
type: 'url',
value: '/second',
}
},
{
text: 'Blog',
link: {
type: 'url',
value: '/blog',
type: 'object',
title: 'Sublink',
icon: LinkIcon,
fields: [
defineField({
name: 'type',
title: 'Link Type',
type: 'string',
initialValue: 'auto',
options: {
list: [
{
title: 'Last Pages',
value: 'auto',
},
{
title: 'Pages by Tag',
value: 'tag',
},
{
title: 'Manual Link',
value: 'manual',
},
],
layout: 'radio',
},
validation: (Rule: StringRule) => Rule.required(),
}),
defineField({
name: 'pageType',
title: 'Page Type',
type: 'string',
initialValue: 'custom',
description:
'Automatically displays the 5 most recently published pages from the selected type',
options: {
list: [
{title: 'Custom Pages', value: 'custom'},
{title: 'Blog Posts', value: 'blog'},
],
},
hidden: ({parent}) => parent?.type !== 'auto',
validation: (Rule: StringRule) =>
Rule.custom((value, context) => {
const parent = context.parent as {type?: string}
if (parent?.type === 'auto' && !value) {
return 'A page type must be selected'
}
return true
}),
}),
defineField({
name: 'text',
title: 'Text',
type: 'string',
hidden: ({parent}) => parent?.type !== 'manual',
validation: (Rule: StringRule) =>
Rule.custom((value, context) => {
const parent = context.parent as {type?: string}
if (parent?.type === 'manual' && !value) {
return 'Text is required for manual links'
}
return true
}),
}),
defineField({
name: 'link',
title: 'Link',
type: 'link',
hidden: ({parent}) => parent?.type !== 'manual',
validation: (rule: Rule) =>
rule.custom((field, context) => {
const parent = context.parent as {type?: string}
if (parent?.type === 'manual') {
return requiredLinkField(field)
}
return true
}),
}),
defineField({
name: 'tagFilter',
title: 'Tag Filter',
type: 'reference',
to: [{type: 'tag'}],
description:
'Select a tag to filter pages by. The last 5 published pages with this tag will be shown.',
hidden: ({parent}) => parent?.type !== 'tag',
validation: (Rule) =>
Rule.custom((value, context) => {
const parent = context.parent as {type?: string}
if (parent?.type === 'tag' && !value) {
return 'A tag is required when using tag-based filtering'
}
return true
}),
}),
defineField({
name: 'tagPageType',
title: 'Page Type for Tag Filter',
type: 'string',
description: 'Select which type of pages to search for the tag',
options: {
list: [
{title: 'Custom Pages', value: 'custom'},
{title: 'Blog Posts', value: 'blog'},
],
},
hidden: ({parent}) => parent?.type !== 'tag',
initialValue: 'custom',
validation: (Rule: StringRule) =>
Rule.custom((value, context) => {
const parent = context.parent as {type?: string}
if (parent?.type === 'tag' && !value) {
return 'A page type must be selected for tag filtering'
}
return true
}),
}),
],
preview: {
select: {
title: 'text',
type: 'type',
tagTitles: 'tagTitles',
autoTitle: 'autoTitle',
pageType: 'pageType',
tagPageType: 'tagPageType',
},
sublinks: [
{
type: 'auto',
pageType: 'blog',
autoTitle: 'Latest Blog Posts'
prepare({title, type, tagTitles, autoTitle, pageType, tagPageType}) {
let displayTitle = title
let subtitle = ''
const formatPageType = (pageType: string) => {
const typeMap: Record<string, string> = {
home: 'Home',
custom: 'Custom',
blog: 'Blog',
}
]
}
],
of: [
{
type: 'object',
title: 'Link',
icon: LinkIcon,
fields: [
defineField({
name: 'text',
title: 'Text',
type: 'string',
validation: (Rule: StringRule) => Rule.required().error('Text is required'),
}),
defineField({
name: 'link',
title: 'Link',
type: 'link',
validation: (rule: Rule) => rule.custom((field: Rule) => requiredLinkField(field))
}),
defineField({
name: 'sublinks',
title: 'Sublinks',
type: 'array',
validation: (Rule) => Rule.max(5).error('Maximum 5 sublinks allowed'),
of: [
{
type: 'object',
title: 'Sublink',
icon: LinkIcon,
fields: [
defineField({
name: 'type',
title: 'Link Type',
type: 'string',
initialValue: 'auto',
options: {
list: [
{
title: 'Last Pages',
value: 'auto'
},
{
title: 'Pages by Tag',
value: 'tag'
},
{
title: 'Manual Link',
value: 'manual'
},
],
layout: 'radio',
},
validation: (Rule: StringRule) => Rule.required(),
}),
defineField({
name: 'pageType',
title: 'Page Type',
type: 'string',
initialValue: 'custom',
description: 'Automatically displays the 5 most recently published pages from the selected type',
options: {
list: [
{ title: 'Custom Pages', value: 'custom' },
{ title: 'Blog Posts', value: 'blog' },
],
},
hidden: ({ parent }) => parent?.type !== 'auto',
validation: (Rule: StringRule) =>
Rule.custom((value, context) => {
const parent = context.parent as { type?: string }
if (parent?.type === 'auto' && !value) {
return 'A page type must be selected'
}
return true
}),
}),
defineField({
name: 'text',
title: 'Text',
type: 'string',
hidden: ({ parent }) => parent?.type !== 'manual',
validation: (Rule: StringRule) =>
Rule.custom((value, context) => {
const parent = context.parent as { type?: string }
if (parent?.type === 'manual' && !value) {
return 'Text is required for manual links'
}
return true
}),
}),
defineField({
name: 'link',
title: 'Link',
type: 'link',
hidden: ({ parent }) => parent?.type !== 'manual',
validation: (rule: Rule) =>
rule.custom((field, context) => {
const parent = context.parent as { type?: string }
if (parent?.type === 'manual') {
return requiredLinkField(field)
}
return true
}),
}),
defineField({
name: 'tagFilter',
title: 'Tag Filter',
type: 'reference',
to: [{ type: 'tag' }],
description: 'Select a tag to filter pages by. The last 5 published pages with this tag will be shown.',
hidden: ({ parent }) => parent?.type !== 'tag',
validation: (Rule) =>
Rule.custom((value, context) => {
const parent = context.parent as { type?: string }
if (parent?.type === 'tag' && (!value)) {
return 'A tag is required when using tag-based filtering'
}
return true
}),
}),
defineField({
name: 'tagPageType',
title: 'Page Type for Tag Filter',
type: 'string',
description: 'Select which type of pages to search for the tag',
options: {
list: [
{ title: 'Custom Pages', value: 'custom' },
{ title: 'Blog Posts', value: 'blog' },
],
},
hidden: ({ parent }) => parent?.type !== 'tag',
initialValue: 'custom',
validation: (Rule: StringRule) =>
Rule.custom((value, context) => {
const parent = context.parent as { type?: string }
if (parent?.type === 'tag' && !value) {
return 'A page type must be selected for tag filtering'
}
return true
}),
}),
],
preview: {
select: {
title: 'text',
type: 'type',
tagTitles: 'tagTitles',
autoTitle: 'autoTitle',
pageType: 'pageType',
tagPageType: 'tagPageType',
},
prepare({ title, type, tagTitles, autoTitle, pageType, tagPageType }) {
let displayTitle = title
let subtitle = ''
const formatPageType = (pageType: string) => {
const typeMap: Record<string, string> = {
home: 'Home',
custom: 'Custom',
blog: 'Blog'
}
return typeMap[pageType] || pageType.charAt(0).toUpperCase() + pageType.slice(1)
}
switch (type) {
case 'auto':
displayTitle = autoTitle || 'Last Pages'
subtitle = `Auto: Latest 5 from ${formatPageType(pageType)}`
break
case 'tag':
const tagNames = tagTitles?.filter(Boolean).join(', ') || 'No tags'
displayTitle = autoTitle || `Pages tagged: ${tagNames}`
subtitle = `Tag: "${tagNames}" in ${formatPageType(tagPageType)}`
break
case 'manual':
subtitle = 'Manual link'
break
default:
displayTitle = 'Unconfigured link'
}
return {
title: displayTitle || 'Untitled Sublink',
subtitle,
media: LinkIcon,
}
},
},
},
],
}),
],
return (
typeMap[pageType] || pageType.charAt(0).toUpperCase() + pageType.slice(1)
)
}
switch (type) {
case 'auto':
displayTitle = autoTitle || 'Last Pages'
subtitle = `Auto: Latest 5 from ${formatPageType(pageType)}`
break
case 'tag':
const tagNames = tagTitles?.filter(Boolean).join(', ') || 'No tags'
displayTitle = autoTitle || `Pages tagged: ${tagNames}`
subtitle = `Tag: "${tagNames}" in ${formatPageType(tagPageType)}`
break
case 'manual':
subtitle = 'Manual link'
break
default:
displayTitle = 'Unconfigured link'
}
return {
title: displayTitle || 'Untitled Sublink',
subtitle,
media: LinkIcon,
}
},
},
},
],
}),
],
})
],
}),
],
},
],
}),
],
})

View File

@@ -1,5 +1,5 @@
import { DocumentIcon } from '@sanity/icons'
import { defineField, defineType, type SlugRule, type StringRule } from 'sanity'
import {DocumentIcon} from '@sanity/icons'
import {defineField, defineType, type SlugRule, type StringRule} from 'sanity'
export default defineType({
name: 'blog',
@@ -11,7 +11,7 @@ export default defineType({
name: 'title',
title: 'Title',
type: 'string',
validation: (Rule: StringRule) => Rule.required().error('Title is required')
validation: (Rule: StringRule) => Rule.required().error('Title is required'),
}),
defineField({
name: 'slug',
@@ -34,14 +34,10 @@ export default defineType({
type: 'datetime',
}),
defineField({
name: 'tags',
title: 'Tags',
type: 'array',
of: [{ type: 'string' }],
description: 'Add tags to categorize this post. Tags can be used to filter and group related content in navigation menus.',
options: {
layout: 'tags',
},
name: 'tagFilter',
title: 'Tag Filter',
type: 'reference',
to: [{type: 'tag'}],
}),
defineField({
name: 'excerpt',
@@ -67,7 +63,7 @@ export default defineType({
author: 'author',
media: 'mainImage',
},
prepare({ title, author, media }) {
prepare({title, author, media}) {
return {
title: title || 'Untitled',
subtitle: author && `by ${author}`,