Foundation + Schemas

This commit is contained in:
2026-09-21 16:59:08 +02:00
parent 3a27b60be4
commit f82d631ba6
25 changed files with 391 additions and 78 deletions

View File

@@ -0,0 +1,40 @@
import { fields } from '@keystatic/core'
import { STATUS_OPTIONS } from '@/lib/constants/status'
import { SEGMENT, SEGMENT_MESSAGE, slugify } from '@/lib/content/slug'
export const title = fields.slug({
name: {
label: 'Title',
validation: {
isRequired: true,
},
},
slug: {
label: 'File ID',
description: 'Internal and unique across the collection.',
generate: slugify,
validation: {
pattern: {
regex: SEGMENT,
message: SEGMENT_MESSAGE,
},
},
},
})
export const status = fields.select({
label: 'Status',
options: STATUS_OPTIONS,
defaultValue: 'draft',
})
export const noindex = fields.checkbox({
label: 'Hide from search engines',
})
export const base = {
title,
status,
noindex,
}

View File

@@ -0,0 +1,12 @@
import { fields } from '@keystatic/core'
import { assets } from '@/lib/content/assets'
export const content = (collection: string) =>
fields.markdoc({
label: 'Content',
options: {
heading: [2, 3, 4],
image: assets(collection),
},
})

View File

@@ -0,0 +1,25 @@
import { fields } from '@keystatic/core'
import { assets } from '@/lib/content/assets'
export const cover = (collection: string) =>
fields.object(
{
image: fields.image({
label: 'Image',
...assets(collection),
}),
alt: fields.text({
label: 'Alt text',
}),
caption: fields.text({
label: 'Caption',
}),
credit: fields.text({
label: 'Credit',
}),
},
{
label: 'Cover',
},
)

View File

@@ -0,0 +1,18 @@
import { fields } from '@keystatic/core'
export const dates = fields.object(
{
published: fields.datetime({
label: 'Published',
defaultValue: {
kind: 'now',
},
}),
updated: fields.datetime({
label: 'Updated',
}),
},
{
label: 'Dates',
},
)

View File

@@ -0,0 +1,42 @@
import { fields } from '@keystatic/core'
import { ARTICLES } from '@/lib/constants/collections'
import { OPTIONAL_SEGMENT, SEGMENT_MESSAGE } from '@/lib/content/slug'
const segment = fields.text({
label: 'URL segment',
description: 'Optional- Leave empty to use the slugified title',
validation: {
pattern: {
regex: OPTIONAL_SEGMENT,
message: SEGMENT_MESSAGE,
},
},
})
export const pageRoute = fields.object(
{
segment,
},
{
label: 'Route',
},
)
export const articleRoute = fields.object(
{
segment,
parent: fields.relationship({
label: 'Parent',
description: 'Empty makes this a root',
collection: ARTICLES,
}),
index: fields.integer({
label: 'Index',
description: 'Sorts among siblings. Empty sorts by date, newest first',
}),
},
{
label: 'Route',
},
)

View File

@@ -0,0 +1,33 @@
import { fields } from '@keystatic/core'
import { cover } from './cover'
const excerpt = fields.text({
label: 'Excerpt',
multiline: true,
validation: {
length: {
max: 160,
},
},
})
export const pageSummary = fields.object(
{
excerpt,
},
{
label: 'Summary',
},
)
export const articleSummary = (collection: string) =>
fields.object(
{
excerpt,
cover: cover(collection),
},
{
label: 'Summary',
},
)