edit
This commit is contained in:
20
sanity/env.ts
Normal file
20
sanity/env.ts
Normal 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
10
sanity/lib/client.ts
Normal 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
11
sanity/lib/image.ts
Normal 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
13
sanity/lib/live.ts
Normal 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'
|
||||
})
|
||||
});
|
46
sanity/schemaTypes/authorType.ts
Normal file
46
sanity/schemaTypes/authorType.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
})
|
76
sanity/schemaTypes/blockContentType.ts
Normal file
76
sanity/schemaTypes/blockContentType.ts
Normal 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',
|
||||
}
|
||||
]
|
||||
}),
|
||||
],
|
||||
})
|
26
sanity/schemaTypes/categoryType.ts
Normal file
26
sanity/schemaTypes/categoryType.ts
Normal 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',
|
||||
}),
|
||||
],
|
||||
})
|
10
sanity/schemaTypes/index.ts
Normal file
10
sanity/schemaTypes/index.ts
Normal 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],
|
||||
}
|
65
sanity/schemaTypes/postType.ts
Normal file
65
sanity/schemaTypes/postType.ts
Normal 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
15
sanity/structure.ts
Normal 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()!),
|
||||
),
|
||||
])
|
Reference in New Issue
Block a user