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, }