This commit is contained in:
2025-06-04 15:46:31 +02:00
parent e0ee3498c7
commit 587b928ab3
66 changed files with 24510 additions and 2489 deletions

20
sanity/env.ts Normal file
View File

@@ -0,0 +1,20 @@
export const apiVersion =
process.env.NEXT_PUBLIC_SANITY_API_VERSION || '2025-06-04'
export const dataset = assertValue(
process.env.NEXT_PUBLIC_SANITY_DATASET,
'Missing environment variable: NEXT_PUBLIC_SANITY_DATASET'
)
export const projectId = assertValue(
process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
'Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID'
)
function assertValue<T>(v: T | undefined, errorMessage: string): T {
if (v === undefined) {
throw new Error(errorMessage)
}
return v
}

10
sanity/lib/client.ts Normal file
View File

@@ -0,0 +1,10 @@
import { createClient } from 'next-sanity'
import { apiVersion, dataset, projectId } from '../env'
export const client = createClient({
projectId,
dataset,
apiVersion,
useCdn: true, // Set to false if statically generating pages, using ISR or tag-based revalidation
})

11
sanity/lib/image.ts Normal file
View File

@@ -0,0 +1,11 @@
import createImageUrlBuilder from '@sanity/image-url'
import { SanityImageSource } from "@sanity/image-url/lib/types/types";
import { dataset, projectId } from '../env'
// https://www.sanity.io/docs/image-url
const builder = createImageUrlBuilder({ projectId, dataset })
export const urlFor = (source: SanityImageSource) => {
return builder.image(source)
}

13
sanity/lib/live.ts Normal file
View File

@@ -0,0 +1,13 @@
// Querying with "sanityFetch" will keep content automatically updated
// Before using it, import and render "<SanityLive />" in your layout, see
// https://github.com/sanity-io/next-sanity#live-content-api for more information.
import { defineLive } from "next-sanity";
import { client } from './client'
export const { sanityFetch, SanityLive } = defineLive({
client: client.withConfig({
// Live content is currently only available on the experimental API
// https://www.sanity.io/docs/api-versioning
apiVersion: 'vX'
})
});

View File

@@ -0,0 +1,46 @@
import {UserIcon} from '@sanity/icons'
import {defineArrayMember, defineField, defineType} from 'sanity'
export const authorType = defineType({
name: 'author',
title: 'Author',
type: 'document',
icon: UserIcon,
fields: [
defineField({
name: 'name',
type: 'string',
}),
defineField({
name: 'slug',
type: 'slug',
options: {
source: 'name',
},
}),
defineField({
name: 'image',
type: 'image',
options: {
hotspot: true,
},
}),
defineField({
name: 'bio',
type: 'array',
of: [
defineArrayMember({
type: 'block',
styles: [{title: 'Normal', value: 'normal'}],
lists: [],
}),
],
}),
],
preview: {
select: {
title: 'name',
media: 'image',
},
},
})

View File

@@ -0,0 +1,76 @@
import {defineType, defineArrayMember} from 'sanity'
import {ImageIcon} from '@sanity/icons'
/**
* This is the schema type for block content used in the post document type
* Importing this type into the studio configuration's `schema` property
* lets you reuse it in other document types with:
* {
* name: 'someName',
* title: 'Some title',
* type: 'blockContent'
* }
*/
export const blockContentType = defineType({
title: 'Block Content',
name: 'blockContent',
type: 'array',
of: [
defineArrayMember({
type: 'block',
// Styles let you define what blocks can be marked up as. The default
// set corresponds with HTML tags, but you can set any title or value
// you want, and decide how you want to deal with it where you want to
// use your content.
styles: [
{title: 'Normal', value: 'normal'},
{title: 'H1', value: 'h1'},
{title: 'H2', value: 'h2'},
{title: 'H3', value: 'h3'},
{title: 'H4', value: 'h4'},
{title: 'Quote', value: 'blockquote'},
],
lists: [{title: 'Bullet', value: 'bullet'}],
// Marks let you mark up inline text in the Portable Text Editor
marks: {
// Decorators usually describe a single property e.g. a typographic
// preference or highlighting
decorators: [
{title: 'Strong', value: 'strong'},
{title: 'Emphasis', value: 'em'},
],
// Annotations can be any object structure e.g. a link or a footnote.
annotations: [
{
title: 'URL',
name: 'link',
type: 'object',
fields: [
{
title: 'URL',
name: 'href',
type: 'url',
},
],
},
],
},
}),
// You can add additional types here. Note that you can't use
// primitive types such as 'string' and 'number' in the same array
// as a block type.
defineArrayMember({
type: 'image',
icon: ImageIcon,
options: {hotspot: true},
fields: [
{
name: 'alt',
type: 'string',
title: 'Alternative Text',
}
]
}),
],
})

View File

@@ -0,0 +1,26 @@
import {TagIcon} from '@sanity/icons'
import {defineField, defineType} from 'sanity'
export const categoryType = defineType({
name: 'category',
title: 'Category',
type: 'document',
icon: TagIcon,
fields: [
defineField({
name: 'title',
type: 'string',
}),
defineField({
name: 'slug',
type: 'slug',
options: {
source: 'title',
},
}),
defineField({
name: 'description',
type: 'text',
}),
],
})

View File

@@ -0,0 +1,10 @@
import { type SchemaTypeDefinition } from 'sanity'
import {blockContentType} from './blockContentType'
import {categoryType} from './categoryType'
import {postType} from './postType'
import {authorType} from './authorType'
export const schema: { types: SchemaTypeDefinition[] } = {
types: [blockContentType, categoryType, postType, authorType],
}

View File

@@ -0,0 +1,65 @@
import {DocumentTextIcon} from '@sanity/icons'
import {defineArrayMember, defineField, defineType} from 'sanity'
export const postType = defineType({
name: 'post',
title: 'Post',
type: 'document',
icon: DocumentTextIcon,
fields: [
defineField({
name: 'title',
type: 'string',
}),
defineField({
name: 'slug',
type: 'slug',
options: {
source: 'title',
},
}),
defineField({
name: 'author',
type: 'reference',
to: {type: 'author'},
}),
defineField({
name: 'mainImage',
type: 'image',
options: {
hotspot: true,
},
fields: [
defineField({
name: 'alt',
type: 'string',
title: 'Alternative text',
})
]
}),
defineField({
name: 'categories',
type: 'array',
of: [defineArrayMember({type: 'reference', to: {type: 'category'}})],
}),
defineField({
name: 'publishedAt',
type: 'datetime',
}),
defineField({
name: 'body',
type: 'blockContent',
}),
],
preview: {
select: {
title: 'title',
author: 'author.name',
media: 'mainImage',
},
prepare(selection) {
const {author} = selection
return {...selection, subtitle: author && `by ${author}`}
},
},
})

15
sanity/structure.ts Normal file
View File

@@ -0,0 +1,15 @@
import type {StructureResolver} from 'sanity/structure'
// https://www.sanity.io/docs/structure-builder-cheat-sheet
export const structure: StructureResolver = (S) =>
S.list()
.title('Blog')
.items([
S.documentTypeListItem('post').title('Posts'),
S.documentTypeListItem('category').title('Categories'),
S.documentTypeListItem('author').title('Authors'),
S.divider(),
...S.documentTypeListItems().filter(
(item) => item.getId() && !['post', 'category', 'author'].includes(item.getId()!),
),
])