├── .node-version ├── frontend ├── public │ ├── robots.txt │ └── favicon.ico ├── server │ └── tsconfig.json ├── tsconfig.json ├── app.vue ├── sanity-typegen.json ├── .env.example ├── layouts │ └── default.vue ├── .gitignore ├── composables │ ├── usePageAnimation.ts │ └── useSiteMetadata.ts ├── components │ ├── PortableText.vue │ ├── Date.vue │ ├── PageBuilder.vue │ ├── Post.vue │ ├── Posts.vue │ ├── global │ │ ├── InfoSection.vue │ │ └── CallToAction.vue │ ├── ResolvedLink.vue │ ├── Avatar.vue │ ├── Footer.vue │ ├── Toast.vue │ ├── GetStartedCode.vue │ ├── Header.vue │ └── SideBySideIcons.vue ├── lib │ └── utils.ts ├── package.json ├── nuxt.config.ts ├── README.md ├── sanity │ ├── queries.ts │ └── types.ts ├── pages │ ├── [slug].vue │ ├── posts │ │ └── [slug].vue │ └── index.vue └── assets │ └── css │ └── main.css ├── .github ├── CODEOWNERS ├── renovate.json └── workflows │ ├── validate.yml │ └── prettier.yml ├── studio ├── .eslintrc ├── static │ ├── .gitkeep │ └── page-builder-thumbnails │ │ ├── callToAction.webp │ │ └── infoSection.webp ├── sample-data.tar.gz ├── sanity-typegen.json ├── .env.example ├── tsconfig.json ├── README.md ├── .gitignore ├── sanity.cli.ts ├── src │ ├── schemaTypes │ │ ├── index.ts │ │ ├── objects │ │ │ ├── infoSection.ts │ │ │ ├── callToAction.ts │ │ │ ├── link.ts │ │ │ └── blockContent.tsx │ │ ├── documents │ │ │ ├── person.ts │ │ │ ├── page.ts │ │ │ └── post.ts │ │ └── singletons │ │ │ └── settings.tsx │ ├── lib │ │ └── initialValues.ts │ └── structure │ │ └── index.ts ├── package.json ├── sanity.config.ts ├── sanity.types.ts └── schema.json ├── nuxt-sanity-preview.webp ├── .gitignore ├── package.json └── README.md /.node-version: -------------------------------------------------------------------------------- 1 | 22.14.0 -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sanity-io/ecosystem 2 | -------------------------------------------------------------------------------- /studio/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@sanity/eslint-config-studio" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /studio/static/.gitkeep: -------------------------------------------------------------------------------- 1 | Files placed here will be served by the Sanity server under the `/static`-prefix 2 | -------------------------------------------------------------------------------- /nuxt-sanity-preview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-template-nuxt-clean/HEAD/nuxt-sanity-preview.webp -------------------------------------------------------------------------------- /studio/sample-data.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-template-nuxt-clean/HEAD/studio/sample-data.tar.gz -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-template-nuxt-clean/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/app.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>sanity-io/renovate-config" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /studio/static/page-builder-thumbnails/callToAction.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-template-nuxt-clean/HEAD/studio/static/page-builder-thumbnails/callToAction.webp -------------------------------------------------------------------------------- /studio/static/page-builder-thumbnails/infoSection.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-template-nuxt-clean/HEAD/studio/static/page-builder-thumbnails/infoSection.webp -------------------------------------------------------------------------------- /frontend/sanity-typegen.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "./sanity/queries.{ts,js}", 3 | "schema": "../studio/schema.json", 4 | "generates": "./sanity/types.ts", 5 | "overloadClientMethods": true 6 | } 7 | -------------------------------------------------------------------------------- /studio/sanity-typegen.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "../frontend/sanity/queries.{ts,js}", 3 | "schema": "schema.json", 4 | "generates": "../frontend/sanity/types.ts", 5 | "overloadClientMethods": true 6 | } 7 | -------------------------------------------------------------------------------- /frontend/.env.example: -------------------------------------------------------------------------------- 1 | NUXT_SANITY_PROJECT_ID="" 2 | NUXT_SANITY_DATASET="production" 3 | NUXT_SANITY_API_READ_TOKEN="" 4 | NUXT_SANITY_API_VERSION="2025-02-04" 5 | NUXT_SANITY_STUDIO_URL="http://localhost:3333" 6 | -------------------------------------------------------------------------------- /frontend/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /studio/.env.example: -------------------------------------------------------------------------------- 1 | SANITY_STUDIO_PROJECT_ID="" # Required - The ID of your Sanity project 2 | SANITY_STUDIO_DATASET="production" # Required - The dataset of your Sanity project 3 | SANITY_STUDIO_PREVIEW_URL="" #Optional - defaults to http://localhost:3000 4 | SANITY_STUDIO_STUDIO_HOST="" #Optional -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: Validate Template 2 | on: push 3 | 4 | jobs: 5 | validate: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Validate Sanity Template 10 | uses: sanity-io/template-validator@v1 11 | with: 12 | repository: ${{ github.repository }} 13 | -------------------------------------------------------------------------------- /frontend/composables/usePageAnimation.ts: -------------------------------------------------------------------------------- 1 | export function usePageAnimation() { 2 | onMounted(() => { 3 | const leftDiv = document.querySelector(".left-div"); 4 | const rightDiv = document.querySelector(".right-div"); 5 | if (leftDiv && rightDiv) { 6 | leftDiv.classList.add("animate-width"); 7 | rightDiv.classList.add("animate-width"); 8 | } 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # misc 10 | .DS_Store 11 | *.pem 12 | 13 | # debug 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # env files 19 | .env 20 | .env.* 21 | !.env.example 22 | 23 | # vercel 24 | .vercel 25 | 26 | # typescript 27 | *.tsbuildinfo 28 | 29 | # VS Code 30 | .vscode -------------------------------------------------------------------------------- /studio/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "module": "Preserve", 10 | "moduleDetection": "force", 11 | "isolatedModules": true, 12 | "jsx": "preserve", 13 | "incremental": true 14 | }, 15 | "include": ["**/*.ts", "**/*.tsx"], 16 | "exclude": ["node_modules"] 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/PortableText.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /frontend/components/Date.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /studio/README.md: -------------------------------------------------------------------------------- 1 | # Sanity Clean Content Studio 2 | 3 | Congratulations, you have now installed the Sanity Content Studio, an open-source real-time content editing environment connected to the Sanity backend. 4 | 5 | Now you can do the following things: 6 | 7 | - [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme) 8 | - [Join the community Slack](https://slack.sanity.io/?utm_source=readme) 9 | - [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme) 10 | -------------------------------------------------------------------------------- /studio/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # Compiled Sanity Studio 9 | /dist 10 | 11 | # Temporary Sanity runtime, generated by the CLI on every dev server start 12 | /.sanity 13 | 14 | # Logs 15 | /logs 16 | *.log 17 | 18 | # Coverage directory used by testing tools 19 | /coverage 20 | 21 | # Misc 22 | .DS_Store 23 | *.pem 24 | 25 | # Typescript 26 | *.tsbuildinfo 27 | 28 | # Dotenv and similar local-only files 29 | *.local 30 | -------------------------------------------------------------------------------- /frontend/composables/useSiteMetadata.ts: -------------------------------------------------------------------------------- 1 | type SiteMetadata = { 2 | title?: string; 3 | description?: string; 4 | ogImage?: string; 5 | }; 6 | 7 | export function useSiteMetadata({ title, description, ogImage }: SiteMetadata) { 8 | useSeoMeta({ 9 | title, 10 | description, 11 | ogTitle: title, 12 | ogDescription: description, 13 | twitterTitle: title, 14 | twitterDescription: description, 15 | twitterCard: "summary", 16 | ogImage, 17 | }); 18 | 19 | useHead({ 20 | htmlAttrs: { 21 | lang: "en", 22 | }, 23 | link: [ 24 | { 25 | rel: "icon", 26 | type: "image/png", 27 | href: "/favicon.png", 28 | }, 29 | ], 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /frontend/components/PageBuilder.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 28 | -------------------------------------------------------------------------------- /studio/sanity.cli.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Sanity CLI Configuration 3 | * This file configures the Sanity CLI tool with project-specific settings 4 | * and customizes the Vite bundler configuration. 5 | * Learn more: https://www.sanity.io/docs/cli 6 | */ 7 | 8 | import {defineCliConfig} from 'sanity/cli' 9 | 10 | const projectId = process.env.SANITY_STUDIO_PROJECT_ID || '' 11 | const dataset = process.env.SANITY_STUDIO_DATASET || 'production' 12 | 13 | export default defineCliConfig({ 14 | api: { 15 | projectId, 16 | dataset, 17 | }, 18 | studioHost: process.env.SANITY_STUDIO_STUDIO_HOST || '', // Visit https://www.sanity.io/docs/environment-variables to learn more about using environment variables for local & production. 19 | autoUpdates: true, 20 | }) 21 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/index.ts: -------------------------------------------------------------------------------- 1 | import {person} from './documents/person' 2 | import {page} from './documents/page' 3 | import {post} from './documents/post' 4 | import {callToAction} from './objects/callToAction' 5 | import {infoSection} from './objects/infoSection' 6 | import {settings} from './singletons/settings' 7 | import {link} from './objects/link' 8 | import {blockContent} from './objects/blockContent' 9 | 10 | // Export an array of all the schema types. This is used in the Sanity Studio configuration. https://www.sanity.io/docs/schema-types 11 | 12 | export const schemaTypes = [ 13 | // Singletons 14 | settings, 15 | // Documents 16 | page, 17 | post, 18 | person, 19 | // Objects 20 | blockContent, 21 | infoSection, 22 | callToAction, 23 | link, 24 | ] 25 | -------------------------------------------------------------------------------- /frontend/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import type { Link } from "~/sanity/types"; 2 | 3 | export function linkResolver(link: Link | undefined) { 4 | if (!link) return null; 5 | 6 | // If linkType is not set but href is, lets set linkType to "href". This comes into play when pasting links into the portable text editor because a link type is not assumed. 7 | if (!link.linkType && link.href) { 8 | link.linkType = "href"; 9 | } 10 | 11 | switch (link.linkType) { 12 | case "href": 13 | return link.href || null; 14 | case "page": 15 | if (link?.page && typeof link.page === "string") { 16 | return `/${link.page}`; 17 | } 18 | case "post": 19 | if (link?.post && typeof link.post === "string") { 20 | return `/posts/${link.post}`; 21 | } 22 | default: 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /frontend/components/Post.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 31 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "prebuild": "npm run typegen", 7 | "build": "nuxt build", 8 | "predev": "npm run typegen", 9 | "dev": "nuxt dev", 10 | "generate": "nuxt generate", 11 | "preview": "nuxt preview", 12 | "postinstall": "nuxt prepare", 13 | "typegen": "sanity typegen generate" 14 | }, 15 | "dependencies": { 16 | "@nuxt/fonts": "^0.11.0", 17 | "@nuxtjs/sanity": "^1.13.3", 18 | "@sanity/client": "^6.27.2", 19 | "@tailwindcss/vite": "^4.0.4", 20 | "date-fns": "^4.1.0", 21 | "groq": "^3.74.1", 22 | "nuxt": "^3.15.4", 23 | "sanity": "^3.82.0", 24 | "tailwindcss": "^4.0.4", 25 | "vue": "latest", 26 | "vue-router": "latest" 27 | }, 28 | "devDependencies": { 29 | "@tailwindcss/typography": "^0.5.16" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /frontend/components/Posts.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 39 | -------------------------------------------------------------------------------- /frontend/components/global/InfoSection.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-template-nuxt-clean", 3 | "description": "Sanity + Nuxt: A Powerful Website Starter with Real-time Visual Editing", 4 | "scripts": { 5 | "dev": "npm-run-all --parallel dev:*", 6 | "dev:next": "npm run dev --workspace=frontend", 7 | "dev:studio": "npm run dev --workspace=studio", 8 | "import-sample-data": "cd studio && sanity dataset import sample-data.tar.gz --replace" 9 | }, 10 | "keywords": [ 11 | "Sanity", 12 | "Nuxt", 13 | "Headless CMS", 14 | "Visual Editing", 15 | "Live Content API (LCAPI)", 16 | "Real-time" 17 | ], 18 | "bugs": { 19 | "url": "https://github.com/sanity-io/sanity-template-nuxt-clean/issues" 20 | }, 21 | "homepage": "https://github.com/sanity-io/sanity-template-nuxt-clean#readme", 22 | "workspaces": [ 23 | "studio", 24 | "frontend" 25 | ], 26 | "devDependencies": { 27 | "npm-run-all": "^4.1.5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/components/ResolvedLink.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 38 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/objects/infoSection.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {TextIcon} from '@sanity/icons' 3 | 4 | export const infoSection = defineType({ 5 | name: 'infoSection', 6 | title: 'Info Section', 7 | type: 'object', 8 | icon: TextIcon, 9 | fields: [ 10 | defineField({ 11 | name: 'heading', 12 | title: 'Heading', 13 | type: 'string', 14 | }), 15 | defineField({ 16 | name: 'subheading', 17 | title: 'Subheading', 18 | type: 'string', 19 | }), 20 | defineField({ 21 | name: 'content', 22 | title: 'Content', 23 | type: 'blockContent', 24 | }), 25 | ], 26 | preview: { 27 | select: { 28 | title: 'heading', 29 | subtitle: 'subheading', 30 | }, 31 | prepare({title}) { 32 | return { 33 | title: title || 'Untitled Info Section', 34 | subtitle: 'Info Section', 35 | } 36 | }, 37 | }, 38 | }) 39 | -------------------------------------------------------------------------------- /frontend/components/Avatar.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 41 | -------------------------------------------------------------------------------- /frontend/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 29 | -------------------------------------------------------------------------------- /frontend/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | import tailwindcss from "@tailwindcss/vite"; 3 | 4 | export default defineNuxtConfig({ 5 | compatibilityDate: "2024-11-01", 6 | css: ["~/assets/css/main.css"], 7 | devtools: { 8 | enabled: true, 9 | 10 | timeline: { 11 | enabled: true, 12 | }, 13 | }, 14 | modules: ["@nuxtjs/sanity", "@nuxt/fonts"], 15 | sanity: { 16 | projectId: process.env.NUXT_SANITY_PROJECT_ID, 17 | dataset: process.env.NUXT_SANITY_DATASET, 18 | apiVersion: process.env.NUXT_SANITY_API_VERSION || "2025-04-01", 19 | token: process.env.NUXT_SANITY_API_READ_TOKEN, // Only required when using a private dataset 20 | visualEditing: { 21 | token: process.env.NUXT_SANITY_API_READ_TOKEN, 22 | studioUrl: process.env.NUXT_SANITY_STUDIO_URL, 23 | zIndex: 51, 24 | }, 25 | }, 26 | runtimeConfig: { 27 | public: { 28 | studioUrl: process.env.NUXT_SANITY_STUDIO_URL, 29 | }, 30 | }, 31 | vite: { 32 | plugins: [tailwindcss()], 33 | optimizeDeps: { 34 | include: ["shallowequal", "lodash/startCase.js"], 35 | }, 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Nuxt Minimal Starter 2 | 3 | Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. 4 | 5 | ## Setup 6 | 7 | Make sure to install dependencies: 8 | 9 | ```bash 10 | # npm 11 | npm install 12 | 13 | # pnpm 14 | pnpm install 15 | 16 | # yarn 17 | yarn install 18 | 19 | # bun 20 | bun install 21 | ``` 22 | 23 | ## Development Server 24 | 25 | Start the development server on `http://localhost:3000`: 26 | 27 | ```bash 28 | # npm 29 | npm run dev 30 | 31 | # pnpm 32 | pnpm dev 33 | 34 | # yarn 35 | yarn dev 36 | 37 | # bun 38 | bun run dev 39 | ``` 40 | 41 | ## Production 42 | 43 | Build the application for production: 44 | 45 | ```bash 46 | # npm 47 | npm run build 48 | 49 | # pnpm 50 | pnpm build 51 | 52 | # yarn 53 | yarn build 54 | 55 | # bun 56 | bun run build 57 | ``` 58 | 59 | Locally preview production build: 60 | 61 | ```bash 62 | # npm 63 | npm run preview 64 | 65 | # pnpm 66 | pnpm preview 67 | 68 | # yarn 69 | yarn preview 70 | 71 | # bun 72 | bun run preview 73 | ``` 74 | 75 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. 76 | -------------------------------------------------------------------------------- /studio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starter-template", 3 | "private": true, 4 | "version": "1.0.0", 5 | "main": "package.json", 6 | "license": "UNLICENSED", 7 | "scripts": { 8 | "dev": "sanity dev", 9 | "start": "sanity start", 10 | "prebuild": "npm run extract-types", 11 | "build": "sanity build", 12 | "deploy": "sanity deploy", 13 | "extract-types": "sanity schema extract --enforce-required-fields" 14 | }, 15 | "keywords": [ 16 | "sanity" 17 | ], 18 | "dependencies": { 19 | "@sanity/assist": "^3.2.0", 20 | "@sanity/icons": "^3.7.0", 21 | "@sanity/vision": "3.82.0", 22 | "date-fns": "^3.6.0", 23 | "pluralize-esm": "^9.0.5", 24 | "react": "^18.3.1", 25 | "react-dom": "^18.3.1", 26 | "rxjs": "^7.8.1", 27 | "sanity": "^3.82.0", 28 | "styled-components": "^6.1.13" 29 | }, 30 | "devDependencies": { 31 | "@sanity/eslint-config-studio": "^5.0.2", 32 | "@types/react": "^18.3.12", 33 | "eslint": "^8.6.0", 34 | "prettier": "^3.3.3", 35 | "typescript": "^5.6.3" 36 | }, 37 | "prettier": { 38 | "semi": false, 39 | "printWidth": 100, 40 | "bracketSpacing": false, 41 | "singleQuote": true 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /frontend/components/global/CallToAction.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 43 | -------------------------------------------------------------------------------- /studio/src/lib/initialValues.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Demo data used as placeholders and initial values for the blog 3 | */ 4 | 5 | export const title = 'Sanity + Nuxt' 6 | 7 | export const description = [ 8 | { 9 | _key: '9f1a629887fd', 10 | _type: 'block', 11 | children: [ 12 | { 13 | _key: '4a58edd077880', 14 | _type: 'span', 15 | marks: [], 16 | text: 'A website example using ', 17 | }, 18 | { 19 | _key: '4a58edd077881', 20 | _type: 'span', 21 | marks: ['ec5b66c9b1e0'], 22 | text: 'Nuxt', 23 | }, 24 | { 25 | _key: '4a58edd077882', 26 | _type: 'span', 27 | marks: [], 28 | text: ' and ', 29 | }, 30 | { 31 | _key: '4a58edd077883', 32 | _type: 'span', 33 | marks: ['1f8991913ea8'], 34 | text: 'Sanity', 35 | }, 36 | { 37 | _key: '4a58edd077884', 38 | _type: 'span', 39 | marks: [], 40 | text: '.', 41 | }, 42 | ], 43 | markDefs: [ 44 | { 45 | _key: 'ec5b66c9b1e0', 46 | _type: 'link', 47 | href: 'https://nuxt.com/', 48 | }, 49 | { 50 | _key: '1f8991913ea8', 51 | _type: 'link', 52 | href: 'https://sanity.io/', 53 | }, 54 | ], 55 | style: 'normal', 56 | }, 57 | ] 58 | 59 | export const ogImageTitle = 'A Nuxt + Sanity Website' 60 | -------------------------------------------------------------------------------- /studio/src/structure/index.ts: -------------------------------------------------------------------------------- 1 | import {CogIcon} from '@sanity/icons' 2 | import type {StructureBuilder, StructureResolver} from 'sanity/structure' 3 | import pluralize from 'pluralize-esm' 4 | 5 | /** 6 | * Structure builder is useful whenever you want to control how documents are grouped and 7 | * listed in the studio or for adding additional in-studio previews or content to documents. 8 | * Learn more: https://www.sanity.io/docs/structure-builder-introduction 9 | */ 10 | 11 | const DISABLED_TYPES = ['settings', 'assist.instruction.context'] 12 | 13 | export const structure: StructureResolver = (S: StructureBuilder) => 14 | S.list() 15 | .title('Website Content') 16 | .items([ 17 | ...S.documentTypeListItems() 18 | // Remove the "assist.instruction.context" and "settings" content from the list of content types 19 | .filter((listItem: any) => !DISABLED_TYPES.includes(listItem.getId())) 20 | // Pluralize the title of each document type. This is not required but just an option to consider. 21 | .map((listItem) => { 22 | return listItem.title(pluralize(listItem.getTitle() as string)) 23 | }), 24 | // Settings Singleton in order to view/edit the one particular document for Settings. Learn more about Singletons: https://www.sanity.io/docs/create-a-link-to-a-single-edit-page-in-your-main-document-type-list 25 | S.listItem() 26 | .title('Site Settings') 27 | .child(S.document().schemaType('settings').documentId('siteSettings')) 28 | .icon(CogIcon), 29 | ]) 30 | -------------------------------------------------------------------------------- /.github/workflows/prettier.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Prettier 3 | 4 | on: 5 | push: 6 | branches: [main] 7 | workflow_dispatch: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 11 | cancel-in-progress: true 12 | 13 | permissions: 14 | contents: read # for checkout 15 | 16 | jobs: 17 | run: 18 | name: Can the code be prettier? 🤔 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: pnpm/action-setup@v4 23 | - uses: actions/setup-node@v4 24 | with: 25 | cache: pnpm 26 | node-version: lts/* 27 | - run: pnpm install --dev --ignore-scripts 28 | - uses: actions/cache@v4 29 | with: 30 | path: node_modules/.cache/prettier/.prettier-cache 31 | key: prettier-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('.prettierignore') }}-${{ hashFiles('package.json') }} 32 | - run: pnpm format 33 | - run: git restore .github/workflows pnpm-lock.yaml 34 | - uses: actions/create-github-app-token@v1 35 | id: generate-token 36 | with: 37 | app-id: ${{ secrets.ECOSPARK_APP_ID }} 38 | private-key: ${{ secrets.ECOSPARK_APP_PRIVATE_KEY }} 39 | - uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7 40 | with: 41 | body: I ran `pnpm format` 🧑‍💻 42 | branch: actions/prettier 43 | commit-message: 'chore(prettier): 🤖 ✨' 44 | labels: 🤖 bot 45 | sign-commits: true 46 | title: 'chore(prettier): 🤖 ✨' 47 | token: ${{ steps.generate-token.outputs.token }} 48 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/objects/callToAction.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {BulbOutlineIcon} from '@sanity/icons' 3 | 4 | /** 5 | * Call to action schema object. Objects are reusable schema structures document. 6 | * Learn more: https://www.sanity.io/docs/object-type 7 | */ 8 | 9 | export const callToAction = defineType({ 10 | name: 'callToAction', 11 | title: 'Call to Action', 12 | type: 'object', 13 | icon: BulbOutlineIcon, 14 | validation: (Rule) => 15 | // This is a custom validation rule that requires both 'buttonText' and 'link' to be set, or neither to be set 16 | Rule.custom((fields) => { 17 | const {buttonText, link} = fields || {} 18 | if ((buttonText && link) || (!buttonText && !link)) { 19 | return true 20 | } 21 | return 'Both Button text and Button link must be set, or both must be empty' 22 | }), 23 | fields: [ 24 | defineField({ 25 | name: 'heading', 26 | title: 'Heading', 27 | type: 'string', 28 | validation: (Rule) => Rule.required(), 29 | }), 30 | defineField({ 31 | name: 'text', 32 | title: 'Text', 33 | type: 'text', 34 | }), 35 | defineField({ 36 | name: 'buttonText', 37 | title: 'Button text', 38 | type: 'string', 39 | }), 40 | defineField({ 41 | name: 'link', 42 | title: 'Button link', 43 | type: 'link', 44 | }), 45 | ], 46 | preview: { 47 | select: { 48 | title: 'heading', 49 | }, 50 | prepare(selection) { 51 | const {title} = selection 52 | 53 | return { 54 | title: title, 55 | subtitle: 'Call to Action', 56 | } 57 | }, 58 | }, 59 | }) 60 | -------------------------------------------------------------------------------- /frontend/sanity/queries.ts: -------------------------------------------------------------------------------- 1 | import { defineQuery } from "groq"; 2 | 3 | const linkReference = /* groq */ ` 4 | _type == "link" => { 5 | "page": page->slug.current, 6 | "post": post->slug.current 7 | } 8 | `; 9 | 10 | const linkFields = /* groq */ ` 11 | link { 12 | ..., 13 | ${linkReference} 14 | } 15 | `; 16 | 17 | export const postsQuery = 18 | defineQuery(`*[_type == "post"] | order(date desc, _updatedAt desc) { 19 | ... 20 | }`); 21 | export const somePostsQuery = defineQuery(/* groq */ ` 22 | *[_type == "post" && slug.current != $skip][0...$limit] | order(date desc, _updatedAt desc) { 23 | ... 24 | }`); 25 | export const postQuery = defineQuery(/* groq */ ` 26 | *[_type == "post" && defined(slug.current) && slug.current == $slug][0]{ 27 | ..., 28 | content[]{ 29 | ..., 30 | markDefs[]{ 31 | ..., 32 | _type == "link" => { 33 | "link": { 34 | ..., 35 | ${linkReference} 36 | } 37 | }, 38 | } 39 | }, 40 | "author": author->{..., "picture": picture.asset._ref} 41 | }`); 42 | 43 | export const pageQuery = defineQuery(/* groq */ ` 44 | *[_type == "page" && defined(slug.current) && slug.current == $slug][0]{ 45 | ..., 46 | "pageBuilder": pageBuilder[]{ 47 | ..., 48 | _type == "callToAction" => { 49 | ${linkFields}, 50 | }, 51 | _type == "infoSection" => { 52 | content[]{ 53 | ..., 54 | markDefs[]{ 55 | ..., 56 | _type == "link" => { 57 | "link": { 58 | ..., 59 | ${linkReference} 60 | } 61 | }, 62 | } 63 | } 64 | }, 65 | } 66 | }`); 67 | 68 | export const settingsQuery = defineQuery(/* groq */ ` 69 | *[_type == "settings"][0]{ 70 | title, 71 | description[]{ 72 | ..., 73 | markDefs[]{ 74 | ..., 75 | _type == "link" => { 76 | "link": { 77 | ..., 78 | ${linkReference} 79 | } 80 | }, 81 | } 82 | }, 83 | "ogImage": ogImage.asset->url 84 | }`); 85 | -------------------------------------------------------------------------------- /frontend/components/Toast.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 51 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/documents/person.ts: -------------------------------------------------------------------------------- 1 | import {UserIcon} from '@sanity/icons' 2 | import {defineField, defineType} from 'sanity' 3 | 4 | /** 5 | * Person schema. Define and edit the fields for the 'person' content type. 6 | * Learn more: https://www.sanity.io/docs/schema-types 7 | */ 8 | 9 | export const person = defineType({ 10 | name: 'person', 11 | title: 'Person', 12 | icon: UserIcon, 13 | type: 'document', 14 | fields: [ 15 | defineField({ 16 | name: 'firstName', 17 | title: 'First Name', 18 | type: 'string', 19 | validation: (rule) => rule.required(), 20 | }), 21 | defineField({ 22 | name: 'lastName', 23 | title: 'Last Name', 24 | type: 'string', 25 | validation: (rule) => rule.required(), 26 | }), 27 | defineField({ 28 | name: 'picture', 29 | title: 'Picture', 30 | type: 'image', 31 | fields: [ 32 | defineField({ 33 | name: 'alt', 34 | type: 'string', 35 | title: 'Alternative text', 36 | description: 'Important for SEO and accessibility.', 37 | validation: (rule) => { 38 | // Custom validation to ensure alt text is provided if the image is present. https://www.sanity.io/docs/validation 39 | return rule.custom((alt, context) => { 40 | if ((context.document?.picture as any)?.asset?._ref && !alt) { 41 | return 'Required' 42 | } 43 | return true 44 | }) 45 | }, 46 | }), 47 | ], 48 | options: { 49 | hotspot: true, 50 | aiAssist: { 51 | imageDescriptionField: 'alt', 52 | }, 53 | }, 54 | validation: (rule) => rule.required(), 55 | }), 56 | ], 57 | // List preview configuration. https://www.sanity.io/docs/previews-list-views 58 | preview: { 59 | select: { 60 | firstName: 'firstName', 61 | lastName: 'lastName', 62 | picture: 'picture', 63 | }, 64 | prepare(selection) { 65 | return { 66 | title: `${selection.firstName} ${selection.lastName}`, 67 | subtitle: 'Person', 68 | media: selection.picture, 69 | } 70 | }, 71 | }, 72 | }) 73 | -------------------------------------------------------------------------------- /frontend/components/GetStartedCode.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 51 | -------------------------------------------------------------------------------- /frontend/pages/[slug].vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 62 | -------------------------------------------------------------------------------- /frontend/pages/posts/[slug].vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 69 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/documents/page.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {DocumentIcon} from '@sanity/icons' 3 | 4 | /** 5 | * Page schema. Define and edit the fields for the 'page' content type. 6 | * Learn more: https://www.sanity.io/docs/schema-types 7 | */ 8 | 9 | export const page = defineType({ 10 | name: 'page', 11 | title: 'Page', 12 | type: 'document', 13 | icon: DocumentIcon, 14 | groups: [ 15 | { 16 | name: 'content', 17 | title: 'Content', 18 | }, 19 | { 20 | name: 'seo', 21 | title: 'SEO', 22 | }, 23 | ], 24 | fields: [ 25 | // Content fields 26 | defineField({ 27 | name: 'name', 28 | title: 'Name', 29 | type: 'string', 30 | validation: (Rule) => Rule.required(), 31 | group: 'content', 32 | }), 33 | 34 | defineField({ 35 | name: 'slug', 36 | title: 'Slug', 37 | type: 'slug', 38 | validation: (Rule) => Rule.required(), 39 | options: { 40 | source: 'name', 41 | maxLength: 96, 42 | }, 43 | group: 'content', 44 | }), 45 | defineField({ 46 | name: 'heading', 47 | title: 'Heading', 48 | type: 'string', 49 | validation: (Rule) => Rule.required(), 50 | group: 'content', 51 | }), 52 | defineField({ 53 | name: 'subheading', 54 | title: 'Subheading', 55 | type: 'string', 56 | group: 'content', 57 | }), 58 | defineField({ 59 | name: 'pageBuilder', 60 | title: 'Page builder', 61 | type: 'array', 62 | of: [{type: 'callToAction'}, {type: 'infoSection'}], 63 | options: { 64 | insertMenu: { 65 | // Configure the "Add Item" menu to display a thumbnail preview of the content type. https://www.sanity.io/docs/array-type#efb1fe03459d 66 | views: [ 67 | { 68 | name: 'grid', 69 | previewImageUrl: (schemaTypeName) => 70 | `/static/page-builder-thumbnails/${schemaTypeName}.webp`, 71 | }, 72 | ], 73 | }, 74 | }, 75 | group: 'content', 76 | }), 77 | 78 | // SEO fields 79 | defineField({ 80 | name: 'seoTitle', 81 | title: 'SEO Title', 82 | type: 'string', 83 | description: 84 | 'Title used for search engines and social media sharing (recommended: 50-60 characters)', 85 | group: 'seo', 86 | }), 87 | defineField({ 88 | name: 'seoDescription', 89 | title: 'SEO Description', 90 | type: 'text', 91 | description: 92 | 'Description used for search engines and social media sharing (recommended: 150-160 characters)', 93 | group: 'seo', 94 | }), 95 | ], 96 | }) 97 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/objects/link.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {LinkIcon} from '@sanity/icons' 3 | 4 | /** 5 | * Link schema object. This link object lets the user first select the type of link and then 6 | * then enter the URL, page reference, or post reference - depending on the type selected. 7 | * Learn more: https://www.sanity.io/docs/object-type 8 | */ 9 | 10 | export const link = defineType({ 11 | name: 'link', 12 | title: 'Link', 13 | type: 'object', 14 | icon: LinkIcon, 15 | fields: [ 16 | defineField({ 17 | name: 'linkType', 18 | title: 'Link Type', 19 | type: 'string', 20 | initialValue: 'url', 21 | options: { 22 | list: [ 23 | {title: 'URL', value: 'href'}, 24 | {title: 'Page', value: 'page'}, 25 | {title: 'Post', value: 'post'}, 26 | ], 27 | layout: 'radio', 28 | }, 29 | }), 30 | defineField({ 31 | name: 'href', 32 | title: 'URL', 33 | type: 'url', 34 | hidden: ({parent}) => parent?.linkType !== 'href', 35 | validation: (Rule) => 36 | // Custom validation to ensure URL is provided if the link type is 'href' 37 | Rule.custom((value, context: any) => { 38 | if (context.parent?.linkType === 'href' && !value) { 39 | return 'URL is required when Link Type is URL' 40 | } 41 | return true 42 | }), 43 | }), 44 | defineField({ 45 | name: 'page', 46 | title: 'Page', 47 | type: 'reference', 48 | to: [{type: 'page'}], 49 | hidden: ({parent}) => parent?.linkType !== 'page', 50 | validation: (Rule) => 51 | // Custom validation to ensure page reference is provided if the link type is 'page' 52 | Rule.custom((value, context: any) => { 53 | if (context.parent?.linkType === 'page' && !value) { 54 | return 'Page reference is required when Link Type is Page' 55 | } 56 | return true 57 | }), 58 | }), 59 | defineField({ 60 | name: 'post', 61 | title: 'Post', 62 | type: 'reference', 63 | to: [{type: 'post'}], 64 | hidden: ({parent}) => parent?.linkType !== 'post', 65 | validation: (Rule) => 66 | // Custom validation to ensure post reference is provided if the link type is 'post' 67 | Rule.custom((value, context: any) => { 68 | if (context.parent?.linkType === 'post' && !value) { 69 | return 'Post reference is required when Link Type is Post' 70 | } 71 | return true 72 | }), 73 | }), 74 | defineField({ 75 | name: 'openInNewTab', 76 | title: 'Open in new tab', 77 | type: 'boolean', 78 | initialValue: false, 79 | }), 80 | ], 81 | }) 82 | -------------------------------------------------------------------------------- /frontend/components/Header.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 67 | -------------------------------------------------------------------------------- /frontend/components/SideBySideIcons.vue: -------------------------------------------------------------------------------- 1 | 55 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/objects/blockContent.tsx: -------------------------------------------------------------------------------- 1 | import {defineArrayMember, defineType, defineField} from 'sanity' 2 | 3 | /** 4 | * This is the schema definition for the rich text fields used for 5 | * for this blog studio. When you import it in schemas.js it can be 6 | * reused in other parts of the studio with: 7 | * { 8 | * name: 'someName', 9 | * title: 'Some title', 10 | * type: 'blockContent' 11 | * } 12 | * 13 | * Learn more: https://www.sanity.io/docs/block-content 14 | */ 15 | export const blockContent = defineType({ 16 | title: 'Block Content', 17 | name: 'blockContent', 18 | type: 'array', 19 | of: [ 20 | defineArrayMember({ 21 | type: 'block', 22 | marks: { 23 | annotations: [ 24 | { 25 | name: 'link', 26 | type: 'object', 27 | title: 'Link', 28 | fields: [ 29 | defineField({ 30 | name: 'linkType', 31 | title: 'Link Type', 32 | type: 'string', 33 | initialValue: 'href', 34 | options: { 35 | list: [ 36 | {title: 'URL', value: 'href'}, 37 | {title: 'Page', value: 'page'}, 38 | {title: 'Post', value: 'post'}, 39 | ], 40 | layout: 'radio', 41 | }, 42 | }), 43 | defineField({ 44 | name: 'href', 45 | title: 'URL', 46 | type: 'url', 47 | hidden: ({parent}) => parent?.linkType !== 'href' && parent?.linkType != null, 48 | validation: (Rule) => 49 | Rule.custom((value, context: any) => { 50 | if (context.parent?.linkType === 'href' && !value) { 51 | return 'URL is required when Link Type is URL' 52 | } 53 | return true 54 | }), 55 | }), 56 | defineField({ 57 | name: 'page', 58 | title: 'Page', 59 | type: 'reference', 60 | to: [{type: 'page'}], 61 | hidden: ({parent}) => parent?.linkType !== 'page', 62 | validation: (Rule) => 63 | Rule.custom((value, context: any) => { 64 | if (context.parent?.linkType === 'page' && !value) { 65 | return 'Page reference is required when Link Type is Page' 66 | } 67 | return true 68 | }), 69 | }), 70 | defineField({ 71 | name: 'post', 72 | title: 'Post', 73 | type: 'reference', 74 | to: [{type: 'post'}], 75 | hidden: ({parent}) => parent?.linkType !== 'post', 76 | validation: (Rule) => 77 | Rule.custom((value, context: any) => { 78 | if (context.parent?.linkType === 'post' && !value) { 79 | return 'Post reference is required when Link Type is Post' 80 | } 81 | return true 82 | }), 83 | }), 84 | defineField({ 85 | name: 'openInNewTab', 86 | title: 'Open in new tab', 87 | type: 'boolean', 88 | initialValue: false, 89 | }), 90 | ], 91 | }, 92 | ], 93 | }, 94 | }), 95 | ], 96 | }) 97 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/documents/post.ts: -------------------------------------------------------------------------------- 1 | import {DocumentTextIcon} from '@sanity/icons' 2 | import {format, parseISO} from 'date-fns' 3 | import {defineField, defineType} from 'sanity' 4 | 5 | /** 6 | * Post schema. Define and edit the fields for the 'post' content type. 7 | * Learn more: https://www.sanity.io/docs/schema-types 8 | */ 9 | 10 | export const post = defineType({ 11 | name: 'post', 12 | title: 'Post', 13 | icon: DocumentTextIcon, 14 | type: 'document', 15 | groups: [ 16 | { 17 | name: 'content', 18 | title: 'Content', 19 | }, 20 | { 21 | name: 'seo', 22 | title: 'SEO', 23 | }, 24 | ], 25 | fields: [ 26 | defineField({ 27 | name: 'title', 28 | title: 'Title', 29 | type: 'string', 30 | validation: (rule) => rule.required(), 31 | group: 'content', 32 | }), 33 | defineField({ 34 | name: 'slug', 35 | title: 'Slug', 36 | type: 'slug', 37 | description: 'A slug is required for the post to show up in the preview', 38 | options: { 39 | source: 'title', 40 | maxLength: 96, 41 | isUnique: (value, context) => context.defaultIsUnique(value, context), 42 | }, 43 | validation: (rule) => rule.required(), 44 | group: 'content', 45 | }), 46 | defineField({ 47 | name: 'content', 48 | title: 'Content', 49 | type: 'blockContent', 50 | group: 'content', 51 | }), 52 | defineField({ 53 | name: 'excerpt', 54 | title: 'Excerpt', 55 | type: 'text', 56 | group: 'content', 57 | }), 58 | defineField({ 59 | name: 'coverImage', 60 | title: 'Cover Image', 61 | type: 'image', 62 | options: { 63 | hotspot: true, 64 | aiAssist: { 65 | imageDescriptionField: 'alt', 66 | }, 67 | }, 68 | fields: [ 69 | { 70 | name: 'alt', 71 | type: 'string', 72 | title: 'Alternative text', 73 | description: 'Important for SEO and accessibility.', 74 | validation: (rule) => { 75 | // Custom validation to ensure alt text is provided if the image is present. https://www.sanity.io/docs/validation 76 | return rule.custom((alt, context) => { 77 | if ((context.document?.coverImage as any)?.asset?._ref && !alt) { 78 | return 'Required' 79 | } 80 | return true 81 | }) 82 | }, 83 | }, 84 | ], 85 | validation: (rule) => rule.required(), 86 | group: 'content', 87 | }), 88 | defineField({ 89 | name: 'date', 90 | title: 'Date', 91 | type: 'datetime', 92 | initialValue: () => new Date().toISOString(), 93 | group: 'content', 94 | }), 95 | defineField({ 96 | name: 'author', 97 | title: 'Author', 98 | type: 'reference', 99 | to: [{type: 'person'}], 100 | group: 'content', 101 | }), 102 | defineField({ 103 | name: 'seoTitle', 104 | title: 'SEO Title', 105 | type: 'string', 106 | description: 107 | 'Title used for search engines and social media sharing (recommended: 50-60 characters)', 108 | group: 'seo', 109 | }), 110 | defineField({ 111 | name: 'seoDescription', 112 | title: 'SEO Description', 113 | type: 'text', 114 | description: 115 | 'Description used for search engines and social media sharing (recommended: 150-160 characters)', 116 | group: 'seo', 117 | }), 118 | ], 119 | // List preview configuration. https://www.sanity.io/docs/previews-list-views 120 | preview: { 121 | select: { 122 | title: 'title', 123 | authorFirstName: 'author.firstName', 124 | authorLastName: 'author.lastName', 125 | date: 'date', 126 | media: 'coverImage', 127 | }, 128 | prepare({title, media, authorFirstName, authorLastName, date}) { 129 | const subtitles = [ 130 | authorFirstName && authorLastName && `by ${authorFirstName} ${authorLastName}`, 131 | date && `on ${format(parseISO(date), 'LLL d, yyyy')}`, 132 | ].filter(Boolean) 133 | 134 | return {title, media, subtitle: subtitles.join(' ')} 135 | }, 136 | }, 137 | }) 138 | -------------------------------------------------------------------------------- /frontend/assets/css/main.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @plugin "@tailwindcss/typography"; 4 | 5 | @utility container { 6 | margin: 0 auto; 7 | padding: 0 2rem; 8 | } 9 | 10 | @theme { 11 | --shadow-layer: 0 35px 60px -15px rgba(0, 0, 0, 0.3); 12 | 13 | --color-nuxt: #00dc82; 14 | 15 | --color-black: #0d0e12; 16 | --color-white: #fff; 17 | --color-cyan-50: #e7fefe; 18 | --color-cyan-100: #c5fcfc; 19 | --color-cyan-200: #96f8f8; 20 | --color-cyan-300: #62efef; 21 | --color-cyan-400: #18e2e2; 22 | --color-cyan-500: #04b8be; 23 | --color-cyan-600: #037782; 24 | --color-cyan-700: #024950; 25 | --color-cyan-800: #042f34; 26 | --color-cyan-900: #072227; 27 | --color-cyan-950: #0d181c; 28 | --color-gray-50: #f6f6f8; 29 | --color-gray-100: #eeeef1; 30 | --color-gray-200: #e3e4e8; 31 | --color-gray-300: #bbbdc9; 32 | --color-gray-400: #9499ad; 33 | --color-gray-500: #727892; 34 | --color-gray-600: #515870; 35 | --color-gray-700: #383d51; 36 | --color-gray-800: #252837; 37 | --color-gray-900: #1b1d27; 38 | --color-gray-950: #13141b; 39 | --color-blue-50: #e8f0fc; 40 | --color-blue-100: #d2e2fa; 41 | --color-blue-200: #a5c5f6; 42 | --color-blue-300: #79a8f1; 43 | --color-blue-400: #4c8bed; 44 | --color-blue-500: #206ee9; 45 | --color-blue-600: #1c5bbe; 46 | --color-blue-700: #194892; 47 | --color-blue-800: #163668; 48 | --color-blue-900: #13233c; 49 | --color-blue-950: #111a27; 50 | --color-purple-50: #f8f5ff; 51 | --color-purple-100: #f1ebff; 52 | --color-purple-200: #ece1fe; 53 | --color-purple-300: #ccb1fc; 54 | --color-purple-400: #b087f7; 55 | --color-purple-500: #8f57ef; 56 | --color-purple-600: #721fe5; 57 | --color-purple-700: #4c1a9e; 58 | --color-purple-800: #2f1862; 59 | --color-purple-900: #23173f; 60 | --color-purple-950: #181128; 61 | --color-magenta-50: #fcebf5; 62 | --color-magenta-100: #f9d7eb; 63 | --color-magenta-200: #f4afd8; 64 | --color-magenta-300: #ef87c4; 65 | --color-magenta-400: #ea5fb1; 66 | --color-magenta-500: #e5389e; 67 | --color-magenta-600: #ba3082; 68 | --color-magenta-700: #8f2866; 69 | --color-magenta-800: #65204a; 70 | --color-magenta-900: #3a182d; 71 | --color-magenta-950: #25141f; 72 | --color-red-50: #fff6f5; 73 | --color-red-100: #ffe7e5; 74 | --color-red-200: #ffdedc; 75 | --color-red-300: #fdada5; 76 | --color-red-400: #f77769; 77 | --color-red-500: #ef4434; 78 | --color-red-600: #cc2819; 79 | --color-red-700: #8b2018; 80 | --color-red-800: #4d1714; 81 | --color-red-900: #321615; 82 | --color-red-950: #1e1011; 83 | --color-orange-50: #fcf1e8; 84 | --color-orange-100: #f9e3d2; 85 | --color-orange-200: #f4c7a6; 86 | --color-orange-300: #efab7a; 87 | --color-orange-400: #ea8f4e; 88 | --color-orange-500: #e57322; 89 | --color-orange-600: #ba5f1e; 90 | --color-orange-700: #8f4b1b; 91 | --color-orange-800: #653818; 92 | --color-orange-900: #3a2415; 93 | --color-orange-950: #251a13; 94 | --color-yellow-50: #fefae1; 95 | --color-yellow-100: #fcf3bb; 96 | --color-yellow-200: #f9e994; 97 | --color-yellow-300: #f7d455; 98 | --color-yellow-400: #f9bc15; 99 | --color-yellow-500: #d28a04; 100 | --color-yellow-600: #965908; 101 | --color-yellow-700: #653a0b; 102 | --color-yellow-800: #3b220c; 103 | --color-yellow-900: #271a11; 104 | --color-yellow-950: #181410; 105 | --color-green-50: #e7f9ed; 106 | --color-green-100: #d0f4dc; 107 | --color-green-200: #a1eaba; 108 | --color-green-300: #72e097; 109 | --color-green-400: #43d675; 110 | --color-green-500: #3ab564; 111 | --color-green-600: #329454; 112 | --color-green-700: #297343; 113 | --color-green-800: #215233; 114 | --color-green-900: #183122; 115 | --color-green-950: #14211a; 116 | 117 | --font-display: "Inter", "sans-serif"; 118 | --font-sans: "Inter", "sans-serif"; 119 | 120 | --animate-gradient: gradient 2s ease-in-out infinite; 121 | @keyframes gradient { 122 | 0%, 123 | 100% { 124 | background-position: 0% 50%; 125 | } 126 | 50% { 127 | background-position: 100% 50%; 128 | } 129 | } 130 | 131 | --default-transition-duration: 250ms; 132 | } 133 | 134 | @keyframes expandWidth { 135 | 0% { 136 | width: 0vw; 137 | opacity: 0%; 138 | } 139 | 50% { 140 | width: 40vw; 141 | opacity: 75%; 142 | } 143 | 100% { 144 | width: 25vw; 145 | opacity: 20%; 146 | } 147 | } 148 | 149 | .animate-width { 150 | animation: expandWidth 1s forwards; 151 | } 152 | -------------------------------------------------------------------------------- /frontend/pages/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 106 | -------------------------------------------------------------------------------- /studio/sanity.config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This config is used to configure your Sanity Studio. 3 | * Learn more: https://www.sanity.io/docs/configuration 4 | */ 5 | 6 | import {defineConfig} from 'sanity' 7 | import {structureTool} from 'sanity/structure' 8 | import {visionTool} from '@sanity/vision' 9 | import {schemaTypes} from './src/schemaTypes' 10 | import {structure} from './src/structure' 11 | // import {unsplashImageAsset} from 'sanity-plugin-asset-source-unsplash' 12 | import { 13 | presentationTool, 14 | defineDocuments, 15 | defineLocations, 16 | type DocumentLocation, 17 | } from 'sanity/presentation' 18 | import {assist} from '@sanity/assist' 19 | 20 | // Environment variables for project configuration 21 | const projectId = process.env.SANITY_STUDIO_PROJECT_ID || 'your-projectID' 22 | const dataset = process.env.SANITY_STUDIO_DATASET || 'production' 23 | 24 | // URL for preview functionality, defaults to localhost:3000 if not set 25 | const SANITY_STUDIO_PREVIEW_URL = process.env.SANITY_STUDIO_PREVIEW_URL || 'http://localhost:3000' 26 | 27 | // Define the home location for the presentation tool 28 | const homeLocation = { 29 | title: 'Home', 30 | href: '/', 31 | } satisfies DocumentLocation 32 | 33 | // resolveHref() is a convenience function that resolves the URL 34 | // path for different document types and used in the presentation tool. 35 | function resolveHref(documentType?: string, slug?: string): string | undefined { 36 | switch (documentType) { 37 | case 'post': 38 | return slug ? `/posts/${slug}` : undefined 39 | case 'page': 40 | return slug ? `/${slug}` : undefined 41 | default: 42 | console.warn('Invalid document type:', documentType) 43 | return undefined 44 | } 45 | } 46 | 47 | // Main Sanity configuration 48 | export default defineConfig({ 49 | name: 'default', 50 | title: 'Clean Nuxt + Sanity', 51 | 52 | projectId, 53 | dataset, 54 | 55 | plugins: [ 56 | // Presentation tool configuration for Visual Editing 57 | presentationTool({ 58 | previewUrl: { 59 | origin: SANITY_STUDIO_PREVIEW_URL, 60 | previewMode: { 61 | enable: '/preview/enable', 62 | disable: '/preview/disable', 63 | }, 64 | }, 65 | resolve: { 66 | // The Main Document Resolver API provides a method of resolving a main document from a given route or route pattern. https://www.sanity.io/docs/presentation-resolver-api#57720a5678d9 67 | mainDocuments: defineDocuments([ 68 | { 69 | route: '/:slug', 70 | filter: `_type == "page" && slug.current == $slug || _id == $slug`, 71 | }, 72 | { 73 | route: '/posts/:slug', 74 | filter: `_type == "post" && slug.current == $slug || _id == $slug`, 75 | }, 76 | ]), 77 | // Locations Resolver API allows you to define where data is being used in your application. https://www.sanity.io/docs/presentation-resolver-api#8d8bca7bfcd7 78 | locations: { 79 | settings: defineLocations({ 80 | locations: [homeLocation], 81 | message: 'This document is used on all pages', 82 | tone: 'positive', 83 | }), 84 | page: defineLocations({ 85 | select: { 86 | name: 'name', 87 | slug: 'slug.current', 88 | }, 89 | resolve: (doc) => ({ 90 | locations: [ 91 | { 92 | title: doc?.name || 'Untitled', 93 | href: resolveHref('page', doc?.slug)!, 94 | }, 95 | ], 96 | }), 97 | }), 98 | post: defineLocations({ 99 | select: { 100 | title: 'title', 101 | slug: 'slug.current', 102 | }, 103 | resolve: (doc) => ({ 104 | locations: [ 105 | { 106 | title: doc?.title || 'Untitled', 107 | href: resolveHref('post', doc?.slug)!, 108 | }, 109 | { 110 | title: 'Home', 111 | href: '/', 112 | } satisfies DocumentLocation, 113 | ].filter(Boolean) as DocumentLocation[], 114 | }), 115 | }), 116 | }, 117 | }, 118 | }), 119 | structureTool({ 120 | structure, // Custom studio structure configuration, imported from ./src/structure.ts 121 | }), 122 | // Additional plugins for enhanced functionality 123 | // unsplashImageAsset(), 124 | assist(), 125 | visionTool(), 126 | ], 127 | 128 | // Schema configuration, imported from ./src/schemaTypes/index.ts 129 | schema: { 130 | types: schemaTypes, 131 | }, 132 | }) 133 | -------------------------------------------------------------------------------- /studio/src/schemaTypes/singletons/settings.tsx: -------------------------------------------------------------------------------- 1 | import {CogIcon} from '@sanity/icons' 2 | import {defineArrayMember, defineField, defineType} from 'sanity' 3 | 4 | import * as demo from '../../lib/initialValues' 5 | 6 | /** 7 | * Settings schema Singleton. Singletons are single documents that are displayed not in a collection, handy for things like site settings and other global configurations. 8 | * Learn more: https://www.sanity.io/docs/create-a-link-to-a-single-edit-page-in-your-main-document-type-list 9 | */ 10 | 11 | export const settings = defineType({ 12 | name: 'settings', 13 | title: 'Settings', 14 | type: 'document', 15 | icon: CogIcon, 16 | fields: [ 17 | defineField({ 18 | name: 'title', 19 | description: 'Site title used in the Navigation Bar', 20 | title: 'Fallback SEOTitle', 21 | type: 'string', 22 | initialValue: demo.title, 23 | validation: (rule) => rule.required(), 24 | }), 25 | defineField({ 26 | name: 'description', 27 | description: 'Used on the Homepage', 28 | title: 'Description', 29 | type: 'array', 30 | initialValue: demo.description, 31 | of: [ 32 | // Define a minified block content field for the description. https://www.sanity.io/docs/block-content 33 | defineArrayMember({ 34 | type: 'block', 35 | options: {}, 36 | styles: [], 37 | lists: [], 38 | marks: { 39 | decorators: [], 40 | annotations: [ 41 | { 42 | name: 'link', 43 | type: 'object', 44 | title: 'Link', 45 | fields: [ 46 | defineField({ 47 | name: 'linkType', 48 | title: 'Link Type', 49 | type: 'string', 50 | initialValue: 'href', 51 | options: { 52 | list: [ 53 | {title: 'URL', value: 'href'}, 54 | {title: 'Page', value: 'page'}, 55 | {title: 'Post', value: 'post'}, 56 | ], 57 | layout: 'radio', 58 | }, 59 | }), 60 | defineField({ 61 | name: 'href', 62 | title: 'URL', 63 | type: 'url', 64 | hidden: ({parent}) => parent?.linkType !== 'href' && parent?.linkType != null, 65 | validation: (Rule) => 66 | Rule.custom((value, context: any) => { 67 | if (context.parent?.linkType === 'href' && !value) { 68 | return 'URL is required when Link Type is URL' 69 | } 70 | return true 71 | }), 72 | }), 73 | defineField({ 74 | name: 'page', 75 | title: 'Page', 76 | type: 'reference', 77 | to: [{type: 'page'}], 78 | hidden: ({parent}) => parent?.linkType !== 'page', 79 | validation: (Rule) => 80 | Rule.custom((value, context: any) => { 81 | if (context.parent?.linkType === 'page' && !value) { 82 | return 'Page reference is required when Link Type is Page' 83 | } 84 | return true 85 | }), 86 | }), 87 | defineField({ 88 | name: 'post', 89 | title: 'Post', 90 | type: 'reference', 91 | to: [{type: 'post'}], 92 | hidden: ({parent}) => parent?.linkType !== 'post', 93 | validation: (Rule) => 94 | Rule.custom((value, context: any) => { 95 | if (context.parent?.linkType === 'post' && !value) { 96 | return 'Post reference is required when Link Type is Post' 97 | } 98 | return true 99 | }), 100 | }), 101 | defineField({ 102 | name: 'openInNewTab', 103 | title: 'Open in new tab', 104 | type: 'boolean', 105 | initialValue: false, 106 | }), 107 | ], 108 | }, 109 | ], 110 | }, 111 | }), 112 | ], 113 | }), 114 | defineField({ 115 | name: 'ogImage', 116 | title: 'Open Graph Image', 117 | type: 'image', 118 | description: 119 | 'Displayed on social cards and search engine results. Used everywhere unless overwritten.', 120 | options: { 121 | hotspot: true, 122 | aiAssist: { 123 | imageDescriptionField: 'alt', 124 | }, 125 | }, 126 | }), 127 | ], 128 | preview: { 129 | prepare() { 130 | return { 131 | title: 'Settings', 132 | } 133 | }, 134 | }, 135 | }) 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clean Nuxt + Sanity app 2 | 3 | This template includes a [Nuxt](https://nuxt.com/) app with a [Sanity Studio](https://www.sanity.io/) – an open-source Vue application that connects to your Sanity project's hosted dataset. The Studio is configured locally and can then be deployed for content collaboration. 4 | 5 | ![Screenshot of Sanity Studio using Presentation Tool to do Visual Editing](./nuxt-sanity-preview.webp) 6 | 7 | ## Features 8 | 9 | - **Nuxt 3 for Performance:** Leverage the power of Nuxt 3's hybrid rendering capabilities for blazing-fast performance and SEO-friendly applications. 10 | - **Real-time Previews:** Edit content live with Sanity's [Presentation Tool](https://www.sanity.io/docs/presentation) and see updates in real time. 11 | - **Powerful Content Management:** Collaborate with team members in real-time, with fine-grained revision history. 12 | - **AI-powered Media Support:** Auto-generate alt text with [Sanity AI Assist](https://www.sanity.io/ai-assist). (Available on Free Trial and Growth Tiers. [See Pricing](https://www.sanity.io/pricing)) 13 | - **Flexible Rendering Strategies:** Choose between Server-Side Rendering (SSR), Static Site Generation (SSG), or hybrid rendering at the route level. 14 | - **Easy Media Management:** [Integrated Unsplash support](https://www.sanity.io/plugins/sanity-plugin-asset-source-unsplash) for seamless media handling. 15 | 16 | ## Demo 17 | 18 | https://template-nuxt-clean.sanity.dev 19 | 20 | ## Getting Started 21 | 22 | ### Installing the template 23 | 24 | #### 1. Initialize template with Sanity CLI 25 | 26 | Run the command in your Terminal to initialize this template on your local computer. 27 | 28 | See the documentation if you are [having issues with the CLI](https://www.sanity.io/help/cli-errors). 29 | 30 | ```shell 31 | npm create sanity@latest -- --template sanity-io/sanity-template-nuxt-clean 32 | ``` 33 | 34 | (ToDo: update script when merging) 35 | 36 | #### 2. Run Studio and Nuxt app locally 37 | 38 | Navigate to the template directory using `cd `, and start the development servers by running the following command 39 | 40 | ```shell 41 | npm run dev 42 | ``` 43 | 44 | #### 3. Open the app and sign in to the Studio 45 | 46 | Open the Nuxt app running locally in your browser on [http://localhost:3000](http://localhost:3000). 47 | 48 | Open the Studio running locally in your browser on [http://localhost:3333](http://localhost:3333). You should now see a screen prompting you to log in to the Studio. Use the same service (Google, GitHub, or email) that you used when you logged in to the CLI. 49 | 50 | ### Adding content with Sanity 51 | 52 | #### 1. Publish your first document 53 | 54 | The template comes pre-defined with a schema containing `Page`, `Post`, `Person`, and `Settings` document types. 55 | 56 | From the Studio, click "+ Create" and select the `Post` document type. Go ahead and create and publish the document. 57 | 58 | Your content should now appear in your Nuxt app ([http://localhost:3000](http://localhost:3000)) as well as in the Studio on the "Presentation" Tab 59 | 60 | #### 2. Import Sample Data (optional) 61 | 62 | You may want to start with some sample content and we've got you covered. Run this command from the root of your project to import the provided dataset (sample-data.tar.gz) into your Sanity project. This step is optional but can be helpful for getting started quickly. 63 | 64 | ```shell 65 | npm run import-sample-data 66 | ``` 67 | 68 | #### 3. Extending the Sanity schema 69 | 70 | The schema for the `Post` document type is defined in the `studio/src/schemaTypes/post.ts` file. You can [add more document types](https://www.sanity.io/docs/schema-types) to the schema to suit your needs. 71 | 72 | ### Deploying your application and inviting editors 73 | 74 | #### 1. Deploy Sanity Studio 75 | 76 | Your Nuxt frontend (`/frontend`) and Sanity Studio (`/studio`) are still only running on your local computer. It's time to deploy and get it into the hands of other content editors. 77 | 78 | Back in your Studio directory (`/studio`), run the following command to deploy your Sanity Studio. 79 | 80 | ```shell 81 | npx sanity deploy 82 | ``` 83 | 84 | #### 2. Deploy Nuxt app 85 | 86 | You have the freedom to deploy your Nuxt app to your hosting provider of choice. Nuxt applications can be deployed to various platforms including Vercel, Netlify, or any platform that supports Node.js or edge runtime. 87 | 88 | 1. Create a GitHub repository from this project. [Learn more](https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github). 89 | 2. Choose your preferred hosting platform and follow their deployment guides for Nuxt applications. 90 | 3. Configure your Environment Variables as needed. 91 | 92 | For detailed deployment instructions, visit the [Nuxt deployment documentation](https://nuxt.com/docs/getting-started/deployment). 93 | 94 | #### 3. Invite a collaborator 95 | 96 | Now that you've deployed your Nuxt application and Sanity Studio, you can optionally invite a collaborator to your Studio. Open up [Manage](https://www.sanity.io/manage), select your project and click "Invite project members" 97 | 98 | They will be able to access the deployed Studio, where you can collaborate together on creating content. 99 | 100 | ## Resources 101 | 102 | - [Sanity documentation](https://www.sanity.io/docs) 103 | - [Nuxt documentation](https://nuxt.com/docs) 104 | - [Join the Sanity Community](https://slack.sanity.io) 105 | - [Learn Sanity](https://www.sanity.io/learn) 106 | -------------------------------------------------------------------------------- /studio/sanity.types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------------------------------------------------------------- 3 | * This file has been generated by Sanity TypeGen. 4 | * Command: `sanity typegen generate` 5 | * 6 | * Any modifications made directly to this file will be overwritten the next time 7 | * the TypeScript definitions are generated. Please make changes to the Sanity 8 | * schema definitions and/or GROQ queries if you need to update these types. 9 | * 10 | * For more information on how to use Sanity TypeGen, visit the official documentation: 11 | * https://www.sanity.io/docs/sanity-typegen 12 | * --------------------------------------------------------------------------------- 13 | */ 14 | 15 | // Source: schema.json 16 | export type SanityImagePaletteSwatch = { 17 | _type: 'sanity.imagePaletteSwatch' 18 | background?: string 19 | foreground?: string 20 | population?: number 21 | title?: string 22 | } 23 | 24 | export type SanityImagePalette = { 25 | _type: 'sanity.imagePalette' 26 | darkMuted?: SanityImagePaletteSwatch 27 | lightVibrant?: SanityImagePaletteSwatch 28 | darkVibrant?: SanityImagePaletteSwatch 29 | vibrant?: SanityImagePaletteSwatch 30 | dominant?: SanityImagePaletteSwatch 31 | lightMuted?: SanityImagePaletteSwatch 32 | muted?: SanityImagePaletteSwatch 33 | } 34 | 35 | export type SanityImageDimensions = { 36 | _type: 'sanity.imageDimensions' 37 | height?: number 38 | width?: number 39 | aspectRatio?: number 40 | } 41 | 42 | export type SanityFileAsset = { 43 | _id: string 44 | _type: 'sanity.fileAsset' 45 | _createdAt: string 46 | _updatedAt: string 47 | _rev: string 48 | originalFilename?: string 49 | label?: string 50 | title?: string 51 | description?: string 52 | altText?: string 53 | sha1hash?: string 54 | extension?: string 55 | mimeType?: string 56 | size?: number 57 | assetId?: string 58 | uploadId?: string 59 | path?: string 60 | url?: string 61 | source?: SanityAssetSourceData 62 | } 63 | 64 | export type Geopoint = { 65 | _type: 'geopoint' 66 | lat?: number 67 | lng?: number 68 | alt?: number 69 | } 70 | 71 | export type CallToAction = { 72 | _type: 'callToAction' 73 | heading: string 74 | text?: string 75 | buttonText?: string 76 | link?: Link 77 | } 78 | 79 | export type Link = { 80 | _type: 'link' 81 | linkType?: 'href' | 'page' | 'post' 82 | href?: string 83 | page?: { 84 | _ref: string 85 | _type: 'reference' 86 | _weak?: boolean 87 | [internalGroqTypeReferenceTo]?: 'page' 88 | } 89 | post?: { 90 | _ref: string 91 | _type: 'reference' 92 | _weak?: boolean 93 | [internalGroqTypeReferenceTo]?: 'post' 94 | } 95 | openInNewTab?: boolean 96 | } 97 | 98 | export type InfoSection = { 99 | _type: 'infoSection' 100 | heading?: string 101 | subheading?: string 102 | content?: Array<{ 103 | children?: Array<{ 104 | marks?: Array 105 | text?: string 106 | _type: 'span' 107 | _key: string 108 | }> 109 | style?: 'normal' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote' 110 | listItem?: 'bullet' | 'number' 111 | markDefs?: Array<{ 112 | linkType?: 'href' | 'page' | 'post' 113 | href?: string 114 | page?: { 115 | _ref: string 116 | _type: 'reference' 117 | _weak?: boolean 118 | [internalGroqTypeReferenceTo]?: 'page' 119 | } 120 | post?: { 121 | _ref: string 122 | _type: 'reference' 123 | _weak?: boolean 124 | [internalGroqTypeReferenceTo]?: 'post' 125 | } 126 | openInNewTab?: boolean 127 | _type: 'link' 128 | _key: string 129 | }> 130 | level?: number 131 | _type: 'block' 132 | _key: string 133 | }> 134 | } 135 | 136 | export type BlockContent = Array<{ 137 | children?: Array<{ 138 | marks?: Array 139 | text?: string 140 | _type: 'span' 141 | _key: string 142 | }> 143 | style?: 'normal' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote' 144 | listItem?: 'bullet' | 'number' 145 | markDefs?: Array<{ 146 | linkType?: 'href' | 'page' | 'post' 147 | href?: string 148 | page?: { 149 | _ref: string 150 | _type: 'reference' 151 | _weak?: boolean 152 | [internalGroqTypeReferenceTo]?: 'page' 153 | } 154 | post?: { 155 | _ref: string 156 | _type: 'reference' 157 | _weak?: boolean 158 | [internalGroqTypeReferenceTo]?: 'post' 159 | } 160 | openInNewTab?: boolean 161 | _type: 'link' 162 | _key: string 163 | }> 164 | level?: number 165 | _type: 'block' 166 | _key: string 167 | }> 168 | 169 | export type Page = { 170 | _id: string 171 | _type: 'page' 172 | _createdAt: string 173 | _updatedAt: string 174 | _rev: string 175 | name: string 176 | slug: Slug 177 | heading: string 178 | subheading?: string 179 | pageBuilder?: Array< 180 | | ({ 181 | _key: string 182 | } & CallToAction) 183 | | ({ 184 | _key: string 185 | } & InfoSection) 186 | > 187 | } 188 | 189 | export type Post = { 190 | _id: string 191 | _type: 'post' 192 | _createdAt: string 193 | _updatedAt: string 194 | _rev: string 195 | title: string 196 | slug: Slug 197 | content?: BlockContent 198 | excerpt?: string 199 | coverImage: { 200 | asset?: { 201 | _ref: string 202 | _type: 'reference' 203 | _weak?: boolean 204 | [internalGroqTypeReferenceTo]?: 'sanity.imageAsset' 205 | } 206 | hotspot?: SanityImageHotspot 207 | crop?: SanityImageCrop 208 | alt?: string 209 | _type: 'image' 210 | } 211 | date?: string 212 | author?: { 213 | _ref: string 214 | _type: 'reference' 215 | _weak?: boolean 216 | [internalGroqTypeReferenceTo]?: 'person' 217 | } 218 | } 219 | 220 | export type Person = { 221 | _id: string 222 | _type: 'person' 223 | _createdAt: string 224 | _updatedAt: string 225 | _rev: string 226 | firstName: string 227 | lastName: string 228 | picture: { 229 | asset?: { 230 | _ref: string 231 | _type: 'reference' 232 | _weak?: boolean 233 | [internalGroqTypeReferenceTo]?: 'sanity.imageAsset' 234 | } 235 | hotspot?: SanityImageHotspot 236 | crop?: SanityImageCrop 237 | alt?: string 238 | _type: 'image' 239 | } 240 | } 241 | 242 | export type Slug = { 243 | _type: 'slug' 244 | current: string 245 | source?: string 246 | } 247 | 248 | export type Settings = { 249 | _id: string 250 | _type: 'settings' 251 | _createdAt: string 252 | _updatedAt: string 253 | _rev: string 254 | title: string 255 | description?: Array<{ 256 | children?: Array<{ 257 | marks?: Array 258 | text?: string 259 | _type: 'span' 260 | _key: string 261 | }> 262 | style?: 'normal' 263 | listItem?: never 264 | markDefs?: Array<{ 265 | href: string 266 | _type: 'link' 267 | _key: string 268 | }> 269 | level?: number 270 | _type: 'block' 271 | _key: string 272 | }> 273 | ogImage?: { 274 | asset?: { 275 | _ref: string 276 | _type: 'reference' 277 | _weak?: boolean 278 | [internalGroqTypeReferenceTo]?: 'sanity.imageAsset' 279 | } 280 | hotspot?: SanityImageHotspot 281 | crop?: SanityImageCrop 282 | alt?: string 283 | metadataBase?: string 284 | _type: 'image' 285 | } 286 | } 287 | 288 | export type SanityImageCrop = { 289 | _type: 'sanity.imageCrop' 290 | top?: number 291 | bottom?: number 292 | left?: number 293 | right?: number 294 | } 295 | 296 | export type SanityImageHotspot = { 297 | _type: 'sanity.imageHotspot' 298 | x?: number 299 | y?: number 300 | height?: number 301 | width?: number 302 | } 303 | 304 | export type SanityImageAsset = { 305 | _id: string 306 | _type: 'sanity.imageAsset' 307 | _createdAt: string 308 | _updatedAt: string 309 | _rev: string 310 | originalFilename?: string 311 | label?: string 312 | title?: string 313 | description?: string 314 | altText?: string 315 | sha1hash?: string 316 | extension?: string 317 | mimeType?: string 318 | size?: number 319 | assetId?: string 320 | uploadId?: string 321 | path?: string 322 | url?: string 323 | metadata?: SanityImageMetadata 324 | source?: SanityAssetSourceData 325 | } 326 | 327 | export type SanityAssetSourceData = { 328 | _type: 'sanity.assetSourceData' 329 | name?: string 330 | id?: string 331 | url?: string 332 | } 333 | 334 | export type SanityImageMetadata = { 335 | _type: 'sanity.imageMetadata' 336 | location?: Geopoint 337 | dimensions?: SanityImageDimensions 338 | palette?: SanityImagePalette 339 | lqip?: string 340 | blurHash?: string 341 | hasAlpha?: boolean 342 | isOpaque?: boolean 343 | } 344 | 345 | export type SanityAssistInstructionTask = { 346 | _type: 'sanity.assist.instructionTask' 347 | path?: string 348 | instructionKey?: string 349 | started?: string 350 | updated?: string 351 | info?: string 352 | } 353 | 354 | export type SanityAssistTaskStatus = { 355 | _type: 'sanity.assist.task.status' 356 | tasks?: Array< 357 | { 358 | _key: string 359 | } & SanityAssistInstructionTask 360 | > 361 | } 362 | 363 | export type SanityAssistSchemaTypeAnnotations = { 364 | _type: 'sanity.assist.schemaType.annotations' 365 | title?: string 366 | fields?: Array< 367 | { 368 | _key: string 369 | } & SanityAssistSchemaTypeField 370 | > 371 | } 372 | 373 | export type SanityAssistOutputType = { 374 | _type: 'sanity.assist.output.type' 375 | type?: string 376 | } 377 | 378 | export type SanityAssistOutputField = { 379 | _type: 'sanity.assist.output.field' 380 | path?: string 381 | } 382 | 383 | export type SanityAssistInstructionContext = { 384 | _type: 'sanity.assist.instruction.context' 385 | reference: { 386 | _ref: string 387 | _type: 'reference' 388 | _weak?: boolean 389 | [internalGroqTypeReferenceTo]?: 'assist.instruction.context' 390 | } 391 | } 392 | 393 | export type AssistInstructionContext = { 394 | _id: string 395 | _type: 'assist.instruction.context' 396 | _createdAt: string 397 | _updatedAt: string 398 | _rev: string 399 | title?: string 400 | context?: Array<{ 401 | children?: Array<{ 402 | marks?: Array 403 | text?: string 404 | _type: 'span' 405 | _key: string 406 | }> 407 | style?: 'normal' 408 | listItem?: never 409 | markDefs?: null 410 | level?: number 411 | _type: 'block' 412 | _key: string 413 | }> 414 | } 415 | 416 | export type SanityAssistInstructionUserInput = { 417 | _type: 'sanity.assist.instruction.userInput' 418 | message: string 419 | description?: string 420 | } 421 | 422 | export type SanityAssistInstructionPrompt = Array<{ 423 | children?: Array< 424 | | { 425 | marks?: Array 426 | text?: string 427 | _type: 'span' 428 | _key: string 429 | } 430 | | ({ 431 | _key: string 432 | } & SanityAssistInstructionFieldRef) 433 | | ({ 434 | _key: string 435 | } & SanityAssistInstructionContext) 436 | | ({ 437 | _key: string 438 | } & SanityAssistInstructionUserInput) 439 | > 440 | style?: 'normal' 441 | listItem?: never 442 | markDefs?: null 443 | level?: number 444 | _type: 'block' 445 | _key: string 446 | }> 447 | 448 | export type SanityAssistInstructionFieldRef = { 449 | _type: 'sanity.assist.instruction.fieldRef' 450 | path?: string 451 | } 452 | 453 | export type SanityAssistInstruction = { 454 | _type: 'sanity.assist.instruction' 455 | prompt?: SanityAssistInstructionPrompt 456 | icon?: string 457 | title?: string 458 | userId?: string 459 | createdById?: string 460 | output?: Array< 461 | | ({ 462 | _key: string 463 | } & SanityAssistOutputField) 464 | | ({ 465 | _key: string 466 | } & SanityAssistOutputType) 467 | > 468 | } 469 | 470 | export type SanityAssistSchemaTypeField = { 471 | _type: 'sanity.assist.schemaType.field' 472 | path?: string 473 | instructions?: Array< 474 | { 475 | _key: string 476 | } & SanityAssistInstruction 477 | > 478 | } 479 | 480 | export type AllSanitySchemaTypes = 481 | | SanityImagePaletteSwatch 482 | | SanityImagePalette 483 | | SanityImageDimensions 484 | | SanityFileAsset 485 | | Geopoint 486 | | CallToAction 487 | | Link 488 | | InfoSection 489 | | BlockContent 490 | | Page 491 | | Post 492 | | Person 493 | | Slug 494 | | Settings 495 | | SanityImageCrop 496 | | SanityImageHotspot 497 | | SanityImageAsset 498 | | SanityAssetSourceData 499 | | SanityImageMetadata 500 | | SanityAssistInstructionTask 501 | | SanityAssistTaskStatus 502 | | SanityAssistSchemaTypeAnnotations 503 | | SanityAssistOutputType 504 | | SanityAssistOutputField 505 | | SanityAssistInstructionContext 506 | | AssistInstructionContext 507 | | SanityAssistInstructionUserInput 508 | | SanityAssistInstructionPrompt 509 | | SanityAssistInstructionFieldRef 510 | | SanityAssistInstruction 511 | | SanityAssistSchemaTypeField 512 | export declare const internalGroqTypeReferenceTo: unique symbol 513 | -------------------------------------------------------------------------------- /frontend/sanity/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------------------------------------------------------------- 3 | * This file has been generated by Sanity TypeGen. 4 | * Command: `sanity typegen generate` 5 | * 6 | * Any modifications made directly to this file will be overwritten the next time 7 | * the TypeScript definitions are generated. Please make changes to the Sanity 8 | * schema definitions and/or GROQ queries if you need to update these types. 9 | * 10 | * For more information on how to use Sanity TypeGen, visit the official documentation: 11 | * https://www.sanity.io/docs/sanity-typegen 12 | * --------------------------------------------------------------------------------- 13 | */ 14 | 15 | // Source: schema.json 16 | export type SanityImagePaletteSwatch = { 17 | _type: "sanity.imagePaletteSwatch"; 18 | background?: string; 19 | foreground?: string; 20 | population?: number; 21 | title?: string; 22 | }; 23 | 24 | export type SanityImagePalette = { 25 | _type: "sanity.imagePalette"; 26 | darkMuted?: SanityImagePaletteSwatch; 27 | lightVibrant?: SanityImagePaletteSwatch; 28 | darkVibrant?: SanityImagePaletteSwatch; 29 | vibrant?: SanityImagePaletteSwatch; 30 | dominant?: SanityImagePaletteSwatch; 31 | lightMuted?: SanityImagePaletteSwatch; 32 | muted?: SanityImagePaletteSwatch; 33 | }; 34 | 35 | export type SanityImageDimensions = { 36 | _type: "sanity.imageDimensions"; 37 | height?: number; 38 | width?: number; 39 | aspectRatio?: number; 40 | }; 41 | 42 | export type SanityFileAsset = { 43 | _id: string; 44 | _type: "sanity.fileAsset"; 45 | _createdAt: string; 46 | _updatedAt: string; 47 | _rev: string; 48 | originalFilename?: string; 49 | label?: string; 50 | title?: string; 51 | description?: string; 52 | altText?: string; 53 | sha1hash?: string; 54 | extension?: string; 55 | mimeType?: string; 56 | size?: number; 57 | assetId?: string; 58 | uploadId?: string; 59 | path?: string; 60 | url?: string; 61 | source?: SanityAssetSourceData; 62 | }; 63 | 64 | export type Geopoint = { 65 | _type: "geopoint"; 66 | lat?: number; 67 | lng?: number; 68 | alt?: number; 69 | }; 70 | 71 | export type CallToAction = { 72 | _type: "callToAction"; 73 | heading: string; 74 | text?: string; 75 | buttonText?: string; 76 | link?: Link; 77 | }; 78 | 79 | export type Link = { 80 | _type: "link"; 81 | linkType?: "href" | "page" | "post"; 82 | href?: string; 83 | page?: { 84 | _ref: string; 85 | _type: "reference"; 86 | _weak?: boolean; 87 | [internalGroqTypeReferenceTo]?: "page"; 88 | }; 89 | post?: { 90 | _ref: string; 91 | _type: "reference"; 92 | _weak?: boolean; 93 | [internalGroqTypeReferenceTo]?: "post"; 94 | }; 95 | openInNewTab?: boolean; 96 | }; 97 | 98 | export type InfoSection = { 99 | _type: "infoSection"; 100 | heading?: string; 101 | subheading?: string; 102 | content?: Array<{ 103 | children?: Array<{ 104 | marks?: Array; 105 | text?: string; 106 | _type: "span"; 107 | _key: string; 108 | }>; 109 | style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote"; 110 | listItem?: "bullet" | "number"; 111 | markDefs?: Array<{ 112 | linkType?: "href" | "page" | "post"; 113 | href?: string; 114 | page?: { 115 | _ref: string; 116 | _type: "reference"; 117 | _weak?: boolean; 118 | [internalGroqTypeReferenceTo]?: "page"; 119 | }; 120 | post?: { 121 | _ref: string; 122 | _type: "reference"; 123 | _weak?: boolean; 124 | [internalGroqTypeReferenceTo]?: "post"; 125 | }; 126 | openInNewTab?: boolean; 127 | _type: "link"; 128 | _key: string; 129 | }>; 130 | level?: number; 131 | _type: "block"; 132 | _key: string; 133 | }>; 134 | }; 135 | 136 | export type BlockContent = Array<{ 137 | children?: Array<{ 138 | marks?: Array; 139 | text?: string; 140 | _type: "span"; 141 | _key: string; 142 | }>; 143 | style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote"; 144 | listItem?: "bullet" | "number"; 145 | markDefs?: Array<{ 146 | linkType?: "href" | "page" | "post"; 147 | href?: string; 148 | page?: { 149 | _ref: string; 150 | _type: "reference"; 151 | _weak?: boolean; 152 | [internalGroqTypeReferenceTo]?: "page"; 153 | }; 154 | post?: { 155 | _ref: string; 156 | _type: "reference"; 157 | _weak?: boolean; 158 | [internalGroqTypeReferenceTo]?: "post"; 159 | }; 160 | openInNewTab?: boolean; 161 | _type: "link"; 162 | _key: string; 163 | }>; 164 | level?: number; 165 | _type: "block"; 166 | _key: string; 167 | }>; 168 | 169 | export type Settings = { 170 | _id: string; 171 | _type: "settings"; 172 | _createdAt: string; 173 | _updatedAt: string; 174 | _rev: string; 175 | title: string; 176 | description?: Array<{ 177 | children?: Array<{ 178 | marks?: Array; 179 | text?: string; 180 | _type: "span"; 181 | _key: string; 182 | }>; 183 | style?: "normal"; 184 | listItem?: never; 185 | markDefs?: Array<{ 186 | linkType?: "href" | "page" | "post"; 187 | href?: string; 188 | page?: { 189 | _ref: string; 190 | _type: "reference"; 191 | _weak?: boolean; 192 | [internalGroqTypeReferenceTo]?: "page"; 193 | }; 194 | post?: { 195 | _ref: string; 196 | _type: "reference"; 197 | _weak?: boolean; 198 | [internalGroqTypeReferenceTo]?: "post"; 199 | }; 200 | openInNewTab?: boolean; 201 | _type: "link"; 202 | _key: string; 203 | }>; 204 | level?: number; 205 | _type: "block"; 206 | _key: string; 207 | }>; 208 | ogImage?: { 209 | asset?: { 210 | _ref: string; 211 | _type: "reference"; 212 | _weak?: boolean; 213 | [internalGroqTypeReferenceTo]?: "sanity.imageAsset"; 214 | }; 215 | hotspot?: SanityImageHotspot; 216 | crop?: SanityImageCrop; 217 | _type: "image"; 218 | }; 219 | }; 220 | 221 | export type Page = { 222 | _id: string; 223 | _type: "page"; 224 | _createdAt: string; 225 | _updatedAt: string; 226 | _rev: string; 227 | name: string; 228 | slug: Slug; 229 | heading: string; 230 | subheading?: string; 231 | pageBuilder?: Array<{ 232 | _key: string; 233 | } & CallToAction | { 234 | _key: string; 235 | } & InfoSection>; 236 | seoTitle?: string; 237 | seoDescription?: string; 238 | }; 239 | 240 | export type Post = { 241 | _id: string; 242 | _type: "post"; 243 | _createdAt: string; 244 | _updatedAt: string; 245 | _rev: string; 246 | title: string; 247 | slug: Slug; 248 | content?: BlockContent; 249 | excerpt?: string; 250 | coverImage: { 251 | asset?: { 252 | _ref: string; 253 | _type: "reference"; 254 | _weak?: boolean; 255 | [internalGroqTypeReferenceTo]?: "sanity.imageAsset"; 256 | }; 257 | hotspot?: SanityImageHotspot; 258 | crop?: SanityImageCrop; 259 | alt?: string; 260 | _type: "image"; 261 | }; 262 | date?: string; 263 | author?: { 264 | _ref: string; 265 | _type: "reference"; 266 | _weak?: boolean; 267 | [internalGroqTypeReferenceTo]?: "person"; 268 | }; 269 | seoTitle?: string; 270 | seoDescription?: string; 271 | }; 272 | 273 | export type Person = { 274 | _id: string; 275 | _type: "person"; 276 | _createdAt: string; 277 | _updatedAt: string; 278 | _rev: string; 279 | firstName: string; 280 | lastName: string; 281 | picture: { 282 | asset?: { 283 | _ref: string; 284 | _type: "reference"; 285 | _weak?: boolean; 286 | [internalGroqTypeReferenceTo]?: "sanity.imageAsset"; 287 | }; 288 | hotspot?: SanityImageHotspot; 289 | crop?: SanityImageCrop; 290 | alt?: string; 291 | _type: "image"; 292 | }; 293 | }; 294 | 295 | export type SanityImageCrop = { 296 | _type: "sanity.imageCrop"; 297 | top?: number; 298 | bottom?: number; 299 | left?: number; 300 | right?: number; 301 | }; 302 | 303 | export type SanityImageHotspot = { 304 | _type: "sanity.imageHotspot"; 305 | x?: number; 306 | y?: number; 307 | height?: number; 308 | width?: number; 309 | }; 310 | 311 | export type SanityImageAsset = { 312 | _id: string; 313 | _type: "sanity.imageAsset"; 314 | _createdAt: string; 315 | _updatedAt: string; 316 | _rev: string; 317 | originalFilename?: string; 318 | label?: string; 319 | title?: string; 320 | description?: string; 321 | altText?: string; 322 | sha1hash?: string; 323 | extension?: string; 324 | mimeType?: string; 325 | size?: number; 326 | assetId?: string; 327 | uploadId?: string; 328 | path?: string; 329 | url?: string; 330 | metadata?: SanityImageMetadata; 331 | source?: SanityAssetSourceData; 332 | }; 333 | 334 | export type SanityAssetSourceData = { 335 | _type: "sanity.assetSourceData"; 336 | name?: string; 337 | id?: string; 338 | url?: string; 339 | }; 340 | 341 | export type SanityImageMetadata = { 342 | _type: "sanity.imageMetadata"; 343 | location?: Geopoint; 344 | dimensions?: SanityImageDimensions; 345 | palette?: SanityImagePalette; 346 | lqip?: string; 347 | blurHash?: string; 348 | hasAlpha?: boolean; 349 | isOpaque?: boolean; 350 | }; 351 | 352 | export type Slug = { 353 | _type: "slug"; 354 | current: string; 355 | source?: string; 356 | }; 357 | 358 | export type SanityAssistInstructionTask = { 359 | _type: "sanity.assist.instructionTask"; 360 | path?: string; 361 | instructionKey?: string; 362 | started?: string; 363 | updated?: string; 364 | info?: string; 365 | }; 366 | 367 | export type SanityAssistTaskStatus = { 368 | _type: "sanity.assist.task.status"; 369 | tasks?: Array<{ 370 | _key: string; 371 | } & SanityAssistInstructionTask>; 372 | }; 373 | 374 | export type SanityAssistSchemaTypeAnnotations = { 375 | _type: "sanity.assist.schemaType.annotations"; 376 | title?: string; 377 | fields?: Array<{ 378 | _key: string; 379 | } & SanityAssistSchemaTypeField>; 380 | }; 381 | 382 | export type SanityAssistOutputType = { 383 | _type: "sanity.assist.output.type"; 384 | type?: string; 385 | }; 386 | 387 | export type SanityAssistOutputField = { 388 | _type: "sanity.assist.output.field"; 389 | path?: string; 390 | }; 391 | 392 | export type SanityAssistInstructionContext = { 393 | _type: "sanity.assist.instruction.context"; 394 | reference: { 395 | _ref: string; 396 | _type: "reference"; 397 | _weak?: boolean; 398 | [internalGroqTypeReferenceTo]?: "assist.instruction.context"; 399 | }; 400 | }; 401 | 402 | export type AssistInstructionContext = { 403 | _id: string; 404 | _type: "assist.instruction.context"; 405 | _createdAt: string; 406 | _updatedAt: string; 407 | _rev: string; 408 | title?: string; 409 | context?: Array<{ 410 | children?: Array<{ 411 | marks?: Array; 412 | text?: string; 413 | _type: "span"; 414 | _key: string; 415 | }>; 416 | style?: "normal"; 417 | listItem?: never; 418 | markDefs?: null; 419 | level?: number; 420 | _type: "block"; 421 | _key: string; 422 | }>; 423 | }; 424 | 425 | export type SanityAssistInstructionUserInput = { 426 | _type: "sanity.assist.instruction.userInput"; 427 | message: string; 428 | description?: string; 429 | }; 430 | 431 | export type SanityAssistInstructionPrompt = Array<{ 432 | children?: Array<{ 433 | marks?: Array; 434 | text?: string; 435 | _type: "span"; 436 | _key: string; 437 | } | { 438 | _key: string; 439 | } & SanityAssistInstructionFieldRef | { 440 | _key: string; 441 | } & SanityAssistInstructionContext | { 442 | _key: string; 443 | } & SanityAssistInstructionUserInput>; 444 | style?: "normal"; 445 | listItem?: never; 446 | markDefs?: null; 447 | level?: number; 448 | _type: "block"; 449 | _key: string; 450 | }>; 451 | 452 | export type SanityAssistInstructionFieldRef = { 453 | _type: "sanity.assist.instruction.fieldRef"; 454 | path?: string; 455 | }; 456 | 457 | export type SanityAssistInstruction = { 458 | _type: "sanity.assist.instruction"; 459 | prompt?: SanityAssistInstructionPrompt; 460 | icon?: string; 461 | title?: string; 462 | userId?: string; 463 | createdById?: string; 464 | output?: Array<{ 465 | _key: string; 466 | } & SanityAssistOutputField | { 467 | _key: string; 468 | } & SanityAssistOutputType>; 469 | }; 470 | 471 | export type SanityAssistSchemaTypeField = { 472 | _type: "sanity.assist.schemaType.field"; 473 | path?: string; 474 | instructions?: Array<{ 475 | _key: string; 476 | } & SanityAssistInstruction>; 477 | }; 478 | 479 | export type AllSanitySchemaTypes = SanityImagePaletteSwatch | SanityImagePalette | SanityImageDimensions | SanityFileAsset | Geopoint | CallToAction | Link | InfoSection | BlockContent | Settings | Page | Post | Person | SanityImageCrop | SanityImageHotspot | SanityImageAsset | SanityAssetSourceData | SanityImageMetadata | Slug | SanityAssistInstructionTask | SanityAssistTaskStatus | SanityAssistSchemaTypeAnnotations | SanityAssistOutputType | SanityAssistOutputField | SanityAssistInstructionContext | AssistInstructionContext | SanityAssistInstructionUserInput | SanityAssistInstructionPrompt | SanityAssistInstructionFieldRef | SanityAssistInstruction | SanityAssistSchemaTypeField; 480 | export declare const internalGroqTypeReferenceTo: unique symbol; 481 | // Source: ./sanity/queries.ts 482 | // Variable: postsQuery 483 | // Query: *[_type == "post"] | order(date desc, _updatedAt desc) { ... } 484 | export type PostsQueryResult = Array<{ 485 | _id: string; 486 | _type: "post"; 487 | _createdAt: string; 488 | _updatedAt: string; 489 | _rev: string; 490 | title: string; 491 | slug: Slug; 492 | content?: BlockContent; 493 | excerpt?: string; 494 | coverImage: { 495 | asset?: { 496 | _ref: string; 497 | _type: "reference"; 498 | _weak?: boolean; 499 | [internalGroqTypeReferenceTo]?: "sanity.imageAsset"; 500 | }; 501 | hotspot?: SanityImageHotspot; 502 | crop?: SanityImageCrop; 503 | alt?: string; 504 | _type: "image"; 505 | }; 506 | date?: string; 507 | author?: { 508 | _ref: string; 509 | _type: "reference"; 510 | _weak?: boolean; 511 | [internalGroqTypeReferenceTo]?: "person"; 512 | }; 513 | seoTitle?: string; 514 | seoDescription?: string; 515 | }>; 516 | // Variable: somePostsQuery 517 | // Query: *[_type == "post" && slug.current != $skip][0...$limit] | order(date desc, _updatedAt desc) { ... } 518 | export type SomePostsQueryResult = Array<{ 519 | _id: string; 520 | _type: "post"; 521 | _createdAt: string; 522 | _updatedAt: string; 523 | _rev: string; 524 | title: string; 525 | slug: Slug; 526 | content?: BlockContent; 527 | excerpt?: string; 528 | coverImage: { 529 | asset?: { 530 | _ref: string; 531 | _type: "reference"; 532 | _weak?: boolean; 533 | [internalGroqTypeReferenceTo]?: "sanity.imageAsset"; 534 | }; 535 | hotspot?: SanityImageHotspot; 536 | crop?: SanityImageCrop; 537 | alt?: string; 538 | _type: "image"; 539 | }; 540 | date?: string; 541 | author?: { 542 | _ref: string; 543 | _type: "reference"; 544 | _weak?: boolean; 545 | [internalGroqTypeReferenceTo]?: "person"; 546 | }; 547 | seoTitle?: string; 548 | seoDescription?: string; 549 | }>; 550 | // Variable: postQuery 551 | // Query: *[_type == "post" && defined(slug.current) && slug.current == $slug][0]{ ..., content[]{ ..., markDefs[]{ ..., _type == "link" => { "link": { ..., _type == "link" => { "page": page->slug.current, "post": post->slug.current} } }, } }, "author": author->{..., "picture": picture.asset._ref} } 552 | export type PostQueryResult = { 553 | _id: string; 554 | _type: "post"; 555 | _createdAt: string; 556 | _updatedAt: string; 557 | _rev: string; 558 | title: string; 559 | slug: Slug; 560 | content: Array<{ 561 | children?: Array<{ 562 | marks?: Array; 563 | text?: string; 564 | _type: "span"; 565 | _key: string; 566 | }>; 567 | style?: "blockquote" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "normal"; 568 | listItem?: "bullet" | "number"; 569 | markDefs: Array<{ 570 | linkType?: "href" | "page" | "post"; 571 | href?: string; 572 | page?: { 573 | _ref: string; 574 | _type: "reference"; 575 | _weak?: boolean; 576 | [internalGroqTypeReferenceTo]?: "page"; 577 | }; 578 | post?: { 579 | _ref: string; 580 | _type: "reference"; 581 | _weak?: boolean; 582 | [internalGroqTypeReferenceTo]?: "post"; 583 | }; 584 | openInNewTab?: boolean; 585 | _type: "link"; 586 | _key: string; 587 | link: { 588 | linkType?: "href" | "page" | "post"; 589 | href?: string; 590 | page: string | null; 591 | post: string | null; 592 | openInNewTab?: boolean; 593 | _type: "link"; 594 | _key: string; 595 | }; 596 | }> | null; 597 | level?: number; 598 | _type: "block"; 599 | _key: string; 600 | }> | null; 601 | excerpt?: string; 602 | coverImage: { 603 | asset?: { 604 | _ref: string; 605 | _type: "reference"; 606 | _weak?: boolean; 607 | [internalGroqTypeReferenceTo]?: "sanity.imageAsset"; 608 | }; 609 | hotspot?: SanityImageHotspot; 610 | crop?: SanityImageCrop; 611 | alt?: string; 612 | _type: "image"; 613 | }; 614 | date?: string; 615 | author: { 616 | _id: string; 617 | _type: "person"; 618 | _createdAt: string; 619 | _updatedAt: string; 620 | _rev: string; 621 | firstName: string; 622 | lastName: string; 623 | picture: string | null; 624 | } | null; 625 | seoTitle?: string; 626 | seoDescription?: string; 627 | } | null; 628 | // Variable: pageQuery 629 | // Query: *[_type == "page" && defined(slug.current) && slug.current == $slug][0]{ ..., "pageBuilder": pageBuilder[]{ ..., _type == "callToAction" => { link { ..., _type == "link" => { "page": page->slug.current, "post": post->slug.current} }, }, _type == "infoSection" => { content[]{ ..., markDefs[]{ ..., _type == "link" => { "link": { ..., _type == "link" => { "page": page->slug.current, "post": post->slug.current} } }, } } }, } } 630 | export type PageQueryResult = { 631 | _id: string; 632 | _type: "page"; 633 | _createdAt: string; 634 | _updatedAt: string; 635 | _rev: string; 636 | name: string; 637 | slug: Slug; 638 | heading: string; 639 | subheading?: string; 640 | pageBuilder: Array<{ 641 | _key: string; 642 | _type: "callToAction"; 643 | heading: string; 644 | text?: string; 645 | buttonText?: string; 646 | link: { 647 | _type: "link"; 648 | linkType?: "href" | "page" | "post"; 649 | href?: string; 650 | page: string | null; 651 | post: string | null; 652 | openInNewTab?: boolean; 653 | } | null; 654 | } | { 655 | _key: string; 656 | _type: "infoSection"; 657 | heading?: string; 658 | subheading?: string; 659 | content: Array<{ 660 | children?: Array<{ 661 | marks?: Array; 662 | text?: string; 663 | _type: "span"; 664 | _key: string; 665 | }>; 666 | style?: "blockquote" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "normal"; 667 | listItem?: "bullet" | "number"; 668 | markDefs: Array<{ 669 | linkType?: "href" | "page" | "post"; 670 | href?: string; 671 | page?: { 672 | _ref: string; 673 | _type: "reference"; 674 | _weak?: boolean; 675 | [internalGroqTypeReferenceTo]?: "page"; 676 | }; 677 | post?: { 678 | _ref: string; 679 | _type: "reference"; 680 | _weak?: boolean; 681 | [internalGroqTypeReferenceTo]?: "post"; 682 | }; 683 | openInNewTab?: boolean; 684 | _type: "link"; 685 | _key: string; 686 | link: { 687 | linkType?: "href" | "page" | "post"; 688 | href?: string; 689 | page: string | null; 690 | post: string | null; 691 | openInNewTab?: boolean; 692 | _type: "link"; 693 | _key: string; 694 | }; 695 | }> | null; 696 | level?: number; 697 | _type: "block"; 698 | _key: string; 699 | }> | null; 700 | }> | null; 701 | seoTitle?: string; 702 | seoDescription?: string; 703 | } | null; 704 | // Variable: settingsQuery 705 | // Query: *[_type == "settings"][0]{ title, description[]{ ..., markDefs[]{ ..., _type == "link" => { "link": { ..., _type == "link" => { "page": page->slug.current, "post": post->slug.current} } }, } }, "ogImage": ogImage.asset->url } 706 | export type SettingsQueryResult = { 707 | title: string; 708 | description: Array<{ 709 | children?: Array<{ 710 | marks?: Array; 711 | text?: string; 712 | _type: "span"; 713 | _key: string; 714 | }>; 715 | style?: "normal"; 716 | listItem?: never; 717 | markDefs: Array<{ 718 | linkType?: "href" | "page" | "post"; 719 | href?: string; 720 | page?: { 721 | _ref: string; 722 | _type: "reference"; 723 | _weak?: boolean; 724 | [internalGroqTypeReferenceTo]?: "page"; 725 | }; 726 | post?: { 727 | _ref: string; 728 | _type: "reference"; 729 | _weak?: boolean; 730 | [internalGroqTypeReferenceTo]?: "post"; 731 | }; 732 | openInNewTab?: boolean; 733 | _type: "link"; 734 | _key: string; 735 | link: { 736 | linkType?: "href" | "page" | "post"; 737 | href?: string; 738 | page: string | null; 739 | post: string | null; 740 | openInNewTab?: boolean; 741 | _type: "link"; 742 | _key: string; 743 | }; 744 | }> | null; 745 | level?: number; 746 | _type: "block"; 747 | _key: string; 748 | }> | null; 749 | ogImage: string | null; 750 | } | null; 751 | 752 | // Query TypeMap 753 | import "@sanity/client"; 754 | declare module "@sanity/client" { 755 | interface SanityQueries { 756 | "*[_type == \"post\"] | order(date desc, _updatedAt desc) {\n\t\t...\n\t}": PostsQueryResult; 757 | "\n\t\t*[_type == \"post\" && slug.current != $skip][0...$limit] | order(date desc, _updatedAt desc) {\n\t\t\t...\n\t\t}": SomePostsQueryResult; 758 | "\n\t\t*[_type == \"post\" && defined(slug.current) && slug.current == $slug][0]{\n\t\t\t...,\n\t\t\tcontent[]{\n\t\t\t\t\t\t...,\n\t\t\t\t\t\tmarkDefs[]{\n\t\t\t\t\t\t\t...,\n\t\t\t\t\t\t\t_type == \"link\" => {\n\t\t\t\t\t\t\t\t\"link\": {\n\t\t\t\t\t\t\t\t\t...,\n\t\t\t\t\t\t\t\t\t\n_type == \"link\" => {\n\t\"page\": page->slug.current,\n\t\"post\": post->slug.current\n}\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\"author\": author->{..., \"picture\": picture.asset._ref}\n\t\t}": PostQueryResult; 759 | "\n\t\t*[_type == \"page\" && defined(slug.current) && slug.current == $slug][0]{\n\t\t\t...,\n\t\t\t\"pageBuilder\": pageBuilder[]{\n\t\t\t\t...,\n\t\t\t\t_type == \"callToAction\" => {\n\t\t\t\t\t\nlink {\n\t...,\n\t\n_type == \"link\" => {\n\t\"page\": page->slug.current,\n\t\"post\": post->slug.current\n}\n\n\t}\n,\n\t\t\t\t},\n\t\t\t\t_type == \"infoSection\" => {\n\t\t\t\t\tcontent[]{\n\t\t\t\t\t\t...,\n\t\t\t\t\t\tmarkDefs[]{\n\t\t\t\t\t\t\t...,\n\t\t\t\t\t\t\t_type == \"link\" => {\n\t\t\t\t\t\t\t\t\"link\": {\n\t\t\t\t\t\t\t\t\t...,\n\t\t\t\t\t\t\t\t\t\n_type == \"link\" => {\n\t\"page\": page->slug.current,\n\t\"post\": post->slug.current\n}\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t}": PageQueryResult; 760 | "\n\t\t*[_type == \"settings\"][0]{\n\t\t\ttitle,\n\t\t\tdescription[]{\n\t\t\t\t\t\t...,\n\t\t\t\t\t\tmarkDefs[]{\n\t\t\t\t\t\t\t...,\n\t\t\t\t\t\t\t_type == \"link\" => {\n\t\t\t\t\t\t\t\t\"link\": {\n\t\t\t\t\t\t\t\t\t...,\n\t\t\t\t\t\t\t\t\t\n_type == \"link\" => {\n\t\"page\": page->slug.current,\n\t\"post\": post->slug.current\n}\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\"ogImage\": ogImage.asset->url\n\t\t}": SettingsQueryResult; 761 | } 762 | } 763 | -------------------------------------------------------------------------------- /studio/schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "sanity.imagePaletteSwatch", 4 | "type": "type", 5 | "value": { 6 | "type": "object", 7 | "attributes": { 8 | "_type": { 9 | "type": "objectAttribute", 10 | "value": { 11 | "type": "string", 12 | "value": "sanity.imagePaletteSwatch" 13 | } 14 | }, 15 | "background": { 16 | "type": "objectAttribute", 17 | "value": { 18 | "type": "string" 19 | }, 20 | "optional": true 21 | }, 22 | "foreground": { 23 | "type": "objectAttribute", 24 | "value": { 25 | "type": "string" 26 | }, 27 | "optional": true 28 | }, 29 | "population": { 30 | "type": "objectAttribute", 31 | "value": { 32 | "type": "number" 33 | }, 34 | "optional": true 35 | }, 36 | "title": { 37 | "type": "objectAttribute", 38 | "value": { 39 | "type": "string" 40 | }, 41 | "optional": true 42 | } 43 | } 44 | } 45 | }, 46 | { 47 | "name": "sanity.imagePalette", 48 | "type": "type", 49 | "value": { 50 | "type": "object", 51 | "attributes": { 52 | "_type": { 53 | "type": "objectAttribute", 54 | "value": { 55 | "type": "string", 56 | "value": "sanity.imagePalette" 57 | } 58 | }, 59 | "darkMuted": { 60 | "type": "objectAttribute", 61 | "value": { 62 | "type": "inline", 63 | "name": "sanity.imagePaletteSwatch" 64 | }, 65 | "optional": true 66 | }, 67 | "lightVibrant": { 68 | "type": "objectAttribute", 69 | "value": { 70 | "type": "inline", 71 | "name": "sanity.imagePaletteSwatch" 72 | }, 73 | "optional": true 74 | }, 75 | "darkVibrant": { 76 | "type": "objectAttribute", 77 | "value": { 78 | "type": "inline", 79 | "name": "sanity.imagePaletteSwatch" 80 | }, 81 | "optional": true 82 | }, 83 | "vibrant": { 84 | "type": "objectAttribute", 85 | "value": { 86 | "type": "inline", 87 | "name": "sanity.imagePaletteSwatch" 88 | }, 89 | "optional": true 90 | }, 91 | "dominant": { 92 | "type": "objectAttribute", 93 | "value": { 94 | "type": "inline", 95 | "name": "sanity.imagePaletteSwatch" 96 | }, 97 | "optional": true 98 | }, 99 | "lightMuted": { 100 | "type": "objectAttribute", 101 | "value": { 102 | "type": "inline", 103 | "name": "sanity.imagePaletteSwatch" 104 | }, 105 | "optional": true 106 | }, 107 | "muted": { 108 | "type": "objectAttribute", 109 | "value": { 110 | "type": "inline", 111 | "name": "sanity.imagePaletteSwatch" 112 | }, 113 | "optional": true 114 | } 115 | } 116 | } 117 | }, 118 | { 119 | "name": "sanity.imageDimensions", 120 | "type": "type", 121 | "value": { 122 | "type": "object", 123 | "attributes": { 124 | "_type": { 125 | "type": "objectAttribute", 126 | "value": { 127 | "type": "string", 128 | "value": "sanity.imageDimensions" 129 | } 130 | }, 131 | "height": { 132 | "type": "objectAttribute", 133 | "value": { 134 | "type": "number" 135 | }, 136 | "optional": true 137 | }, 138 | "width": { 139 | "type": "objectAttribute", 140 | "value": { 141 | "type": "number" 142 | }, 143 | "optional": true 144 | }, 145 | "aspectRatio": { 146 | "type": "objectAttribute", 147 | "value": { 148 | "type": "number" 149 | }, 150 | "optional": true 151 | } 152 | } 153 | } 154 | }, 155 | { 156 | "name": "sanity.fileAsset", 157 | "type": "document", 158 | "attributes": { 159 | "_id": { 160 | "type": "objectAttribute", 161 | "value": { 162 | "type": "string" 163 | } 164 | }, 165 | "_type": { 166 | "type": "objectAttribute", 167 | "value": { 168 | "type": "string", 169 | "value": "sanity.fileAsset" 170 | } 171 | }, 172 | "_createdAt": { 173 | "type": "objectAttribute", 174 | "value": { 175 | "type": "string" 176 | } 177 | }, 178 | "_updatedAt": { 179 | "type": "objectAttribute", 180 | "value": { 181 | "type": "string" 182 | } 183 | }, 184 | "_rev": { 185 | "type": "objectAttribute", 186 | "value": { 187 | "type": "string" 188 | } 189 | }, 190 | "originalFilename": { 191 | "type": "objectAttribute", 192 | "value": { 193 | "type": "string" 194 | }, 195 | "optional": true 196 | }, 197 | "label": { 198 | "type": "objectAttribute", 199 | "value": { 200 | "type": "string" 201 | }, 202 | "optional": true 203 | }, 204 | "title": { 205 | "type": "objectAttribute", 206 | "value": { 207 | "type": "string" 208 | }, 209 | "optional": true 210 | }, 211 | "description": { 212 | "type": "objectAttribute", 213 | "value": { 214 | "type": "string" 215 | }, 216 | "optional": true 217 | }, 218 | "altText": { 219 | "type": "objectAttribute", 220 | "value": { 221 | "type": "string" 222 | }, 223 | "optional": true 224 | }, 225 | "sha1hash": { 226 | "type": "objectAttribute", 227 | "value": { 228 | "type": "string" 229 | }, 230 | "optional": true 231 | }, 232 | "extension": { 233 | "type": "objectAttribute", 234 | "value": { 235 | "type": "string" 236 | }, 237 | "optional": true 238 | }, 239 | "mimeType": { 240 | "type": "objectAttribute", 241 | "value": { 242 | "type": "string" 243 | }, 244 | "optional": true 245 | }, 246 | "size": { 247 | "type": "objectAttribute", 248 | "value": { 249 | "type": "number" 250 | }, 251 | "optional": true 252 | }, 253 | "assetId": { 254 | "type": "objectAttribute", 255 | "value": { 256 | "type": "string" 257 | }, 258 | "optional": true 259 | }, 260 | "uploadId": { 261 | "type": "objectAttribute", 262 | "value": { 263 | "type": "string" 264 | }, 265 | "optional": true 266 | }, 267 | "path": { 268 | "type": "objectAttribute", 269 | "value": { 270 | "type": "string" 271 | }, 272 | "optional": true 273 | }, 274 | "url": { 275 | "type": "objectAttribute", 276 | "value": { 277 | "type": "string" 278 | }, 279 | "optional": true 280 | }, 281 | "source": { 282 | "type": "objectAttribute", 283 | "value": { 284 | "type": "inline", 285 | "name": "sanity.assetSourceData" 286 | }, 287 | "optional": true 288 | } 289 | } 290 | }, 291 | { 292 | "name": "geopoint", 293 | "type": "type", 294 | "value": { 295 | "type": "object", 296 | "attributes": { 297 | "_type": { 298 | "type": "objectAttribute", 299 | "value": { 300 | "type": "string", 301 | "value": "geopoint" 302 | } 303 | }, 304 | "lat": { 305 | "type": "objectAttribute", 306 | "value": { 307 | "type": "number" 308 | }, 309 | "optional": true 310 | }, 311 | "lng": { 312 | "type": "objectAttribute", 313 | "value": { 314 | "type": "number" 315 | }, 316 | "optional": true 317 | }, 318 | "alt": { 319 | "type": "objectAttribute", 320 | "value": { 321 | "type": "number" 322 | }, 323 | "optional": true 324 | } 325 | } 326 | } 327 | }, 328 | { 329 | "name": "callToAction", 330 | "type": "type", 331 | "value": { 332 | "type": "object", 333 | "attributes": { 334 | "_type": { 335 | "type": "objectAttribute", 336 | "value": { 337 | "type": "string", 338 | "value": "callToAction" 339 | } 340 | }, 341 | "heading": { 342 | "type": "objectAttribute", 343 | "value": { 344 | "type": "string" 345 | }, 346 | "optional": false 347 | }, 348 | "text": { 349 | "type": "objectAttribute", 350 | "value": { 351 | "type": "string" 352 | }, 353 | "optional": true 354 | }, 355 | "buttonText": { 356 | "type": "objectAttribute", 357 | "value": { 358 | "type": "string" 359 | }, 360 | "optional": true 361 | }, 362 | "link": { 363 | "type": "objectAttribute", 364 | "value": { 365 | "type": "inline", 366 | "name": "link" 367 | }, 368 | "optional": true 369 | } 370 | } 371 | } 372 | }, 373 | { 374 | "name": "link", 375 | "type": "type", 376 | "value": { 377 | "type": "object", 378 | "attributes": { 379 | "_type": { 380 | "type": "objectAttribute", 381 | "value": { 382 | "type": "string", 383 | "value": "link" 384 | } 385 | }, 386 | "linkType": { 387 | "type": "objectAttribute", 388 | "value": { 389 | "type": "union", 390 | "of": [ 391 | { 392 | "type": "string", 393 | "value": "href" 394 | }, 395 | { 396 | "type": "string", 397 | "value": "page" 398 | }, 399 | { 400 | "type": "string", 401 | "value": "post" 402 | } 403 | ] 404 | }, 405 | "optional": true 406 | }, 407 | "href": { 408 | "type": "objectAttribute", 409 | "value": { 410 | "type": "string" 411 | }, 412 | "optional": true 413 | }, 414 | "page": { 415 | "type": "objectAttribute", 416 | "value": { 417 | "type": "object", 418 | "attributes": { 419 | "_ref": { 420 | "type": "objectAttribute", 421 | "value": { 422 | "type": "string" 423 | } 424 | }, 425 | "_type": { 426 | "type": "objectAttribute", 427 | "value": { 428 | "type": "string", 429 | "value": "reference" 430 | } 431 | }, 432 | "_weak": { 433 | "type": "objectAttribute", 434 | "value": { 435 | "type": "boolean" 436 | }, 437 | "optional": true 438 | } 439 | }, 440 | "dereferencesTo": "page" 441 | }, 442 | "optional": true 443 | }, 444 | "post": { 445 | "type": "objectAttribute", 446 | "value": { 447 | "type": "object", 448 | "attributes": { 449 | "_ref": { 450 | "type": "objectAttribute", 451 | "value": { 452 | "type": "string" 453 | } 454 | }, 455 | "_type": { 456 | "type": "objectAttribute", 457 | "value": { 458 | "type": "string", 459 | "value": "reference" 460 | } 461 | }, 462 | "_weak": { 463 | "type": "objectAttribute", 464 | "value": { 465 | "type": "boolean" 466 | }, 467 | "optional": true 468 | } 469 | }, 470 | "dereferencesTo": "post" 471 | }, 472 | "optional": true 473 | }, 474 | "openInNewTab": { 475 | "type": "objectAttribute", 476 | "value": { 477 | "type": "boolean" 478 | }, 479 | "optional": true 480 | } 481 | } 482 | } 483 | }, 484 | { 485 | "name": "infoSection", 486 | "type": "type", 487 | "value": { 488 | "type": "object", 489 | "attributes": { 490 | "_type": { 491 | "type": "objectAttribute", 492 | "value": { 493 | "type": "string", 494 | "value": "infoSection" 495 | } 496 | }, 497 | "heading": { 498 | "type": "objectAttribute", 499 | "value": { 500 | "type": "string" 501 | }, 502 | "optional": true 503 | }, 504 | "subheading": { 505 | "type": "objectAttribute", 506 | "value": { 507 | "type": "string" 508 | }, 509 | "optional": true 510 | }, 511 | "content": { 512 | "type": "objectAttribute", 513 | "value": { 514 | "type": "array", 515 | "of": { 516 | "type": "object", 517 | "attributes": { 518 | "children": { 519 | "type": "objectAttribute", 520 | "value": { 521 | "type": "array", 522 | "of": { 523 | "type": "object", 524 | "attributes": { 525 | "marks": { 526 | "type": "objectAttribute", 527 | "value": { 528 | "type": "array", 529 | "of": { 530 | "type": "string" 531 | } 532 | }, 533 | "optional": true 534 | }, 535 | "text": { 536 | "type": "objectAttribute", 537 | "value": { 538 | "type": "string" 539 | }, 540 | "optional": true 541 | }, 542 | "_type": { 543 | "type": "objectAttribute", 544 | "value": { 545 | "type": "string", 546 | "value": "span" 547 | } 548 | } 549 | }, 550 | "rest": { 551 | "type": "object", 552 | "attributes": { 553 | "_key": { 554 | "type": "objectAttribute", 555 | "value": { 556 | "type": "string" 557 | } 558 | } 559 | } 560 | } 561 | } 562 | }, 563 | "optional": true 564 | }, 565 | "style": { 566 | "type": "objectAttribute", 567 | "value": { 568 | "type": "union", 569 | "of": [ 570 | { 571 | "type": "string", 572 | "value": "normal" 573 | }, 574 | { 575 | "type": "string", 576 | "value": "h1" 577 | }, 578 | { 579 | "type": "string", 580 | "value": "h2" 581 | }, 582 | { 583 | "type": "string", 584 | "value": "h3" 585 | }, 586 | { 587 | "type": "string", 588 | "value": "h4" 589 | }, 590 | { 591 | "type": "string", 592 | "value": "h5" 593 | }, 594 | { 595 | "type": "string", 596 | "value": "h6" 597 | }, 598 | { 599 | "type": "string", 600 | "value": "blockquote" 601 | } 602 | ] 603 | }, 604 | "optional": true 605 | }, 606 | "listItem": { 607 | "type": "objectAttribute", 608 | "value": { 609 | "type": "union", 610 | "of": [ 611 | { 612 | "type": "string", 613 | "value": "bullet" 614 | }, 615 | { 616 | "type": "string", 617 | "value": "number" 618 | } 619 | ] 620 | }, 621 | "optional": true 622 | }, 623 | "markDefs": { 624 | "type": "objectAttribute", 625 | "value": { 626 | "type": "array", 627 | "of": { 628 | "type": "object", 629 | "attributes": { 630 | "linkType": { 631 | "type": "objectAttribute", 632 | "value": { 633 | "type": "union", 634 | "of": [ 635 | { 636 | "type": "string", 637 | "value": "href" 638 | }, 639 | { 640 | "type": "string", 641 | "value": "page" 642 | }, 643 | { 644 | "type": "string", 645 | "value": "post" 646 | } 647 | ] 648 | }, 649 | "optional": true 650 | }, 651 | "href": { 652 | "type": "objectAttribute", 653 | "value": { 654 | "type": "string" 655 | }, 656 | "optional": true 657 | }, 658 | "page": { 659 | "type": "objectAttribute", 660 | "value": { 661 | "type": "object", 662 | "attributes": { 663 | "_ref": { 664 | "type": "objectAttribute", 665 | "value": { 666 | "type": "string" 667 | } 668 | }, 669 | "_type": { 670 | "type": "objectAttribute", 671 | "value": { 672 | "type": "string", 673 | "value": "reference" 674 | } 675 | }, 676 | "_weak": { 677 | "type": "objectAttribute", 678 | "value": { 679 | "type": "boolean" 680 | }, 681 | "optional": true 682 | } 683 | }, 684 | "dereferencesTo": "page" 685 | }, 686 | "optional": true 687 | }, 688 | "post": { 689 | "type": "objectAttribute", 690 | "value": { 691 | "type": "object", 692 | "attributes": { 693 | "_ref": { 694 | "type": "objectAttribute", 695 | "value": { 696 | "type": "string" 697 | } 698 | }, 699 | "_type": { 700 | "type": "objectAttribute", 701 | "value": { 702 | "type": "string", 703 | "value": "reference" 704 | } 705 | }, 706 | "_weak": { 707 | "type": "objectAttribute", 708 | "value": { 709 | "type": "boolean" 710 | }, 711 | "optional": true 712 | } 713 | }, 714 | "dereferencesTo": "post" 715 | }, 716 | "optional": true 717 | }, 718 | "openInNewTab": { 719 | "type": "objectAttribute", 720 | "value": { 721 | "type": "boolean" 722 | }, 723 | "optional": true 724 | }, 725 | "_type": { 726 | "type": "objectAttribute", 727 | "value": { 728 | "type": "string", 729 | "value": "link" 730 | } 731 | } 732 | }, 733 | "rest": { 734 | "type": "object", 735 | "attributes": { 736 | "_key": { 737 | "type": "objectAttribute", 738 | "value": { 739 | "type": "string" 740 | } 741 | } 742 | } 743 | } 744 | } 745 | }, 746 | "optional": true 747 | }, 748 | "level": { 749 | "type": "objectAttribute", 750 | "value": { 751 | "type": "number" 752 | }, 753 | "optional": true 754 | }, 755 | "_type": { 756 | "type": "objectAttribute", 757 | "value": { 758 | "type": "string", 759 | "value": "block" 760 | } 761 | } 762 | }, 763 | "rest": { 764 | "type": "object", 765 | "attributes": { 766 | "_key": { 767 | "type": "objectAttribute", 768 | "value": { 769 | "type": "string" 770 | } 771 | } 772 | } 773 | } 774 | } 775 | }, 776 | "optional": true 777 | } 778 | } 779 | } 780 | }, 781 | { 782 | "name": "blockContent", 783 | "type": "type", 784 | "value": { 785 | "type": "array", 786 | "of": { 787 | "type": "object", 788 | "attributes": { 789 | "children": { 790 | "type": "objectAttribute", 791 | "value": { 792 | "type": "array", 793 | "of": { 794 | "type": "object", 795 | "attributes": { 796 | "marks": { 797 | "type": "objectAttribute", 798 | "value": { 799 | "type": "array", 800 | "of": { 801 | "type": "string" 802 | } 803 | }, 804 | "optional": true 805 | }, 806 | "text": { 807 | "type": "objectAttribute", 808 | "value": { 809 | "type": "string" 810 | }, 811 | "optional": true 812 | }, 813 | "_type": { 814 | "type": "objectAttribute", 815 | "value": { 816 | "type": "string", 817 | "value": "span" 818 | } 819 | } 820 | }, 821 | "rest": { 822 | "type": "object", 823 | "attributes": { 824 | "_key": { 825 | "type": "objectAttribute", 826 | "value": { 827 | "type": "string" 828 | } 829 | } 830 | } 831 | } 832 | } 833 | }, 834 | "optional": true 835 | }, 836 | "style": { 837 | "type": "objectAttribute", 838 | "value": { 839 | "type": "union", 840 | "of": [ 841 | { 842 | "type": "string", 843 | "value": "normal" 844 | }, 845 | { 846 | "type": "string", 847 | "value": "h1" 848 | }, 849 | { 850 | "type": "string", 851 | "value": "h2" 852 | }, 853 | { 854 | "type": "string", 855 | "value": "h3" 856 | }, 857 | { 858 | "type": "string", 859 | "value": "h4" 860 | }, 861 | { 862 | "type": "string", 863 | "value": "h5" 864 | }, 865 | { 866 | "type": "string", 867 | "value": "h6" 868 | }, 869 | { 870 | "type": "string", 871 | "value": "blockquote" 872 | } 873 | ] 874 | }, 875 | "optional": true 876 | }, 877 | "listItem": { 878 | "type": "objectAttribute", 879 | "value": { 880 | "type": "union", 881 | "of": [ 882 | { 883 | "type": "string", 884 | "value": "bullet" 885 | }, 886 | { 887 | "type": "string", 888 | "value": "number" 889 | } 890 | ] 891 | }, 892 | "optional": true 893 | }, 894 | "markDefs": { 895 | "type": "objectAttribute", 896 | "value": { 897 | "type": "array", 898 | "of": { 899 | "type": "object", 900 | "attributes": { 901 | "linkType": { 902 | "type": "objectAttribute", 903 | "value": { 904 | "type": "union", 905 | "of": [ 906 | { 907 | "type": "string", 908 | "value": "href" 909 | }, 910 | { 911 | "type": "string", 912 | "value": "page" 913 | }, 914 | { 915 | "type": "string", 916 | "value": "post" 917 | } 918 | ] 919 | }, 920 | "optional": true 921 | }, 922 | "href": { 923 | "type": "objectAttribute", 924 | "value": { 925 | "type": "string" 926 | }, 927 | "optional": true 928 | }, 929 | "page": { 930 | "type": "objectAttribute", 931 | "value": { 932 | "type": "object", 933 | "attributes": { 934 | "_ref": { 935 | "type": "objectAttribute", 936 | "value": { 937 | "type": "string" 938 | } 939 | }, 940 | "_type": { 941 | "type": "objectAttribute", 942 | "value": { 943 | "type": "string", 944 | "value": "reference" 945 | } 946 | }, 947 | "_weak": { 948 | "type": "objectAttribute", 949 | "value": { 950 | "type": "boolean" 951 | }, 952 | "optional": true 953 | } 954 | }, 955 | "dereferencesTo": "page" 956 | }, 957 | "optional": true 958 | }, 959 | "post": { 960 | "type": "objectAttribute", 961 | "value": { 962 | "type": "object", 963 | "attributes": { 964 | "_ref": { 965 | "type": "objectAttribute", 966 | "value": { 967 | "type": "string" 968 | } 969 | }, 970 | "_type": { 971 | "type": "objectAttribute", 972 | "value": { 973 | "type": "string", 974 | "value": "reference" 975 | } 976 | }, 977 | "_weak": { 978 | "type": "objectAttribute", 979 | "value": { 980 | "type": "boolean" 981 | }, 982 | "optional": true 983 | } 984 | }, 985 | "dereferencesTo": "post" 986 | }, 987 | "optional": true 988 | }, 989 | "openInNewTab": { 990 | "type": "objectAttribute", 991 | "value": { 992 | "type": "boolean" 993 | }, 994 | "optional": true 995 | }, 996 | "_type": { 997 | "type": "objectAttribute", 998 | "value": { 999 | "type": "string", 1000 | "value": "link" 1001 | } 1002 | } 1003 | }, 1004 | "rest": { 1005 | "type": "object", 1006 | "attributes": { 1007 | "_key": { 1008 | "type": "objectAttribute", 1009 | "value": { 1010 | "type": "string" 1011 | } 1012 | } 1013 | } 1014 | } 1015 | } 1016 | }, 1017 | "optional": true 1018 | }, 1019 | "level": { 1020 | "type": "objectAttribute", 1021 | "value": { 1022 | "type": "number" 1023 | }, 1024 | "optional": true 1025 | }, 1026 | "_type": { 1027 | "type": "objectAttribute", 1028 | "value": { 1029 | "type": "string", 1030 | "value": "block" 1031 | } 1032 | } 1033 | }, 1034 | "rest": { 1035 | "type": "object", 1036 | "attributes": { 1037 | "_key": { 1038 | "type": "objectAttribute", 1039 | "value": { 1040 | "type": "string" 1041 | } 1042 | } 1043 | } 1044 | } 1045 | } 1046 | } 1047 | }, 1048 | { 1049 | "name": "settings", 1050 | "type": "document", 1051 | "attributes": { 1052 | "_id": { 1053 | "type": "objectAttribute", 1054 | "value": { 1055 | "type": "string" 1056 | } 1057 | }, 1058 | "_type": { 1059 | "type": "objectAttribute", 1060 | "value": { 1061 | "type": "string", 1062 | "value": "settings" 1063 | } 1064 | }, 1065 | "_createdAt": { 1066 | "type": "objectAttribute", 1067 | "value": { 1068 | "type": "string" 1069 | } 1070 | }, 1071 | "_updatedAt": { 1072 | "type": "objectAttribute", 1073 | "value": { 1074 | "type": "string" 1075 | } 1076 | }, 1077 | "_rev": { 1078 | "type": "objectAttribute", 1079 | "value": { 1080 | "type": "string" 1081 | } 1082 | }, 1083 | "title": { 1084 | "type": "objectAttribute", 1085 | "value": { 1086 | "type": "string" 1087 | }, 1088 | "optional": false 1089 | }, 1090 | "description": { 1091 | "type": "objectAttribute", 1092 | "value": { 1093 | "type": "array", 1094 | "of": { 1095 | "type": "object", 1096 | "attributes": { 1097 | "children": { 1098 | "type": "objectAttribute", 1099 | "value": { 1100 | "type": "array", 1101 | "of": { 1102 | "type": "object", 1103 | "attributes": { 1104 | "marks": { 1105 | "type": "objectAttribute", 1106 | "value": { 1107 | "type": "array", 1108 | "of": { 1109 | "type": "string" 1110 | } 1111 | }, 1112 | "optional": true 1113 | }, 1114 | "text": { 1115 | "type": "objectAttribute", 1116 | "value": { 1117 | "type": "string" 1118 | }, 1119 | "optional": true 1120 | }, 1121 | "_type": { 1122 | "type": "objectAttribute", 1123 | "value": { 1124 | "type": "string", 1125 | "value": "span" 1126 | } 1127 | } 1128 | }, 1129 | "rest": { 1130 | "type": "object", 1131 | "attributes": { 1132 | "_key": { 1133 | "type": "objectAttribute", 1134 | "value": { 1135 | "type": "string" 1136 | } 1137 | } 1138 | } 1139 | } 1140 | } 1141 | }, 1142 | "optional": true 1143 | }, 1144 | "style": { 1145 | "type": "objectAttribute", 1146 | "value": { 1147 | "type": "union", 1148 | "of": [ 1149 | { 1150 | "type": "string", 1151 | "value": "normal" 1152 | } 1153 | ] 1154 | }, 1155 | "optional": true 1156 | }, 1157 | "listItem": { 1158 | "type": "objectAttribute", 1159 | "value": { 1160 | "type": "union", 1161 | "of": [] 1162 | }, 1163 | "optional": true 1164 | }, 1165 | "markDefs": { 1166 | "type": "objectAttribute", 1167 | "value": { 1168 | "type": "array", 1169 | "of": { 1170 | "type": "object", 1171 | "attributes": { 1172 | "linkType": { 1173 | "type": "objectAttribute", 1174 | "value": { 1175 | "type": "union", 1176 | "of": [ 1177 | { 1178 | "type": "string", 1179 | "value": "href" 1180 | }, 1181 | { 1182 | "type": "string", 1183 | "value": "page" 1184 | }, 1185 | { 1186 | "type": "string", 1187 | "value": "post" 1188 | } 1189 | ] 1190 | }, 1191 | "optional": true 1192 | }, 1193 | "href": { 1194 | "type": "objectAttribute", 1195 | "value": { 1196 | "type": "string" 1197 | }, 1198 | "optional": true 1199 | }, 1200 | "page": { 1201 | "type": "objectAttribute", 1202 | "value": { 1203 | "type": "object", 1204 | "attributes": { 1205 | "_ref": { 1206 | "type": "objectAttribute", 1207 | "value": { 1208 | "type": "string" 1209 | } 1210 | }, 1211 | "_type": { 1212 | "type": "objectAttribute", 1213 | "value": { 1214 | "type": "string", 1215 | "value": "reference" 1216 | } 1217 | }, 1218 | "_weak": { 1219 | "type": "objectAttribute", 1220 | "value": { 1221 | "type": "boolean" 1222 | }, 1223 | "optional": true 1224 | } 1225 | }, 1226 | "dereferencesTo": "page" 1227 | }, 1228 | "optional": true 1229 | }, 1230 | "post": { 1231 | "type": "objectAttribute", 1232 | "value": { 1233 | "type": "object", 1234 | "attributes": { 1235 | "_ref": { 1236 | "type": "objectAttribute", 1237 | "value": { 1238 | "type": "string" 1239 | } 1240 | }, 1241 | "_type": { 1242 | "type": "objectAttribute", 1243 | "value": { 1244 | "type": "string", 1245 | "value": "reference" 1246 | } 1247 | }, 1248 | "_weak": { 1249 | "type": "objectAttribute", 1250 | "value": { 1251 | "type": "boolean" 1252 | }, 1253 | "optional": true 1254 | } 1255 | }, 1256 | "dereferencesTo": "post" 1257 | }, 1258 | "optional": true 1259 | }, 1260 | "openInNewTab": { 1261 | "type": "objectAttribute", 1262 | "value": { 1263 | "type": "boolean" 1264 | }, 1265 | "optional": true 1266 | }, 1267 | "_type": { 1268 | "type": "objectAttribute", 1269 | "value": { 1270 | "type": "string", 1271 | "value": "link" 1272 | } 1273 | } 1274 | }, 1275 | "rest": { 1276 | "type": "object", 1277 | "attributes": { 1278 | "_key": { 1279 | "type": "objectAttribute", 1280 | "value": { 1281 | "type": "string" 1282 | } 1283 | } 1284 | } 1285 | } 1286 | } 1287 | }, 1288 | "optional": true 1289 | }, 1290 | "level": { 1291 | "type": "objectAttribute", 1292 | "value": { 1293 | "type": "number" 1294 | }, 1295 | "optional": true 1296 | }, 1297 | "_type": { 1298 | "type": "objectAttribute", 1299 | "value": { 1300 | "type": "string", 1301 | "value": "block" 1302 | } 1303 | } 1304 | }, 1305 | "rest": { 1306 | "type": "object", 1307 | "attributes": { 1308 | "_key": { 1309 | "type": "objectAttribute", 1310 | "value": { 1311 | "type": "string" 1312 | } 1313 | } 1314 | } 1315 | } 1316 | } 1317 | }, 1318 | "optional": true 1319 | }, 1320 | "ogImage": { 1321 | "type": "objectAttribute", 1322 | "value": { 1323 | "type": "object", 1324 | "attributes": { 1325 | "asset": { 1326 | "type": "objectAttribute", 1327 | "value": { 1328 | "type": "object", 1329 | "attributes": { 1330 | "_ref": { 1331 | "type": "objectAttribute", 1332 | "value": { 1333 | "type": "string" 1334 | } 1335 | }, 1336 | "_type": { 1337 | "type": "objectAttribute", 1338 | "value": { 1339 | "type": "string", 1340 | "value": "reference" 1341 | } 1342 | }, 1343 | "_weak": { 1344 | "type": "objectAttribute", 1345 | "value": { 1346 | "type": "boolean" 1347 | }, 1348 | "optional": true 1349 | } 1350 | }, 1351 | "dereferencesTo": "sanity.imageAsset" 1352 | }, 1353 | "optional": true 1354 | }, 1355 | "hotspot": { 1356 | "type": "objectAttribute", 1357 | "value": { 1358 | "type": "inline", 1359 | "name": "sanity.imageHotspot" 1360 | }, 1361 | "optional": true 1362 | }, 1363 | "crop": { 1364 | "type": "objectAttribute", 1365 | "value": { 1366 | "type": "inline", 1367 | "name": "sanity.imageCrop" 1368 | }, 1369 | "optional": true 1370 | }, 1371 | "_type": { 1372 | "type": "objectAttribute", 1373 | "value": { 1374 | "type": "string", 1375 | "value": "image" 1376 | } 1377 | } 1378 | } 1379 | }, 1380 | "optional": true 1381 | } 1382 | } 1383 | }, 1384 | { 1385 | "name": "page", 1386 | "type": "document", 1387 | "attributes": { 1388 | "_id": { 1389 | "type": "objectAttribute", 1390 | "value": { 1391 | "type": "string" 1392 | } 1393 | }, 1394 | "_type": { 1395 | "type": "objectAttribute", 1396 | "value": { 1397 | "type": "string", 1398 | "value": "page" 1399 | } 1400 | }, 1401 | "_createdAt": { 1402 | "type": "objectAttribute", 1403 | "value": { 1404 | "type": "string" 1405 | } 1406 | }, 1407 | "_updatedAt": { 1408 | "type": "objectAttribute", 1409 | "value": { 1410 | "type": "string" 1411 | } 1412 | }, 1413 | "_rev": { 1414 | "type": "objectAttribute", 1415 | "value": { 1416 | "type": "string" 1417 | } 1418 | }, 1419 | "name": { 1420 | "type": "objectAttribute", 1421 | "value": { 1422 | "type": "string" 1423 | }, 1424 | "optional": false 1425 | }, 1426 | "slug": { 1427 | "type": "objectAttribute", 1428 | "value": { 1429 | "type": "inline", 1430 | "name": "slug" 1431 | }, 1432 | "optional": false 1433 | }, 1434 | "heading": { 1435 | "type": "objectAttribute", 1436 | "value": { 1437 | "type": "string" 1438 | }, 1439 | "optional": false 1440 | }, 1441 | "subheading": { 1442 | "type": "objectAttribute", 1443 | "value": { 1444 | "type": "string" 1445 | }, 1446 | "optional": true 1447 | }, 1448 | "pageBuilder": { 1449 | "type": "objectAttribute", 1450 | "value": { 1451 | "type": "array", 1452 | "of": { 1453 | "type": "union", 1454 | "of": [ 1455 | { 1456 | "type": "object", 1457 | "attributes": { 1458 | "_key": { 1459 | "type": "objectAttribute", 1460 | "value": { 1461 | "type": "string" 1462 | } 1463 | } 1464 | }, 1465 | "rest": { 1466 | "type": "inline", 1467 | "name": "callToAction" 1468 | } 1469 | }, 1470 | { 1471 | "type": "object", 1472 | "attributes": { 1473 | "_key": { 1474 | "type": "objectAttribute", 1475 | "value": { 1476 | "type": "string" 1477 | } 1478 | } 1479 | }, 1480 | "rest": { 1481 | "type": "inline", 1482 | "name": "infoSection" 1483 | } 1484 | } 1485 | ] 1486 | } 1487 | }, 1488 | "optional": true 1489 | }, 1490 | "seoTitle": { 1491 | "type": "objectAttribute", 1492 | "value": { 1493 | "type": "string" 1494 | }, 1495 | "optional": true 1496 | }, 1497 | "seoDescription": { 1498 | "type": "objectAttribute", 1499 | "value": { 1500 | "type": "string" 1501 | }, 1502 | "optional": true 1503 | } 1504 | } 1505 | }, 1506 | { 1507 | "name": "post", 1508 | "type": "document", 1509 | "attributes": { 1510 | "_id": { 1511 | "type": "objectAttribute", 1512 | "value": { 1513 | "type": "string" 1514 | } 1515 | }, 1516 | "_type": { 1517 | "type": "objectAttribute", 1518 | "value": { 1519 | "type": "string", 1520 | "value": "post" 1521 | } 1522 | }, 1523 | "_createdAt": { 1524 | "type": "objectAttribute", 1525 | "value": { 1526 | "type": "string" 1527 | } 1528 | }, 1529 | "_updatedAt": { 1530 | "type": "objectAttribute", 1531 | "value": { 1532 | "type": "string" 1533 | } 1534 | }, 1535 | "_rev": { 1536 | "type": "objectAttribute", 1537 | "value": { 1538 | "type": "string" 1539 | } 1540 | }, 1541 | "title": { 1542 | "type": "objectAttribute", 1543 | "value": { 1544 | "type": "string" 1545 | }, 1546 | "optional": false 1547 | }, 1548 | "slug": { 1549 | "type": "objectAttribute", 1550 | "value": { 1551 | "type": "inline", 1552 | "name": "slug" 1553 | }, 1554 | "optional": false 1555 | }, 1556 | "content": { 1557 | "type": "objectAttribute", 1558 | "value": { 1559 | "type": "inline", 1560 | "name": "blockContent" 1561 | }, 1562 | "optional": true 1563 | }, 1564 | "excerpt": { 1565 | "type": "objectAttribute", 1566 | "value": { 1567 | "type": "string" 1568 | }, 1569 | "optional": true 1570 | }, 1571 | "coverImage": { 1572 | "type": "objectAttribute", 1573 | "value": { 1574 | "type": "object", 1575 | "attributes": { 1576 | "asset": { 1577 | "type": "objectAttribute", 1578 | "value": { 1579 | "type": "object", 1580 | "attributes": { 1581 | "_ref": { 1582 | "type": "objectAttribute", 1583 | "value": { 1584 | "type": "string" 1585 | } 1586 | }, 1587 | "_type": { 1588 | "type": "objectAttribute", 1589 | "value": { 1590 | "type": "string", 1591 | "value": "reference" 1592 | } 1593 | }, 1594 | "_weak": { 1595 | "type": "objectAttribute", 1596 | "value": { 1597 | "type": "boolean" 1598 | }, 1599 | "optional": true 1600 | } 1601 | }, 1602 | "dereferencesTo": "sanity.imageAsset" 1603 | }, 1604 | "optional": true 1605 | }, 1606 | "hotspot": { 1607 | "type": "objectAttribute", 1608 | "value": { 1609 | "type": "inline", 1610 | "name": "sanity.imageHotspot" 1611 | }, 1612 | "optional": true 1613 | }, 1614 | "crop": { 1615 | "type": "objectAttribute", 1616 | "value": { 1617 | "type": "inline", 1618 | "name": "sanity.imageCrop" 1619 | }, 1620 | "optional": true 1621 | }, 1622 | "alt": { 1623 | "type": "objectAttribute", 1624 | "value": { 1625 | "type": "string" 1626 | }, 1627 | "optional": true 1628 | }, 1629 | "_type": { 1630 | "type": "objectAttribute", 1631 | "value": { 1632 | "type": "string", 1633 | "value": "image" 1634 | } 1635 | } 1636 | } 1637 | }, 1638 | "optional": false 1639 | }, 1640 | "date": { 1641 | "type": "objectAttribute", 1642 | "value": { 1643 | "type": "string" 1644 | }, 1645 | "optional": true 1646 | }, 1647 | "author": { 1648 | "type": "objectAttribute", 1649 | "value": { 1650 | "type": "object", 1651 | "attributes": { 1652 | "_ref": { 1653 | "type": "objectAttribute", 1654 | "value": { 1655 | "type": "string" 1656 | } 1657 | }, 1658 | "_type": { 1659 | "type": "objectAttribute", 1660 | "value": { 1661 | "type": "string", 1662 | "value": "reference" 1663 | } 1664 | }, 1665 | "_weak": { 1666 | "type": "objectAttribute", 1667 | "value": { 1668 | "type": "boolean" 1669 | }, 1670 | "optional": true 1671 | } 1672 | }, 1673 | "dereferencesTo": "person" 1674 | }, 1675 | "optional": true 1676 | }, 1677 | "seoTitle": { 1678 | "type": "objectAttribute", 1679 | "value": { 1680 | "type": "string" 1681 | }, 1682 | "optional": true 1683 | }, 1684 | "seoDescription": { 1685 | "type": "objectAttribute", 1686 | "value": { 1687 | "type": "string" 1688 | }, 1689 | "optional": true 1690 | } 1691 | } 1692 | }, 1693 | { 1694 | "name": "person", 1695 | "type": "document", 1696 | "attributes": { 1697 | "_id": { 1698 | "type": "objectAttribute", 1699 | "value": { 1700 | "type": "string" 1701 | } 1702 | }, 1703 | "_type": { 1704 | "type": "objectAttribute", 1705 | "value": { 1706 | "type": "string", 1707 | "value": "person" 1708 | } 1709 | }, 1710 | "_createdAt": { 1711 | "type": "objectAttribute", 1712 | "value": { 1713 | "type": "string" 1714 | } 1715 | }, 1716 | "_updatedAt": { 1717 | "type": "objectAttribute", 1718 | "value": { 1719 | "type": "string" 1720 | } 1721 | }, 1722 | "_rev": { 1723 | "type": "objectAttribute", 1724 | "value": { 1725 | "type": "string" 1726 | } 1727 | }, 1728 | "firstName": { 1729 | "type": "objectAttribute", 1730 | "value": { 1731 | "type": "string" 1732 | }, 1733 | "optional": false 1734 | }, 1735 | "lastName": { 1736 | "type": "objectAttribute", 1737 | "value": { 1738 | "type": "string" 1739 | }, 1740 | "optional": false 1741 | }, 1742 | "picture": { 1743 | "type": "objectAttribute", 1744 | "value": { 1745 | "type": "object", 1746 | "attributes": { 1747 | "asset": { 1748 | "type": "objectAttribute", 1749 | "value": { 1750 | "type": "object", 1751 | "attributes": { 1752 | "_ref": { 1753 | "type": "objectAttribute", 1754 | "value": { 1755 | "type": "string" 1756 | } 1757 | }, 1758 | "_type": { 1759 | "type": "objectAttribute", 1760 | "value": { 1761 | "type": "string", 1762 | "value": "reference" 1763 | } 1764 | }, 1765 | "_weak": { 1766 | "type": "objectAttribute", 1767 | "value": { 1768 | "type": "boolean" 1769 | }, 1770 | "optional": true 1771 | } 1772 | }, 1773 | "dereferencesTo": "sanity.imageAsset" 1774 | }, 1775 | "optional": true 1776 | }, 1777 | "hotspot": { 1778 | "type": "objectAttribute", 1779 | "value": { 1780 | "type": "inline", 1781 | "name": "sanity.imageHotspot" 1782 | }, 1783 | "optional": true 1784 | }, 1785 | "crop": { 1786 | "type": "objectAttribute", 1787 | "value": { 1788 | "type": "inline", 1789 | "name": "sanity.imageCrop" 1790 | }, 1791 | "optional": true 1792 | }, 1793 | "alt": { 1794 | "type": "objectAttribute", 1795 | "value": { 1796 | "type": "string" 1797 | }, 1798 | "optional": true 1799 | }, 1800 | "_type": { 1801 | "type": "objectAttribute", 1802 | "value": { 1803 | "type": "string", 1804 | "value": "image" 1805 | } 1806 | } 1807 | } 1808 | }, 1809 | "optional": false 1810 | } 1811 | } 1812 | }, 1813 | { 1814 | "name": "sanity.imageCrop", 1815 | "type": "type", 1816 | "value": { 1817 | "type": "object", 1818 | "attributes": { 1819 | "_type": { 1820 | "type": "objectAttribute", 1821 | "value": { 1822 | "type": "string", 1823 | "value": "sanity.imageCrop" 1824 | } 1825 | }, 1826 | "top": { 1827 | "type": "objectAttribute", 1828 | "value": { 1829 | "type": "number" 1830 | }, 1831 | "optional": true 1832 | }, 1833 | "bottom": { 1834 | "type": "objectAttribute", 1835 | "value": { 1836 | "type": "number" 1837 | }, 1838 | "optional": true 1839 | }, 1840 | "left": { 1841 | "type": "objectAttribute", 1842 | "value": { 1843 | "type": "number" 1844 | }, 1845 | "optional": true 1846 | }, 1847 | "right": { 1848 | "type": "objectAttribute", 1849 | "value": { 1850 | "type": "number" 1851 | }, 1852 | "optional": true 1853 | } 1854 | } 1855 | } 1856 | }, 1857 | { 1858 | "name": "sanity.imageHotspot", 1859 | "type": "type", 1860 | "value": { 1861 | "type": "object", 1862 | "attributes": { 1863 | "_type": { 1864 | "type": "objectAttribute", 1865 | "value": { 1866 | "type": "string", 1867 | "value": "sanity.imageHotspot" 1868 | } 1869 | }, 1870 | "x": { 1871 | "type": "objectAttribute", 1872 | "value": { 1873 | "type": "number" 1874 | }, 1875 | "optional": true 1876 | }, 1877 | "y": { 1878 | "type": "objectAttribute", 1879 | "value": { 1880 | "type": "number" 1881 | }, 1882 | "optional": true 1883 | }, 1884 | "height": { 1885 | "type": "objectAttribute", 1886 | "value": { 1887 | "type": "number" 1888 | }, 1889 | "optional": true 1890 | }, 1891 | "width": { 1892 | "type": "objectAttribute", 1893 | "value": { 1894 | "type": "number" 1895 | }, 1896 | "optional": true 1897 | } 1898 | } 1899 | } 1900 | }, 1901 | { 1902 | "name": "sanity.imageAsset", 1903 | "type": "document", 1904 | "attributes": { 1905 | "_id": { 1906 | "type": "objectAttribute", 1907 | "value": { 1908 | "type": "string" 1909 | } 1910 | }, 1911 | "_type": { 1912 | "type": "objectAttribute", 1913 | "value": { 1914 | "type": "string", 1915 | "value": "sanity.imageAsset" 1916 | } 1917 | }, 1918 | "_createdAt": { 1919 | "type": "objectAttribute", 1920 | "value": { 1921 | "type": "string" 1922 | } 1923 | }, 1924 | "_updatedAt": { 1925 | "type": "objectAttribute", 1926 | "value": { 1927 | "type": "string" 1928 | } 1929 | }, 1930 | "_rev": { 1931 | "type": "objectAttribute", 1932 | "value": { 1933 | "type": "string" 1934 | } 1935 | }, 1936 | "originalFilename": { 1937 | "type": "objectAttribute", 1938 | "value": { 1939 | "type": "string" 1940 | }, 1941 | "optional": true 1942 | }, 1943 | "label": { 1944 | "type": "objectAttribute", 1945 | "value": { 1946 | "type": "string" 1947 | }, 1948 | "optional": true 1949 | }, 1950 | "title": { 1951 | "type": "objectAttribute", 1952 | "value": { 1953 | "type": "string" 1954 | }, 1955 | "optional": true 1956 | }, 1957 | "description": { 1958 | "type": "objectAttribute", 1959 | "value": { 1960 | "type": "string" 1961 | }, 1962 | "optional": true 1963 | }, 1964 | "altText": { 1965 | "type": "objectAttribute", 1966 | "value": { 1967 | "type": "string" 1968 | }, 1969 | "optional": true 1970 | }, 1971 | "sha1hash": { 1972 | "type": "objectAttribute", 1973 | "value": { 1974 | "type": "string" 1975 | }, 1976 | "optional": true 1977 | }, 1978 | "extension": { 1979 | "type": "objectAttribute", 1980 | "value": { 1981 | "type": "string" 1982 | }, 1983 | "optional": true 1984 | }, 1985 | "mimeType": { 1986 | "type": "objectAttribute", 1987 | "value": { 1988 | "type": "string" 1989 | }, 1990 | "optional": true 1991 | }, 1992 | "size": { 1993 | "type": "objectAttribute", 1994 | "value": { 1995 | "type": "number" 1996 | }, 1997 | "optional": true 1998 | }, 1999 | "assetId": { 2000 | "type": "objectAttribute", 2001 | "value": { 2002 | "type": "string" 2003 | }, 2004 | "optional": true 2005 | }, 2006 | "uploadId": { 2007 | "type": "objectAttribute", 2008 | "value": { 2009 | "type": "string" 2010 | }, 2011 | "optional": true 2012 | }, 2013 | "path": { 2014 | "type": "objectAttribute", 2015 | "value": { 2016 | "type": "string" 2017 | }, 2018 | "optional": true 2019 | }, 2020 | "url": { 2021 | "type": "objectAttribute", 2022 | "value": { 2023 | "type": "string" 2024 | }, 2025 | "optional": true 2026 | }, 2027 | "metadata": { 2028 | "type": "objectAttribute", 2029 | "value": { 2030 | "type": "inline", 2031 | "name": "sanity.imageMetadata" 2032 | }, 2033 | "optional": true 2034 | }, 2035 | "source": { 2036 | "type": "objectAttribute", 2037 | "value": { 2038 | "type": "inline", 2039 | "name": "sanity.assetSourceData" 2040 | }, 2041 | "optional": true 2042 | } 2043 | } 2044 | }, 2045 | { 2046 | "name": "sanity.assetSourceData", 2047 | "type": "type", 2048 | "value": { 2049 | "type": "object", 2050 | "attributes": { 2051 | "_type": { 2052 | "type": "objectAttribute", 2053 | "value": { 2054 | "type": "string", 2055 | "value": "sanity.assetSourceData" 2056 | } 2057 | }, 2058 | "name": { 2059 | "type": "objectAttribute", 2060 | "value": { 2061 | "type": "string" 2062 | }, 2063 | "optional": true 2064 | }, 2065 | "id": { 2066 | "type": "objectAttribute", 2067 | "value": { 2068 | "type": "string" 2069 | }, 2070 | "optional": true 2071 | }, 2072 | "url": { 2073 | "type": "objectAttribute", 2074 | "value": { 2075 | "type": "string" 2076 | }, 2077 | "optional": true 2078 | } 2079 | } 2080 | } 2081 | }, 2082 | { 2083 | "name": "sanity.imageMetadata", 2084 | "type": "type", 2085 | "value": { 2086 | "type": "object", 2087 | "attributes": { 2088 | "_type": { 2089 | "type": "objectAttribute", 2090 | "value": { 2091 | "type": "string", 2092 | "value": "sanity.imageMetadata" 2093 | } 2094 | }, 2095 | "location": { 2096 | "type": "objectAttribute", 2097 | "value": { 2098 | "type": "inline", 2099 | "name": "geopoint" 2100 | }, 2101 | "optional": true 2102 | }, 2103 | "dimensions": { 2104 | "type": "objectAttribute", 2105 | "value": { 2106 | "type": "inline", 2107 | "name": "sanity.imageDimensions" 2108 | }, 2109 | "optional": true 2110 | }, 2111 | "palette": { 2112 | "type": "objectAttribute", 2113 | "value": { 2114 | "type": "inline", 2115 | "name": "sanity.imagePalette" 2116 | }, 2117 | "optional": true 2118 | }, 2119 | "lqip": { 2120 | "type": "objectAttribute", 2121 | "value": { 2122 | "type": "string" 2123 | }, 2124 | "optional": true 2125 | }, 2126 | "blurHash": { 2127 | "type": "objectAttribute", 2128 | "value": { 2129 | "type": "string" 2130 | }, 2131 | "optional": true 2132 | }, 2133 | "hasAlpha": { 2134 | "type": "objectAttribute", 2135 | "value": { 2136 | "type": "boolean" 2137 | }, 2138 | "optional": true 2139 | }, 2140 | "isOpaque": { 2141 | "type": "objectAttribute", 2142 | "value": { 2143 | "type": "boolean" 2144 | }, 2145 | "optional": true 2146 | } 2147 | } 2148 | } 2149 | }, 2150 | { 2151 | "name": "slug", 2152 | "type": "type", 2153 | "value": { 2154 | "type": "object", 2155 | "attributes": { 2156 | "_type": { 2157 | "type": "objectAttribute", 2158 | "value": { 2159 | "type": "string", 2160 | "value": "slug" 2161 | } 2162 | }, 2163 | "current": { 2164 | "type": "objectAttribute", 2165 | "value": { 2166 | "type": "string" 2167 | }, 2168 | "optional": false 2169 | }, 2170 | "source": { 2171 | "type": "objectAttribute", 2172 | "value": { 2173 | "type": "string" 2174 | }, 2175 | "optional": true 2176 | } 2177 | } 2178 | } 2179 | }, 2180 | { 2181 | "name": "sanity.assist.instructionTask", 2182 | "type": "type", 2183 | "value": { 2184 | "type": "object", 2185 | "attributes": { 2186 | "_type": { 2187 | "type": "objectAttribute", 2188 | "value": { 2189 | "type": "string", 2190 | "value": "sanity.assist.instructionTask" 2191 | } 2192 | }, 2193 | "path": { 2194 | "type": "objectAttribute", 2195 | "value": { 2196 | "type": "string" 2197 | }, 2198 | "optional": true 2199 | }, 2200 | "instructionKey": { 2201 | "type": "objectAttribute", 2202 | "value": { 2203 | "type": "string" 2204 | }, 2205 | "optional": true 2206 | }, 2207 | "started": { 2208 | "type": "objectAttribute", 2209 | "value": { 2210 | "type": "string" 2211 | }, 2212 | "optional": true 2213 | }, 2214 | "updated": { 2215 | "type": "objectAttribute", 2216 | "value": { 2217 | "type": "string" 2218 | }, 2219 | "optional": true 2220 | }, 2221 | "info": { 2222 | "type": "objectAttribute", 2223 | "value": { 2224 | "type": "string" 2225 | }, 2226 | "optional": true 2227 | } 2228 | } 2229 | } 2230 | }, 2231 | { 2232 | "name": "sanity.assist.task.status", 2233 | "type": "type", 2234 | "value": { 2235 | "type": "object", 2236 | "attributes": { 2237 | "_type": { 2238 | "type": "objectAttribute", 2239 | "value": { 2240 | "type": "string", 2241 | "value": "sanity.assist.task.status" 2242 | } 2243 | }, 2244 | "tasks": { 2245 | "type": "objectAttribute", 2246 | "value": { 2247 | "type": "array", 2248 | "of": { 2249 | "type": "object", 2250 | "attributes": { 2251 | "_key": { 2252 | "type": "objectAttribute", 2253 | "value": { 2254 | "type": "string" 2255 | } 2256 | } 2257 | }, 2258 | "rest": { 2259 | "type": "inline", 2260 | "name": "sanity.assist.instructionTask" 2261 | } 2262 | } 2263 | }, 2264 | "optional": true 2265 | } 2266 | } 2267 | } 2268 | }, 2269 | { 2270 | "name": "sanity.assist.schemaType.annotations", 2271 | "type": "type", 2272 | "value": { 2273 | "type": "object", 2274 | "attributes": { 2275 | "_type": { 2276 | "type": "objectAttribute", 2277 | "value": { 2278 | "type": "string", 2279 | "value": "sanity.assist.schemaType.annotations" 2280 | } 2281 | }, 2282 | "title": { 2283 | "type": "objectAttribute", 2284 | "value": { 2285 | "type": "string" 2286 | }, 2287 | "optional": true 2288 | }, 2289 | "fields": { 2290 | "type": "objectAttribute", 2291 | "value": { 2292 | "type": "array", 2293 | "of": { 2294 | "type": "object", 2295 | "attributes": { 2296 | "_key": { 2297 | "type": "objectAttribute", 2298 | "value": { 2299 | "type": "string" 2300 | } 2301 | } 2302 | }, 2303 | "rest": { 2304 | "type": "inline", 2305 | "name": "sanity.assist.schemaType.field" 2306 | } 2307 | } 2308 | }, 2309 | "optional": true 2310 | } 2311 | } 2312 | } 2313 | }, 2314 | { 2315 | "name": "sanity.assist.output.type", 2316 | "type": "type", 2317 | "value": { 2318 | "type": "object", 2319 | "attributes": { 2320 | "_type": { 2321 | "type": "objectAttribute", 2322 | "value": { 2323 | "type": "string", 2324 | "value": "sanity.assist.output.type" 2325 | } 2326 | }, 2327 | "type": { 2328 | "type": "objectAttribute", 2329 | "value": { 2330 | "type": "string" 2331 | }, 2332 | "optional": true 2333 | } 2334 | } 2335 | } 2336 | }, 2337 | { 2338 | "name": "sanity.assist.output.field", 2339 | "type": "type", 2340 | "value": { 2341 | "type": "object", 2342 | "attributes": { 2343 | "_type": { 2344 | "type": "objectAttribute", 2345 | "value": { 2346 | "type": "string", 2347 | "value": "sanity.assist.output.field" 2348 | } 2349 | }, 2350 | "path": { 2351 | "type": "objectAttribute", 2352 | "value": { 2353 | "type": "string" 2354 | }, 2355 | "optional": true 2356 | } 2357 | } 2358 | } 2359 | }, 2360 | { 2361 | "name": "sanity.assist.instruction.context", 2362 | "type": "type", 2363 | "value": { 2364 | "type": "object", 2365 | "attributes": { 2366 | "_type": { 2367 | "type": "objectAttribute", 2368 | "value": { 2369 | "type": "string", 2370 | "value": "sanity.assist.instruction.context" 2371 | } 2372 | }, 2373 | "reference": { 2374 | "type": "objectAttribute", 2375 | "value": { 2376 | "type": "object", 2377 | "attributes": { 2378 | "_ref": { 2379 | "type": "objectAttribute", 2380 | "value": { 2381 | "type": "string" 2382 | } 2383 | }, 2384 | "_type": { 2385 | "type": "objectAttribute", 2386 | "value": { 2387 | "type": "string", 2388 | "value": "reference" 2389 | } 2390 | }, 2391 | "_weak": { 2392 | "type": "objectAttribute", 2393 | "value": { 2394 | "type": "boolean" 2395 | }, 2396 | "optional": true 2397 | } 2398 | }, 2399 | "dereferencesTo": "assist.instruction.context" 2400 | }, 2401 | "optional": false 2402 | } 2403 | } 2404 | } 2405 | }, 2406 | { 2407 | "name": "assist.instruction.context", 2408 | "type": "document", 2409 | "attributes": { 2410 | "_id": { 2411 | "type": "objectAttribute", 2412 | "value": { 2413 | "type": "string" 2414 | } 2415 | }, 2416 | "_type": { 2417 | "type": "objectAttribute", 2418 | "value": { 2419 | "type": "string", 2420 | "value": "assist.instruction.context" 2421 | } 2422 | }, 2423 | "_createdAt": { 2424 | "type": "objectAttribute", 2425 | "value": { 2426 | "type": "string" 2427 | } 2428 | }, 2429 | "_updatedAt": { 2430 | "type": "objectAttribute", 2431 | "value": { 2432 | "type": "string" 2433 | } 2434 | }, 2435 | "_rev": { 2436 | "type": "objectAttribute", 2437 | "value": { 2438 | "type": "string" 2439 | } 2440 | }, 2441 | "title": { 2442 | "type": "objectAttribute", 2443 | "value": { 2444 | "type": "string" 2445 | }, 2446 | "optional": true 2447 | }, 2448 | "context": { 2449 | "type": "objectAttribute", 2450 | "value": { 2451 | "type": "array", 2452 | "of": { 2453 | "type": "object", 2454 | "attributes": { 2455 | "children": { 2456 | "type": "objectAttribute", 2457 | "value": { 2458 | "type": "array", 2459 | "of": { 2460 | "type": "object", 2461 | "attributes": { 2462 | "marks": { 2463 | "type": "objectAttribute", 2464 | "value": { 2465 | "type": "array", 2466 | "of": { 2467 | "type": "string" 2468 | } 2469 | }, 2470 | "optional": true 2471 | }, 2472 | "text": { 2473 | "type": "objectAttribute", 2474 | "value": { 2475 | "type": "string" 2476 | }, 2477 | "optional": true 2478 | }, 2479 | "_type": { 2480 | "type": "objectAttribute", 2481 | "value": { 2482 | "type": "string", 2483 | "value": "span" 2484 | } 2485 | } 2486 | }, 2487 | "rest": { 2488 | "type": "object", 2489 | "attributes": { 2490 | "_key": { 2491 | "type": "objectAttribute", 2492 | "value": { 2493 | "type": "string" 2494 | } 2495 | } 2496 | } 2497 | } 2498 | } 2499 | }, 2500 | "optional": true 2501 | }, 2502 | "style": { 2503 | "type": "objectAttribute", 2504 | "value": { 2505 | "type": "union", 2506 | "of": [ 2507 | { 2508 | "type": "string", 2509 | "value": "normal" 2510 | } 2511 | ] 2512 | }, 2513 | "optional": true 2514 | }, 2515 | "listItem": { 2516 | "type": "objectAttribute", 2517 | "value": { 2518 | "type": "union", 2519 | "of": [] 2520 | }, 2521 | "optional": true 2522 | }, 2523 | "markDefs": { 2524 | "type": "objectAttribute", 2525 | "value": { 2526 | "type": "null" 2527 | }, 2528 | "optional": true 2529 | }, 2530 | "level": { 2531 | "type": "objectAttribute", 2532 | "value": { 2533 | "type": "number" 2534 | }, 2535 | "optional": true 2536 | }, 2537 | "_type": { 2538 | "type": "objectAttribute", 2539 | "value": { 2540 | "type": "string", 2541 | "value": "block" 2542 | } 2543 | } 2544 | }, 2545 | "rest": { 2546 | "type": "object", 2547 | "attributes": { 2548 | "_key": { 2549 | "type": "objectAttribute", 2550 | "value": { 2551 | "type": "string" 2552 | } 2553 | } 2554 | } 2555 | } 2556 | } 2557 | }, 2558 | "optional": true 2559 | } 2560 | } 2561 | }, 2562 | { 2563 | "name": "sanity.assist.instruction.userInput", 2564 | "type": "type", 2565 | "value": { 2566 | "type": "object", 2567 | "attributes": { 2568 | "_type": { 2569 | "type": "objectAttribute", 2570 | "value": { 2571 | "type": "string", 2572 | "value": "sanity.assist.instruction.userInput" 2573 | } 2574 | }, 2575 | "message": { 2576 | "type": "objectAttribute", 2577 | "value": { 2578 | "type": "string" 2579 | }, 2580 | "optional": false 2581 | }, 2582 | "description": { 2583 | "type": "objectAttribute", 2584 | "value": { 2585 | "type": "string" 2586 | }, 2587 | "optional": true 2588 | } 2589 | } 2590 | } 2591 | }, 2592 | { 2593 | "name": "sanity.assist.instruction.prompt", 2594 | "type": "type", 2595 | "value": { 2596 | "type": "array", 2597 | "of": { 2598 | "type": "object", 2599 | "attributes": { 2600 | "children": { 2601 | "type": "objectAttribute", 2602 | "value": { 2603 | "type": "array", 2604 | "of": { 2605 | "type": "union", 2606 | "of": [ 2607 | { 2608 | "type": "object", 2609 | "attributes": { 2610 | "marks": { 2611 | "type": "objectAttribute", 2612 | "value": { 2613 | "type": "array", 2614 | "of": { 2615 | "type": "string" 2616 | } 2617 | }, 2618 | "optional": true 2619 | }, 2620 | "text": { 2621 | "type": "objectAttribute", 2622 | "value": { 2623 | "type": "string" 2624 | }, 2625 | "optional": true 2626 | }, 2627 | "_type": { 2628 | "type": "objectAttribute", 2629 | "value": { 2630 | "type": "string", 2631 | "value": "span" 2632 | } 2633 | } 2634 | }, 2635 | "rest": { 2636 | "type": "object", 2637 | "attributes": { 2638 | "_key": { 2639 | "type": "objectAttribute", 2640 | "value": { 2641 | "type": "string" 2642 | } 2643 | } 2644 | } 2645 | } 2646 | }, 2647 | { 2648 | "type": "object", 2649 | "attributes": { 2650 | "_key": { 2651 | "type": "objectAttribute", 2652 | "value": { 2653 | "type": "string" 2654 | } 2655 | } 2656 | }, 2657 | "rest": { 2658 | "type": "inline", 2659 | "name": "sanity.assist.instruction.fieldRef" 2660 | } 2661 | }, 2662 | { 2663 | "type": "object", 2664 | "attributes": { 2665 | "_key": { 2666 | "type": "objectAttribute", 2667 | "value": { 2668 | "type": "string" 2669 | } 2670 | } 2671 | }, 2672 | "rest": { 2673 | "type": "inline", 2674 | "name": "sanity.assist.instruction.context" 2675 | } 2676 | }, 2677 | { 2678 | "type": "object", 2679 | "attributes": { 2680 | "_key": { 2681 | "type": "objectAttribute", 2682 | "value": { 2683 | "type": "string" 2684 | } 2685 | } 2686 | }, 2687 | "rest": { 2688 | "type": "inline", 2689 | "name": "sanity.assist.instruction.userInput" 2690 | } 2691 | } 2692 | ] 2693 | } 2694 | }, 2695 | "optional": true 2696 | }, 2697 | "style": { 2698 | "type": "objectAttribute", 2699 | "value": { 2700 | "type": "union", 2701 | "of": [ 2702 | { 2703 | "type": "string", 2704 | "value": "normal" 2705 | } 2706 | ] 2707 | }, 2708 | "optional": true 2709 | }, 2710 | "listItem": { 2711 | "type": "objectAttribute", 2712 | "value": { 2713 | "type": "union", 2714 | "of": [] 2715 | }, 2716 | "optional": true 2717 | }, 2718 | "markDefs": { 2719 | "type": "objectAttribute", 2720 | "value": { 2721 | "type": "null" 2722 | }, 2723 | "optional": true 2724 | }, 2725 | "level": { 2726 | "type": "objectAttribute", 2727 | "value": { 2728 | "type": "number" 2729 | }, 2730 | "optional": true 2731 | }, 2732 | "_type": { 2733 | "type": "objectAttribute", 2734 | "value": { 2735 | "type": "string", 2736 | "value": "block" 2737 | } 2738 | } 2739 | }, 2740 | "rest": { 2741 | "type": "object", 2742 | "attributes": { 2743 | "_key": { 2744 | "type": "objectAttribute", 2745 | "value": { 2746 | "type": "string" 2747 | } 2748 | } 2749 | } 2750 | } 2751 | } 2752 | } 2753 | }, 2754 | { 2755 | "name": "sanity.assist.instruction.fieldRef", 2756 | "type": "type", 2757 | "value": { 2758 | "type": "object", 2759 | "attributes": { 2760 | "_type": { 2761 | "type": "objectAttribute", 2762 | "value": { 2763 | "type": "string", 2764 | "value": "sanity.assist.instruction.fieldRef" 2765 | } 2766 | }, 2767 | "path": { 2768 | "type": "objectAttribute", 2769 | "value": { 2770 | "type": "string" 2771 | }, 2772 | "optional": true 2773 | } 2774 | } 2775 | } 2776 | }, 2777 | { 2778 | "name": "sanity.assist.instruction", 2779 | "type": "type", 2780 | "value": { 2781 | "type": "object", 2782 | "attributes": { 2783 | "_type": { 2784 | "type": "objectAttribute", 2785 | "value": { 2786 | "type": "string", 2787 | "value": "sanity.assist.instruction" 2788 | } 2789 | }, 2790 | "prompt": { 2791 | "type": "objectAttribute", 2792 | "value": { 2793 | "type": "inline", 2794 | "name": "sanity.assist.instruction.prompt" 2795 | }, 2796 | "optional": true 2797 | }, 2798 | "icon": { 2799 | "type": "objectAttribute", 2800 | "value": { 2801 | "type": "string" 2802 | }, 2803 | "optional": true 2804 | }, 2805 | "title": { 2806 | "type": "objectAttribute", 2807 | "value": { 2808 | "type": "string" 2809 | }, 2810 | "optional": true 2811 | }, 2812 | "userId": { 2813 | "type": "objectAttribute", 2814 | "value": { 2815 | "type": "string" 2816 | }, 2817 | "optional": true 2818 | }, 2819 | "createdById": { 2820 | "type": "objectAttribute", 2821 | "value": { 2822 | "type": "string" 2823 | }, 2824 | "optional": true 2825 | }, 2826 | "output": { 2827 | "type": "objectAttribute", 2828 | "value": { 2829 | "type": "array", 2830 | "of": { 2831 | "type": "union", 2832 | "of": [ 2833 | { 2834 | "type": "object", 2835 | "attributes": { 2836 | "_key": { 2837 | "type": "objectAttribute", 2838 | "value": { 2839 | "type": "string" 2840 | } 2841 | } 2842 | }, 2843 | "rest": { 2844 | "type": "inline", 2845 | "name": "sanity.assist.output.field" 2846 | } 2847 | }, 2848 | { 2849 | "type": "object", 2850 | "attributes": { 2851 | "_key": { 2852 | "type": "objectAttribute", 2853 | "value": { 2854 | "type": "string" 2855 | } 2856 | } 2857 | }, 2858 | "rest": { 2859 | "type": "inline", 2860 | "name": "sanity.assist.output.type" 2861 | } 2862 | } 2863 | ] 2864 | } 2865 | }, 2866 | "optional": true 2867 | } 2868 | } 2869 | } 2870 | }, 2871 | { 2872 | "name": "sanity.assist.schemaType.field", 2873 | "type": "type", 2874 | "value": { 2875 | "type": "object", 2876 | "attributes": { 2877 | "_type": { 2878 | "type": "objectAttribute", 2879 | "value": { 2880 | "type": "string", 2881 | "value": "sanity.assist.schemaType.field" 2882 | } 2883 | }, 2884 | "path": { 2885 | "type": "objectAttribute", 2886 | "value": { 2887 | "type": "string" 2888 | }, 2889 | "optional": true 2890 | }, 2891 | "instructions": { 2892 | "type": "objectAttribute", 2893 | "value": { 2894 | "type": "array", 2895 | "of": { 2896 | "type": "object", 2897 | "attributes": { 2898 | "_key": { 2899 | "type": "objectAttribute", 2900 | "value": { 2901 | "type": "string" 2902 | } 2903 | } 2904 | }, 2905 | "rest": { 2906 | "type": "inline", 2907 | "name": "sanity.assist.instruction" 2908 | } 2909 | } 2910 | }, 2911 | "optional": true 2912 | } 2913 | } 2914 | } 2915 | } 2916 | ] 2917 | --------------------------------------------------------------------------------