diff --git a/packages/@sanity/cli/src/actions/init-project/initProject.ts b/packages/@sanity/cli/src/actions/init-project/initProject.ts
index 9ca2f92b181..06c46dcc7de 100644
--- a/packages/@sanity/cli/src/actions/init-project/initProject.ts
+++ b/packages/@sanity/cli/src/actions/init-project/initProject.ts
@@ -439,10 +439,14 @@ export default async function initSanity(
}
const {chosen} = await getPackageManagerChoice(workDir, {interactive: false})
trace.log({step: 'selectPackageManager', selectedOption: chosen})
+ const packages = ['@sanity/vision@3', 'sanity@3', '@sanity/image-url@1', 'styled-components@6']
+ if (templateToUse === 'blog') {
+ packages.push('@sanity/icons')
+ }
await installNewPackages(
{
packageManager: chosen,
- packages: ['@sanity/vision@3', 'sanity@3', '@sanity/image-url@1', 'styled-components@6'],
+ packages,
},
{
output: context.output,
diff --git a/packages/@sanity/cli/src/actions/init-project/prompts/nextjs.ts b/packages/@sanity/cli/src/actions/init-project/prompts/nextjs.ts
index b1436218224..202a0797189 100644
--- a/packages/@sanity/cli/src/actions/init-project/prompts/nextjs.ts
+++ b/packages/@sanity/cli/src/actions/init-project/prompts/nextjs.ts
@@ -37,16 +37,16 @@ export function promptForNextTemplate(prompt: CliPrompter): Promise<'clean' | 'b
message: 'Select project template to use',
type: 'list',
choices: [
- {
- value: 'clean',
- name: 'Clean project with no predefined schema types',
- },
{
value: 'blog',
name: 'Blog (schema)',
},
+ {
+ value: 'clean',
+ name: 'Clean project with no predefined schema types',
+ },
],
- default: 'clean',
+ default: 'blog',
})
}
diff --git a/packages/@sanity/cli/src/actions/init-project/templates/nextjs/index.ts b/packages/@sanity/cli/src/actions/init-project/templates/nextjs/index.ts
index b8e857d5316..bfbdd0c6b4b 100644
--- a/packages/@sanity/cli/src/actions/init-project/templates/nextjs/index.ts
+++ b/packages/@sanity/cli/src/actions/init-project/templates/nextjs/index.ts
@@ -12,17 +12,18 @@ import {structureTool} from 'sanity/structure'
// Go to https://www.sanity.io/docs/api-versioning to learn how API versioning works
import {apiVersion, dataset, projectId} from ${hasSrcFolder ? "'./src/sanity/env'" : "'./sanity/env'"}
-import {schema} from ${hasSrcFolder ? "'./src/sanity/schema'" : "'./sanity/schema'"}
+import {schema} from ${hasSrcFolder ? "'./src/sanity/schemaTypes'" : "'./sanity/schemaTypes'"}
+import {structure} from ${hasSrcFolder ? "'./src/sanity/structure'" : "'./sanity/structure'"}
export default defineConfig({
basePath: ':basePath:',
projectId,
dataset,
- // Add and edit the content schema in the './sanity/schema' folder
+ // Add and edit the content schema in the './sanity/schemaTypes' folder
schema,
plugins: [
- structureTool(),
- // Vision is a tool that lets you query your content with GROQ in the studio
+ structureTool({structure}),
+ // Vision is for querying with GROQ from inside the Studio
// https://www.sanity.io/docs/the-vision-plugin
visionTool({defaultApiVersion: apiVersion}),
],
@@ -59,7 +60,8 @@ export { metadata, viewport } from 'next-sanity/studio'
export default function StudioPage() {
return
-}`
+}
+`
// Format today's date like YYYY-MM-DD
const envTS = `export const apiVersion =
@@ -103,6 +105,54 @@ const schemaJS = `export const schema = {
}
`
+const blogStructureTS = `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()!),
+ ),
+ ])
+`
+
+const blogStructureJS = `// https://www.sanity.io/docs/structure-builder-cheat-sheet
+export const structure = (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()),
+ ),
+ ])
+`
+
+const structureTS = `import type {StructureResolver} from 'sanity/structure'
+
+// https://www.sanity.io/docs/structure-builder-cheat-sheet
+export const structure: StructureResolver = (S) =>
+ S.list()
+ .title('Content')
+ .items(S.documentTypeListItems())
+`
+
+const structureJS = `// https://www.sanity.io/docs/structure-builder-cheat-sheet
+export const structure = (S) =>
+ S.list()
+ .title('Content')
+ .items(S.documentTypeListItems())
+`
+
const client = `import { createClient } from 'next-sanity'
import { apiVersion, dataset, projectId } from '../env'
@@ -146,17 +196,8 @@ export const sanityFolder = (
useTypeScript: boolean,
template?: 'clean' | 'blog',
): FolderStructure => {
- const isBlogTemplate = template === 'blog'
-
+ // Files used in both templates
const structure: FolderStructure = {
- // eslint-disable-next-line no-nested-ternary
- 'schema.': useTypeScript
- ? isBlogTemplate
- ? blogSchemaTS
- : schemaTS
- : isBlogTemplate
- ? blogSchemaJS
- : schemaJS,
'env.': useTypeScript ? envTS : envJS,
'lib': {
'client.': client,
@@ -164,8 +205,17 @@ export const sanityFolder = (
},
}
- if (isBlogTemplate) {
- structure.schemaTypes = blogSchemaFolder(useTypeScript)
+ if (template === 'blog') {
+ structure.schemaTypes = {
+ ...blogSchemaFolder,
+ 'index.': useTypeScript ? blogSchemaTS : blogSchemaJS,
+ }
+ structure['structure.'] = useTypeScript ? blogStructureTS : blogStructureJS
+ } else {
+ structure.schemaTypes = {
+ 'index.': useTypeScript ? schemaTS : schemaJS,
+ }
+ structure['structure.'] = useTypeScript ? structureTS : structureJS
}
return structure
diff --git a/packages/@sanity/cli/src/actions/init-project/templates/nextjs/schemaTypes/blog.ts b/packages/@sanity/cli/src/actions/init-project/templates/nextjs/schemaTypes/blog.ts
index 89c9c95b247..cfdcfab827e 100644
--- a/packages/@sanity/cli/src/actions/init-project/templates/nextjs/schemaTypes/blog.ts
+++ b/packages/@sanity/cli/src/actions/init-project/templates/nextjs/schemaTypes/blog.ts
@@ -1,11 +1,13 @@
// Types
-const authorTS = `import {defineField, defineType} from 'sanity'
+const authorType = `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',
@@ -16,7 +18,6 @@ export const authorType = defineType({
type: 'slug',
options: {
source: 'name',
- maxLength: 96,
},
}),
defineField({
@@ -25,23 +26,16 @@ export const authorType = defineType({
options: {
hotspot: true,
},
- fields: [
- {
- name: 'alt',
- type: 'string',
- title: 'Alternative Text',
- }
- ]
}),
defineField({
name: 'bio',
type: 'array',
of: [
- {
+ defineArrayMember({
type: 'block',
styles: [{title: 'Normal', value: 'normal'}],
lists: [],
- },
+ }),
],
}),
],
@@ -54,59 +48,7 @@ export const authorType = defineType({
})
`
-const authorJS = `export const authorType = {
- name: 'author',
- title: 'Author',
- type: 'document',
- fields: [
- {
- name: 'name',
- type: 'string',
- },
- {
- name: 'slug',
- type: 'slug',
- options: {
- source: 'name',
- maxLength: 96,
- },
- },
- {
- name: 'image',
- type: 'image',
- options: {
- hotspot: true,
- },
- fields: [
- {
- name: 'alt',
- type: 'string',
- title: 'Alternative Text',
- }
- ]
- },
- {
- name: 'bio',
- type: 'array',
- of: [
- {
- type: 'block',
- styles: [{title: 'Normal', value: 'normal'}],
- lists: [],
- },
- ],
- },
- ],
- preview: {
- select: {
- title: 'name',
- media: 'image',
- },
- },
-}
-`
-
-const blockContentTS = `import {defineType, defineArrayMember} from 'sanity'
+const blockContentType = `import {defineType, defineArrayMember} from 'sanity'
import {ImageIcon} from '@sanity/icons'
/**
@@ -184,94 +126,26 @@ export const blockContentType = defineType({
})
`
-const blockContentJS = `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 = {
- title: 'Block Content',
- name: 'blockContent',
- type: 'array',
- of: [
- {
- title: 'Block',
- type: 'block',
- // Styles let you set what your user can mark up blocks with. These
- // correspond 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 block editor.
- marks: {
- // Decorators usually describe a single property – e.g. a typographic
- // preference or highlighting by editors.
- 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.
- {
- type: 'image',
- icon: ImageIcon,
- options: {hotspot: true},
- fields: [
- {
- name: 'alt',
- type: 'string',
- title: 'Alternative Text',
- }
- ]
- },
- ],
-}
-`
-
-const categoryTS = `import {defineField, defineType} from 'sanity'
+const categoryType = `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',
@@ -280,29 +154,14 @@ export const categoryType = defineType({
})
`
-const categoryJS = `export const categoryType = {
- name: 'category',
- title: 'Category',
- type: 'document',
- fields: [
- {
- name: 'title',
- type: 'string',
- },
- {
- name: 'description',
- type: 'text',
- },
- ],
-}
-`
-
-const postTS = `import {defineField, defineType} from 'sanity'
+const postType = `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',
@@ -313,7 +172,6 @@ export const postType = defineType({
type: 'slug',
options: {
source: 'title',
- maxLength: 96,
},
}),
defineField({
@@ -338,7 +196,7 @@ export const postType = defineType({
defineField({
name: 'categories',
type: 'array',
- of: [{type: 'reference', to: {type: 'category'}}],
+ of: [defineArrayMember({type: 'reference', to: {type: 'category'}})],
}),
defineField({
name: 'publishedAt',
@@ -363,99 +221,32 @@ export const postType = defineType({
})
`
-const postJS = `export const postType = {
- name: 'post',
- title: 'Post',
- type: 'document',
- fields: [
- {
- name: 'title',
- type: 'string',
- },
- {
- name: 'slug',
- type: 'slug',
- options: {
- source: 'title',
- maxLength: 96,
- },
- },
- {
- name: 'author',
- type: 'reference',
- to: {type: 'author'},
- },
- {
- name: 'mainImage',
- type: 'image',
- options: {
- hotspot: true,
- },
- fields: [
- {
- name: 'alt',
- type: 'string',
- title: 'Alternative text',
- }
- ]
- },
- {
- name: 'categories',
- type: 'array',
- of: [{type: 'reference', to: {type: 'category'}}],
- },
- {
- name: 'publishedAt',
- type: 'datetime',
- },
- {
- name: 'body',
- type: 'blockContent',
- },
- ],
- preview: {
- select: {
- title: 'title',
- author: 'author.name',
- media: 'mainImage',
- },
- prepare(selection) {
- const {author} = selection
- return {...selection, subtitle: author && \`by \${author}\`}
- },
- },
-}
-`
-
// Schema definition
-
export const blogSchemaTS = `import { type SchemaTypeDefinition } from 'sanity'
-import {blockContentType} from './schemaTypes/blockContentType'
-import {categoryType} from './schemaTypes/categoryType'
-import {postType} from './schemaTypes/postType'
-import {authorType} from './schemaTypes/authorType'
+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],
}
`
-export const blogSchemaJS = `import {blockContentType} from './schemaTypes/blockContentType'
-import {categoryType} from './schemaTypes/categoryType'
-import {postType} from './schemaTypes/postType'
-import {authorType} from './schemaTypes/authorType'
+export const blogSchemaJS = `import {blockContentType} from './blockContentType'
+import {categoryType} from './categoryType'
+import {postType} from './postType'
+import {authorType} from './authorType'
export const schema = {
types: [blockContentType, categoryType, postType, authorType],
}
`
-export const blogSchemaFolder = (useTypeScript: boolean): Record => {
- return {
- 'authorType.': useTypeScript ? authorTS : authorJS,
- 'blockContentType.': useTypeScript ? blockContentTS : blockContentJS,
- 'categoryType.': useTypeScript ? categoryTS : categoryJS,
- 'postType.': useTypeScript ? postTS : postJS,
- }
+export const blogSchemaFolder: Record = {
+ 'authorType.': authorType,
+ 'blockContentType.': blockContentType,
+ 'categoryType.': categoryType,
+ 'postType.': postType,
}