├── .eslintrc.js ├── .github ├── CODEOWNERS ├── renovate.json └── workflows │ ├── lock.yml │ ├── main.yml │ ├── prettier.yml │ └── release-please.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.cjs ├── LICENSE ├── README.md ├── apps ├── example-ssr │ ├── .gitignore │ ├── .vscode │ │ ├── extensions.json │ │ └── launch.json │ ├── README.md │ ├── astro.config.mjs │ ├── package.json │ ├── public │ │ └── favicon.svg │ ├── sanity.config.ts │ ├── schemas │ │ ├── .gitkeep │ │ └── index.ts │ ├── src │ │ ├── components │ │ │ ├── CallToActionBox.astro │ │ │ ├── Code.astro │ │ │ ├── Debug.astro │ │ │ ├── InternalLink.astro │ │ │ ├── NewsBar.jsx │ │ │ ├── PortableText.astro │ │ │ ├── SanityImage.astro │ │ │ └── YouTube.astro │ │ ├── env.d.ts │ │ ├── layouts │ │ │ └── Layout.astro │ │ └── pages │ │ │ ├── index.astro │ │ │ └── posts │ │ │ └── [slug].astro │ └── tsconfig.json ├── example │ ├── .gitignore │ ├── .vscode │ │ ├── extensions.json │ │ └── launch.json │ ├── README.md │ ├── astro.config.mjs │ ├── package.json │ ├── public │ │ └── favicon.svg │ ├── sanity.config.ts │ ├── schemas │ │ ├── .gitkeep │ │ └── index.ts │ ├── src │ │ ├── components │ │ │ ├── CallToActionBox.astro │ │ │ ├── Code.astro │ │ │ ├── Debug.astro │ │ │ ├── InternalLink.astro │ │ │ ├── NewsBar.jsx │ │ │ ├── PortableText.astro │ │ │ ├── SanityImage.astro │ │ │ └── YouTube.astro │ │ ├── env.d.ts │ │ ├── layouts │ │ │ └── Layout.astro │ │ └── pages │ │ │ ├── index.astro │ │ │ └── posts │ │ │ └── [slug].astro │ └── tsconfig.json └── movies │ ├── .gitignore │ ├── .vscode │ ├── extensions.json │ └── launch.json │ ├── README.md │ ├── astro.config.mjs │ ├── package.json │ ├── public │ └── favicon.svg │ ├── sanity.cli.ts │ ├── sanity.config.ts │ ├── schemaTypes │ ├── blockContent.ts │ ├── castMember.ts │ ├── crewMember.ts │ ├── index.ts │ ├── movie.ts │ ├── person.ts │ ├── plotSummaries.ts │ ├── plotSummary.ts │ └── screening.ts │ ├── src │ ├── env.d.ts │ ├── layout.astro │ ├── load-query.ts │ └── pages │ │ └── index.astro │ └── tsconfig.json ├── package.json ├── packages └── sanity-astro │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── module.d.ts │ ├── package.json │ ├── src │ ├── env.d.ts │ ├── index.ts │ ├── studio │ │ ├── studio-component.tsx │ │ ├── studio-route-hash.astro │ │ ├── studio-route.astro │ │ └── studio-route.ts │ ├── visual-editing │ │ ├── index.ts │ │ ├── visual-editing-component.tsx │ │ └── visual-editing.astro │ ├── vite-plugin-sanity-client.ts │ ├── vite-plugin-sanity-studio-hash-router.ts │ └── vite-plugin-sanity-studio.ts │ ├── tsconfig.json │ └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // This tells ESLint to load the config from the package `eslint-config-custom` 4 | extends: ['custom'], 5 | settings: { 6 | next: { 7 | rootDir: ['apps/*/'], 8 | }, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sanity-io/ecosystem 2 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>sanity-io/renovate-config", ":reviewer(team:ecosystem)"], 4 | "ignorePresets": [":ignoreModulesAndTests", "github>sanity-io/renovate-config:group-non-major"], 5 | "packageRules": [ 6 | { 7 | "group": { 8 | "semanticCommitType": "chore" 9 | }, 10 | "matchDepTypes": ["dependencies", "engines", "optionalDependencies", "peerDependencies"], 11 | "matchManagers": ["npm"], 12 | "semanticCommitType": "chore", 13 | "description": "Group all dependencies from the apps directory", 14 | "matchFileNames": ["apps/**/package.json"], 15 | "groupName": "Apps dependencies" 16 | }, 17 | { 18 | "matchDepTypes": ["dependencies"], 19 | "rangeStrategy": "bump" 20 | }, 21 | { 22 | "matchDepTypes": ["peerDependencies"], 23 | "rangeStrategy": "bump", 24 | "matchPackageNames": ["!astro", "!react", "!react-dom", "!react-is"], 25 | "semanticCommitType": "fix" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lock Threads 3 | 4 | on: 5 | issues: 6 | types: [closed] 7 | pull_request: 8 | types: [closed] 9 | schedule: 10 | - cron: "0 0 * * *" 11 | workflow_dispatch: 12 | 13 | permissions: 14 | issues: write 15 | pull-requests: write 16 | 17 | concurrency: 18 | group: ${{ github.workflow }} 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | action: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5 26 | with: 27 | issue-inactive-days: 1 28 | pr-inactive-days: 7 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 4 | on: 5 | merge_group: 6 | pull_request: 7 | types: [opened, synchronize] 8 | push: 9 | branches: [main] 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 13 | cancel-in-progress: true 14 | 15 | permissions: 16 | contents: read # for checkout 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | env: 22 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 23 | TURBO_TEAM: ${{ vars.TURBO_TEAM }} 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: pnpm/action-setup@v4 27 | - uses: actions/setup-node@v4 28 | with: 29 | cache: pnpm 30 | node-version: lts/* 31 | - run: pnpm install --ignore-scripts 32 | - run: pnpm lint 33 | - run: pnpm build 34 | 35 | test: 36 | needs: build 37 | timeout-minutes: 15 38 | strategy: 39 | # A test failing on windows doesn't mean it'll fail on macos. It's useful to let all tests run to its completion to get the full picture 40 | fail-fast: false 41 | matrix: 42 | # https://nodejs.org/en/about/releases/ 43 | node: [lts/*, current] 44 | os: [ubuntu-latest] 45 | # Also test the LTS on mac and windows 46 | include: 47 | - os: macos-latest 48 | node: lts/* 49 | - os: windows-latest 50 | node: lts/* 51 | runs-on: ${{ matrix.os }} 52 | env: 53 | NODE_VERSION: ${{ matrix.node }} 54 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 55 | TURBO_TEAM: ${{ vars.TURBO_TEAM }} 56 | steps: 57 | # It's only necessary to do this for windows, as mac and ubuntu are sane OS's that already use LF 58 | - if: matrix.os == 'windows-latest' 59 | run: | 60 | git config --global core.autocrlf false 61 | git config --global core.eol lf 62 | - uses: actions/checkout@v4 63 | - uses: pnpm/action-setup@v4 64 | - uses: actions/setup-node@v4 65 | with: 66 | cache: pnpm 67 | node-version: ${{ matrix.node }} 68 | - run: pnpm install 69 | - run: pnpm --if-present --recursive prepublishOnly 70 | -------------------------------------------------------------------------------- /.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 | jobs: 14 | run: 15 | name: Can the code be prettier? 🤔 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: pnpm/action-setup@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | cache: pnpm 23 | node-version: lts/* 24 | - run: pnpm install --dev --ignore-scripts 25 | - uses: actions/cache@v4 26 | with: 27 | path: node_modules/.cache/prettier/.prettier-cache 28 | key: prettier-${{ hashFiles('pnpm-lock.yaml') }} 29 | - run: pnpm format 30 | - run: git restore .github/workflows 31 | - uses: actions/create-github-app-token@v2 32 | id: generate-token 33 | with: 34 | app-id: ${{ secrets.ECOSPARK_APP_ID }} 35 | private-key: ${{ secrets.ECOSPARK_APP_PRIVATE_KEY }} 36 | - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7 37 | with: 38 | body: I ran `pnpm format` 🧑‍💻 39 | branch: actions/prettier 40 | commit-message: "chore(prettier): 🤖 ✨" 41 | labels: 🤖 bot 42 | sign-commits: true 43 | title: "chore(prettier): 🤖 ✨" 44 | token: ${{ steps.generate-token.outputs.token }} 45 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | name: Release Please 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | release-please: 13 | permissions: 14 | contents: read # for checkout 15 | id-token: write # to enable use of OIDC for npm provenance 16 | # permissions for pushing commits and opening PRs are handled by the `generate-token` step 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/create-github-app-token@v2 20 | id: generate-token 21 | with: 22 | app-id: ${{ secrets.ECOSPARK_APP_ID }} 23 | private-key: ${{ secrets.ECOSPARK_APP_PRIVATE_KEY }} 24 | # This action will create a release PR when regular conventional commits are pushed to main, it'll also detect if a release PR is merged and npm publish should happen 25 | - uses: googleapis/release-please-action@v4 26 | id: release 27 | with: 28 | release-type: node 29 | token: ${{ steps.generate-token.outputs.token }} 30 | path: packages/sanity-astro 31 | 32 | # Publish to NPM on new releases 33 | - uses: actions/checkout@v4 34 | if: ${{ steps.release.outputs.releases_created == 'true' }} 35 | - uses: pnpm/action-setup@v4 36 | if: ${{ steps.release.outputs.releases_created == 'true' }} 37 | - uses: actions/setup-node@v4 38 | if: ${{ steps.release.outputs.releases_created == 'true' }} 39 | with: 40 | cache: pnpm 41 | node-version: lts/* 42 | - run: pnpm install --ignore-scripts 43 | if: ${{ steps.release.outputs.releases_created == 'true' }} 44 | - name: Set publishing config 45 | run: pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}" 46 | if: ${{ steps.release.outputs.releases_created == 'true' }} 47 | env: 48 | NODE_AUTH_TOKEN: ${{secrets.NPM_PUBLISH_TOKEN}} 49 | # Release Please has already incremented versions and published tags, so we just 50 | # need to publish the new version to npm here 51 | - run: pnpm -r publish 52 | if: ${{ steps.release.outputs.releases_created == 'true' }} 53 | env: 54 | NPM_CONFIG_PROVENANCE: true 55 | -------------------------------------------------------------------------------- /.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 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # local env files 26 | .env 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | # vercel 36 | .vercel 37 | 38 | # ides 39 | .idea/ 40 | 41 | # Output of 'npm pack' 42 | *.tgz 43 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | CHANGELOG.md 3 | pnpm-lock.yaml 4 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | const preset = require('@sanity/prettier-config') 2 | 3 | /** @type {import("prettier").Config} */ 4 | const config = { 5 | ...preset, 6 | plugins: [...preset.plugins, 'prettier-plugin-astro'], 7 | } 8 | 9 | module.exports = config 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Sanity.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ./packages/sanity-astro/README.md -------------------------------------------------------------------------------- /apps/example-ssr/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | .vercel 23 | .env*.local 24 | -------------------------------------------------------------------------------- /apps/example-ssr/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /apps/example-ssr/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/example-ssr/README.md: -------------------------------------------------------------------------------- 1 | # Sanity + Astro example app 2 | 3 | This example app is the same as the other example app in this repository, except with `output: 'server'` in the Astro configuration. 4 | 5 | This example application renders the Sanity.io blog using Astro. It shows how to configure the Sanity + Astro integration in `astro.config.mjs`, querying and displaying Sanity content in `src/pages/index.astro` and `src/pages/posts/[slug].astro`, how to render PortableText in `src/components/PortableText.astro`, and how to present Sanity images in `src/components/SanityImage.astro`. 6 | -------------------------------------------------------------------------------- /apps/example-ssr/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import sanity from '@sanity/astro' 2 | import {defineConfig} from 'astro/config' 3 | import vercel from '@astrojs/vercel' 4 | import react from '@astrojs/react' 5 | 6 | // https://astro.build/config 7 | export default defineConfig({ 8 | integrations: [ 9 | sanity({ 10 | projectId: '3do82whm', 11 | dataset: 'next', 12 | // If you are doing static builds you may want opt out of the CDN 13 | useCdn: true, 14 | studioBasePath: '/admin', 15 | }), 16 | react(), 17 | ], 18 | output: 'server', 19 | adapter: vercel({ 20 | edgeMiddleware: true, 21 | }), 22 | }) 23 | -------------------------------------------------------------------------------- /apps/example-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-ssr", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "astro": "astro", 7 | "build": "astro build", 8 | "clean": "rimraf .astro && rimraf .turbo && rimraf .vercel && rimraf node_modules", 9 | "dev": "astro dev --port 4323", 10 | "preview": "astro preview", 11 | "start": "astro dev --port 4323" 12 | }, 13 | "dependencies": { 14 | "@astro-community/astro-embed-youtube": "^0.5.6", 15 | "@astrojs/prism": "^3.3.0", 16 | "@astrojs/react": "^4.3.0", 17 | "@astrojs/vercel": "^8.1.4", 18 | "@sanity/astro": "workspace:^", 19 | "@sanity/client": "^7.3.0", 20 | "@sanity/image-url": "^1.1.0", 21 | "@sanity/vision": "^3.90.0", 22 | "astro": "5.4.1", 23 | "astro-portabletext": "^0.11.1", 24 | "react": "^19.1.0", 25 | "react-dom": "^19.1.0", 26 | "sanity": "^3.90.0", 27 | "styled-components": "^6.1.18" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/example-ssr/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-ssr/sanity.config.ts: -------------------------------------------------------------------------------- 1 | import {visionTool} from '@sanity/vision' 2 | import {defineConfig} from 'sanity' 3 | import {deskTool} from 'sanity/desk' 4 | import {schemaTypes} from './schemas' 5 | 6 | export const projectId = import.meta.env.PUBLIC_SANITY_PROJECT_ID! || '3do82whm' 7 | export const dataset = import.meta.env.PUBLIC_SANITY_DATASET! || 'next' 8 | 9 | export default defineConfig({ 10 | name: 'project-name', 11 | title: 'Project Name', 12 | projectId, 13 | dataset, 14 | plugins: [deskTool(), visionTool()], 15 | schema: { 16 | types: schemaTypes, 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /apps/example-ssr/schemas/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-astro/609bf7a45873996729d0e6a1294e15bab07d9280/apps/example-ssr/schemas/.gitkeep -------------------------------------------------------------------------------- /apps/example-ssr/schemas/index.ts: -------------------------------------------------------------------------------- 1 | // import schemas here from folder, and add to schemaTypes array 2 | 3 | export const schemaTypes = [] 4 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/CallToActionBox.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Debug from './Debug.astro' 3 | import PortableText from './PortableText.astro' 4 | const {node} = Astro.props 5 | --- 6 | 7 |
8 | 9 | {node.linkText} 10 |
11 | 12 | 23 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/Code.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {Prism} from '@astrojs/prism' 3 | 4 | const {node} = Astro.props 5 | --- 6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/Debug.astro: -------------------------------------------------------------------------------- 1 |
{JSON.stringify(Astro.props, null,2)}
2 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/InternalLink.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sanityClient} from 'sanity:client' 3 | const {node} = Astro.props 4 | const {markDef} = node 5 | 6 | // Only deal with posts links for this example 7 | const destination = 8 | markDef._ref && 9 | (await sanityClient.fetch(`* [_type == "post" && _id == $id] {slug {current}}[0]`, { 10 | id: markDef._ref, 11 | })) 12 | 13 | const linkText = node.children.map((c: any) => c.text).join(' ') 14 | --- 15 | 16 | {destination && {linkText}} 17 | {!destination && {linkText}} 18 | 19 | 24 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/NewsBar.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * A dynamic Newsbar that fetches content live from Sanity. 3 | * 4 | */ 5 | import {useState, useEffect, useCallback} from 'react' 6 | import {sanityClient} from 'sanity:client' 7 | 8 | export function NewsBar() { 9 | const [news, setNews] = useState({message: 'Loading news…'}) 10 | const getNews = useCallback(async () => { 11 | const response = await sanityClient.fetch(`*[_type == "sanityIoSettings"][0].banner`) 12 | setNews(response || {message: 'no news'}) 13 | }, [sanityClient]) 14 | 15 | useEffect(() => { 16 | getNews() 17 | }, [getNews]) 18 | 19 | return ( 20 | 21 | 22 | {news.message} 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/PortableText.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import CallToActionBox from './CallToActionBox.astro' 3 | import Code from './Code.astro' 4 | import Debug from './Debug.astro' 5 | import YouTube from './YouTube.astro' 6 | import {PortableText as PortableTextInternal} from 'astro-portabletext' 7 | import SanityImage from './SanityImage.astro' 8 | import InternalLink from './InternalLink.astro' 9 | 10 | const components = { 11 | type: { 12 | youtube: YouTube, 13 | callToActionBox: CallToActionBox, 14 | image: SanityImage, 15 | code: Code, 16 | }, 17 | mark: { 18 | internalLink: InternalLink, 19 | }, 20 | } 21 | --- 22 | 23 | 24 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/SanityImage.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import imageUrlBuilder from '@sanity/image-url' 3 | import type {ImageUrlBuilder} from '@sanity/image-url/lib/types/builder' 4 | import {sanityClient} from 'sanity:client' 5 | 6 | const builder = imageUrlBuilder(sanityClient) 7 | 8 | const {node} = Astro.props 9 | const {width = 960} = Astro.props 10 | let image: ImageUrlBuilder | undefined 11 | 12 | // See https://www.sanity.io/docs/presenting-images for general documentation on 13 | // presenting images, and https://www.sanity.io/docs/image-url for specifics on 14 | // this builder API 15 | try { 16 | image = node && node.asset && builder.image(node).width(width).fit('max').auto('format') 17 | } catch (error) { 18 | console.error(error) 19 | } 20 | --- 21 | 22 | {image && {node.alt} 23 | -------------------------------------------------------------------------------- /apps/example-ssr/src/components/YouTube.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {YouTube as YouTubeEmbed} from '@astro-community/astro-embed-youtube' 3 | const {url} = Astro.props.node 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /apps/example-ssr/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /apps/example-ssr/src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {NewsBar} from '../components/NewsBar' 3 | 4 | interface Props { 5 | title: string 6 | } 7 | 8 | const {title} = Astro.props 9 | --- 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {title} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 54 | -------------------------------------------------------------------------------- /apps/example-ssr/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sanityClient} from 'sanity:client' 3 | import Layout from '../layouts/Layout.astro' 4 | 5 | const posts = await sanityClient.fetch( 6 | `*[_type == "post" && defined(publishedAt)] | order(publishedAt desc)`, 7 | ) 8 | --- 9 | 10 | 11 |

Sanity.io blog

12 | 23 |
24 | -------------------------------------------------------------------------------- /apps/example-ssr/src/pages/posts/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sanityClient} from 'sanity:client' 3 | import Layout from '../../layouts/Layout.astro' 4 | import PortableText from '../../components/PortableText.astro' 5 | import SanityImage from '../../components/SanityImage.astro' 6 | 7 | const post = await sanityClient.fetch( 8 | `*[_type == "post" && defined(publishedAt) && slug.current == $slug] | order(publishedAt desc) { 9 | ..., 10 | authors[]-> { 11 | name 12 | } 13 | }[0]`, 14 | { 15 | slug: Astro.params.slug, 16 | }, 17 | ) 18 | 19 | const byline = (post.authors || []).map((a: any) => a.name).join(', ') 20 | --- 21 | 22 | 23 |
24 |

{post.title}

25 |

Written by {byline}

26 | 27 | 28 | 29 |
30 |
31 | -------------------------------------------------------------------------------- /apps/example-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict" 3 | } 4 | -------------------------------------------------------------------------------- /apps/example/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | 23 | .vercel 24 | .env*.local 25 | -------------------------------------------------------------------------------- /apps/example/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /apps/example/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/example/README.md: -------------------------------------------------------------------------------- 1 | # Sanity + Astro example app 2 | 3 | This example application renders the Sanity.io blog using Astro. It shows how to configure the Sanity + Astro integration in `astro.config.mjs`, querying and displaying Sanity content in `src/pages/index.astro` and `src/pages/posts/[slug].astro`, how to render PortableText in `src/components/PortableText.astro`, and how to present Sanity images in `src/components/SanityImage.astro`. 4 | -------------------------------------------------------------------------------- /apps/example/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import sanity from '@sanity/astro' 2 | import {defineConfig} from 'astro/config' 3 | import react from '@astrojs/react' 4 | 5 | // https://astro.build/config 6 | export default defineConfig({ 7 | integrations: [ 8 | sanity({ 9 | projectId: '3do82whm', 10 | dataset: 'next', 11 | // If you are doing static builds you may want opt out of the CDN 12 | useCdn: false, 13 | studioBasePath: '/admin', 14 | studioRouterHistory: 'hash', 15 | stega: { 16 | studioUrl: '/admin#', 17 | }, 18 | }), 19 | react(), 20 | ], 21 | vite: { 22 | ssr: { 23 | // See: https://github.com/withastro/astro/issues/9192#issuecomment-1834192321 24 | external: ['prismjs'], 25 | }, 26 | }, 27 | }) 28 | -------------------------------------------------------------------------------- /apps/example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "astro": "astro", 7 | "build": "astro build", 8 | "clean": "rimraf .astro rimraf dist && rimraf .turbo && rimraf node_modules", 9 | "dev": "astro dev --port 4322", 10 | "preview": "astro preview", 11 | "start": "astro dev --port 4322" 12 | }, 13 | "dependencies": { 14 | "@astro-community/astro-embed-youtube": "^0.5.6", 15 | "@astrojs/prism": "^3.3.0", 16 | "@astrojs/react": "^4.3.0", 17 | "@sanity/astro": "workspace:^", 18 | "@sanity/client": "^7.3.0", 19 | "@sanity/image-url": "^1.1.0", 20 | "@sanity/vision": "^3.90.0", 21 | "astro": "5.4.1", 22 | "astro-portabletext": "^0.11.1", 23 | "prismjs": "^1.30.0", 24 | "react": "^19.1.0", 25 | "react-dom": "^19.1.0", 26 | "sanity": "^3.90.0", 27 | "styled-components": "^6.1.18" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/example/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example/sanity.config.ts: -------------------------------------------------------------------------------- 1 | import {visionTool} from '@sanity/vision' 2 | import {defineConfig} from 'sanity' 3 | import {deskTool} from 'sanity/desk' 4 | import {sanityClient} from 'sanity:client' 5 | import {schemaTypes} from './schemas' 6 | 7 | const {projectId, dataset} = sanityClient.config() 8 | 9 | export default defineConfig({ 10 | name: 'project-name', 11 | title: 'Project Name', 12 | projectId, 13 | dataset, 14 | plugins: [deskTool(), visionTool()], 15 | schema: { 16 | types: schemaTypes, 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /apps/example/schemas/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity-io/sanity-astro/609bf7a45873996729d0e6a1294e15bab07d9280/apps/example/schemas/.gitkeep -------------------------------------------------------------------------------- /apps/example/schemas/index.ts: -------------------------------------------------------------------------------- 1 | // import schemas here from folder, and add to schemaTypes array 2 | 3 | export const schemaTypes = [] 4 | -------------------------------------------------------------------------------- /apps/example/src/components/CallToActionBox.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Debug from './Debug.astro' 3 | import PortableText from './PortableText.astro' 4 | const {node} = Astro.props 5 | --- 6 | 7 |
8 | 9 | {node.linkText} 10 |
11 | 12 | 23 | -------------------------------------------------------------------------------- /apps/example/src/components/Code.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {Prism} from '@astrojs/prism' 3 | 4 | const {node} = Astro.props 5 | --- 6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/example/src/components/Debug.astro: -------------------------------------------------------------------------------- 1 |
{JSON.stringify(Astro.props, null,2)}
2 | -------------------------------------------------------------------------------- /apps/example/src/components/InternalLink.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sanityClient} from 'sanity:client' 3 | const {node} = Astro.props 4 | const {markDef} = node 5 | 6 | // Only deal with posts links for this example 7 | const destination = 8 | markDef._ref && 9 | (await sanityClient.fetch(`* [_type == "post" && _id == $id] {slug {current}}[0]`, { 10 | id: markDef._ref, 11 | })) 12 | 13 | const linkText = node.children.map((c: any) => c.text).join(' ') 14 | --- 15 | 16 | {destination && {linkText}} 17 | {!destination && {linkText}} 18 | 19 | 24 | -------------------------------------------------------------------------------- /apps/example/src/components/NewsBar.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * A dynamic Newsbar that fetches content live from Sanity. 3 | * 4 | */ 5 | import {useState, useEffect, useCallback} from 'react' 6 | import {sanityClient} from 'sanity:client' 7 | 8 | export function NewsBar() { 9 | const [news, setNews] = useState({message: 'Loading news…'}) 10 | const getNews = useCallback(async () => { 11 | const response = await sanityClient.fetch(`*[_type == "sanityIoSettings"][0].banner`) 12 | setNews(response || {message: 'no news'}) 13 | }, [sanityClient]) 14 | 15 | useEffect(() => { 16 | getNews() 17 | }, [getNews]) 18 | 19 | return ( 20 | 21 | 22 | {news.message} 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /apps/example/src/components/PortableText.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import CallToActionBox from './CallToActionBox.astro' 3 | import Code from './Code.astro' 4 | import Debug from './Debug.astro' 5 | import YouTube from './YouTube.astro' 6 | import {PortableText as PortableTextInternal} from 'astro-portabletext' 7 | import SanityImage from './SanityImage.astro' 8 | import InternalLink from './InternalLink.astro' 9 | 10 | const components = { 11 | type: { 12 | youtube: YouTube, 13 | callToActionBox: CallToActionBox, 14 | image: SanityImage, 15 | code: Code, 16 | }, 17 | mark: { 18 | internalLink: InternalLink, 19 | }, 20 | } 21 | --- 22 | 23 | 24 | -------------------------------------------------------------------------------- /apps/example/src/components/SanityImage.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import imageUrlBuilder from '@sanity/image-url' 3 | import type {ImageUrlBuilder} from '@sanity/image-url/lib/types/builder' 4 | import {sanityClient} from 'sanity:client' 5 | 6 | const builder = imageUrlBuilder(sanityClient) 7 | 8 | const {node} = Astro.props 9 | const {width = 960} = Astro.props 10 | let image: ImageUrlBuilder | undefined 11 | 12 | // See https://www.sanity.io/docs/presenting-images for general documentation on 13 | // presenting images, and https://www.sanity.io/docs/image-url for specifics on 14 | // this builder API 15 | try { 16 | image = node && node.asset && builder.image(node).width(width).fit('max').auto('format') 17 | } catch (error) { 18 | console.error(error) 19 | } 20 | --- 21 | 22 | {image && {node.alt} 23 | -------------------------------------------------------------------------------- /apps/example/src/components/YouTube.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {YouTube as YouTubeEmbed} from '@astro-community/astro-embed-youtube' 3 | const {url} = Astro.props.node 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /apps/example/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /apps/example/src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {NewsBar} from '../components/NewsBar' 3 | 4 | interface Props { 5 | title: string 6 | } 7 | 8 | const {title} = Astro.props 9 | --- 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {title} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 54 | -------------------------------------------------------------------------------- /apps/example/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sanityClient} from 'sanity:client' 3 | import Layout from '../layouts/Layout.astro' 4 | 5 | const posts = await sanityClient.fetch( 6 | `*[_type == "post" && defined(publishedAt)] | order(publishedAt desc)`, 7 | ) 8 | --- 9 | 10 | 11 |

Sanity.io blog

12 | 23 |
24 | -------------------------------------------------------------------------------- /apps/example/src/pages/posts/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {sanityClient} from 'sanity:client' 3 | import Layout from '../../layouts/Layout.astro' 4 | import PortableText from '../../components/PortableText.astro' 5 | import SanityImage from '../../components/SanityImage.astro' 6 | 7 | export async function getStaticPaths() { 8 | const posts = await sanityClient.fetch( 9 | `*[_type == "post" && defined(publishedAt)] | order(publishedAt desc) { 10 | ..., 11 | authors[]-> { 12 | name 13 | } 14 | }`, 15 | ) 16 | return posts.map((post: any) => ({ 17 | params: {slug: post.slug.current}, 18 | props: {post}, 19 | })) 20 | } 21 | 22 | const {post} = Astro.props 23 | const byline = (post.authors || []).map((a: any) => a.name).join(', ') 24 | --- 25 | 26 | 27 |
28 |

{post.title}

29 |

Written by {byline}

30 | 31 | 32 | 33 |
34 |
35 | -------------------------------------------------------------------------------- /apps/example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict" 3 | } 4 | -------------------------------------------------------------------------------- /apps/movies/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | 23 | # jetbrains setting folder 24 | .idea/ 25 | .vercel 26 | .env*.local 27 | -------------------------------------------------------------------------------- /apps/movies/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /apps/movies/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/movies/README.md: -------------------------------------------------------------------------------- 1 | # Movies Example App 2 | -------------------------------------------------------------------------------- /apps/movies/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'astro/config' 2 | 3 | import react from '@astrojs/react' 4 | import vercel from '@astrojs/vercel' 5 | import sanity from '@sanity/astro' 6 | 7 | // https://astro.build/config 8 | export default defineConfig({ 9 | integrations: [ 10 | sanity({ 11 | projectId: '4j2qnyob', 12 | dataset: 'production', 13 | useCdn: true, 14 | studioBasePath: '/admin', 15 | stega: { 16 | studioUrl: '/admin', 17 | }, 18 | }), 19 | react(), 20 | ], 21 | output: 'server', 22 | adapter: vercel(), 23 | }) 24 | -------------------------------------------------------------------------------- /apps/movies/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movies", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "astro": "astro", 8 | "build": "astro check && astro build", 9 | "dev": "PUBLIC_SANITY_VISUAL_EDITING_ENABLED=true astro dev --port 4321", 10 | "preview": "astro preview", 11 | "start": "astro dev --port 4321" 12 | }, 13 | "dependencies": { 14 | "@astrojs/check": "^0.9.4", 15 | "@astrojs/react": "^4.3.0", 16 | "@astrojs/vercel": "^8.1.4", 17 | "@sanity/astro": "workspace:^", 18 | "@sanity/client": "^7.3.0", 19 | "@types/react": "^19.1.6", 20 | "@types/react-dom": "^19.1.5", 21 | "astro": "5.4.1", 22 | "react": "^19.1.0", 23 | "react-dom": "^19.1.0", 24 | "react-icons": "^5.5.0", 25 | "sanity": "^3.90.0", 26 | "typescript": "^5.8.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /apps/movies/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /apps/movies/sanity.cli.ts: -------------------------------------------------------------------------------- 1 | import {defineCliConfig} from 'sanity/cli' 2 | 3 | export default defineCliConfig({ 4 | api: { 5 | projectId: '4j2qnyob', 6 | dataset: 'production', 7 | }, 8 | }) 9 | -------------------------------------------------------------------------------- /apps/movies/sanity.config.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'sanity' 2 | import {structureTool} from 'sanity/structure' 3 | import {schemaTypes} from './schemaTypes' 4 | import {presentationTool} from 'sanity/presentation' 5 | 6 | export default defineConfig({ 7 | name: 'default', 8 | title: 'sanity-astro-movies', 9 | 10 | projectId: '4j2qnyob', 11 | dataset: 'production', 12 | 13 | plugins: [ 14 | presentationTool({ 15 | previewUrl: process.env.VERCEL_BRANCH_URL 16 | ? `https://${process.env.VERCEL_BRANCH_URL}` 17 | : process.env.VERCEL_PROJECT_PRODUCTION_URL 18 | ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` 19 | : 'http://localhost:4321', 20 | }), 21 | structureTool(), 22 | ], 23 | 24 | schema: { 25 | types: schemaTypes, 26 | }, 27 | }) 28 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/blockContent.ts: -------------------------------------------------------------------------------- 1 | import {defineArrayMember, defineType} 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 | export default defineType({ 14 | title: 'Block Content', 15 | name: 'blockContent', 16 | type: 'array', 17 | of: [ 18 | defineArrayMember({ 19 | title: 'Block', 20 | type: 'block', 21 | // Styles let you set what your user can mark up blocks with. These 22 | // correspond with HTML tags, but you can set any title or value 23 | // you want and decide how you want to deal with it where you want to 24 | // use your content. 25 | styles: [ 26 | {title: 'Normal', value: 'normal'}, 27 | {title: 'H1', value: 'h1'}, 28 | {title: 'H2', value: 'h2'}, 29 | {title: 'H3', value: 'h3'}, 30 | {title: 'H4', value: 'h4'}, 31 | {title: 'Quote', value: 'blockquote'}, 32 | ], 33 | lists: [{title: 'Bullet', value: 'bullet'}], 34 | // Marks let you mark up inline text in the block editor. 35 | marks: { 36 | // Decorators usually describe a single property – e.g. a typographic 37 | // preference or highlighting by editors. 38 | decorators: [ 39 | {title: 'Strong', value: 'strong'}, 40 | {title: 'Emphasis', value: 'em'}, 41 | ], 42 | // Annotations can be any object structure – e.g. a link or a footnote. 43 | annotations: [ 44 | { 45 | title: 'URL', 46 | name: 'link', 47 | type: 'object', 48 | fields: [ 49 | { 50 | title: 'URL', 51 | name: 'href', 52 | type: 'url', 53 | }, 54 | ], 55 | }, 56 | ], 57 | }, 58 | }), 59 | // You can add additional types here. Note that you can't use 60 | // primitive types such as 'string' and 'number' in the same array 61 | // as a block type. 62 | defineArrayMember({ 63 | type: 'image', 64 | options: {hotspot: true}, 65 | }), 66 | ], 67 | }) 68 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/castMember.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | 3 | export default defineType({ 4 | name: 'castMember', 5 | title: 'Cast Member', 6 | type: 'object', 7 | fields: [ 8 | defineField({ 9 | name: 'characterName', 10 | title: 'Character Name', 11 | type: 'string', 12 | }), 13 | defineField({ 14 | name: 'person', 15 | title: 'Actor', 16 | type: 'reference', 17 | to: [{type: 'person'}], 18 | }), 19 | defineField({ 20 | name: 'externalId', 21 | title: 'External ID', 22 | type: 'number', 23 | }), 24 | defineField({ 25 | name: 'externalCreditId', 26 | title: 'External Credit ID', 27 | type: 'string', 28 | }), 29 | ], 30 | preview: { 31 | select: { 32 | subtitle: 'characterName', 33 | title: 'person.name', 34 | media: 'person.image', 35 | }, 36 | }, 37 | }) 38 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/crewMember.ts: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import {defineField, defineType} from 'sanity' 3 | 4 | export default defineType({ 5 | name: 'crewMember', 6 | title: 'Crew Member', 7 | type: 'object', 8 | fields: [ 9 | defineField({ 10 | name: 'department', 11 | title: 'Department', 12 | type: 'string', 13 | }), 14 | defineField({ 15 | name: 'job', 16 | title: 'Job', 17 | type: 'string', 18 | }), 19 | defineField({ 20 | name: 'person', 21 | title: 'Person', 22 | type: 'reference', 23 | to: [{type: 'person'}], 24 | }), 25 | defineField({ 26 | name: 'externalId', 27 | title: 'External ID', 28 | type: 'number', 29 | }), 30 | defineField({ 31 | name: 'externalCreditId', 32 | title: 'External Credit ID', 33 | type: 'string', 34 | }), 35 | ], 36 | preview: { 37 | select: { 38 | name: 'person.name', 39 | job: 'job', 40 | department: 'department', 41 | media: 'person.image', 42 | }, 43 | prepare(selection) { 44 | const {name, job, department, media} = selection 45 | return { 46 | title: name, 47 | subtitle: `${job} [${department}]`, 48 | media, 49 | } 50 | }, 51 | }, 52 | }) 53 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/index.ts: -------------------------------------------------------------------------------- 1 | import blockContent from './blockContent' 2 | import crewMember from './crewMember' 3 | import castMember from './castMember' 4 | import movie from './movie' 5 | import person from './person' 6 | import screening from './screening' 7 | import plotSummary from './plotSummary' 8 | import plotSummaries from './plotSummaries' 9 | 10 | export const schemaTypes = [ 11 | // Document types 12 | movie, 13 | person, 14 | screening, 15 | 16 | // Other types 17 | blockContent, 18 | plotSummary, 19 | plotSummaries, 20 | castMember, 21 | crewMember, 22 | ] 23 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/movie.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {MdLocalMovies as icon} from 'react-icons/md' 3 | 4 | export default defineType({ 5 | name: 'movie', 6 | title: 'Movie', 7 | type: 'document', 8 | icon, 9 | fields: [ 10 | defineField({ 11 | name: 'title', 12 | title: 'Title', 13 | type: 'string', 14 | }), 15 | defineField({ 16 | name: 'slug', 17 | title: 'Slug', 18 | type: 'slug', 19 | options: { 20 | source: 'title', 21 | maxLength: 100, 22 | }, 23 | }), 24 | defineField({ 25 | name: 'overview', 26 | title: 'Overview', 27 | type: 'blockContent', 28 | }), 29 | defineField({ 30 | name: 'releaseDate', 31 | title: 'Release date', 32 | type: 'datetime', 33 | }), 34 | defineField({ 35 | name: 'poster', 36 | title: 'Poster Image', 37 | type: 'image', 38 | options: { 39 | hotspot: true, 40 | }, 41 | }), 42 | defineField({ 43 | name: 'externalId', 44 | title: 'External ID', 45 | type: 'number', 46 | }), 47 | defineField({ 48 | name: 'popularity', 49 | title: 'Popularity', 50 | type: 'number', 51 | }), 52 | defineField({ 53 | name: 'castMembers', 54 | title: 'Cast Members', 55 | type: 'array', 56 | of: [{type: 'castMember'}], 57 | }), 58 | defineField({ 59 | name: 'crewMembers', 60 | title: 'Crew Members', 61 | type: 'array', 62 | of: [{type: 'crewMember'}], 63 | }), 64 | ], 65 | preview: { 66 | select: { 67 | title: 'title', 68 | date: 'releaseDate', 69 | media: 'poster', 70 | castName0: 'castMembers.0.person.name', 71 | castName1: 'castMembers.1.person.name', 72 | }, 73 | prepare(selection) { 74 | const year = selection.date && selection.date.split('-')[0] 75 | const cast = [selection.castName0, selection.castName1].filter(Boolean).join(', ') 76 | 77 | return { 78 | title: `${selection.title} ${year ? `(${year})` : ''}`, 79 | date: selection.date, 80 | subtitle: cast, 81 | media: selection.media, 82 | } 83 | }, 84 | }, 85 | }) 86 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/person.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {MdPerson as icon} from 'react-icons/md' 3 | 4 | export default defineType({ 5 | name: 'person', 6 | title: 'Person', 7 | type: 'document', 8 | icon, 9 | fields: [ 10 | defineField({ 11 | name: 'name', 12 | title: 'Name', 13 | type: 'string', 14 | description: 'Please use "Firstname Lastname" format', 15 | }), 16 | defineField({ 17 | name: 'slug', 18 | title: 'Slug', 19 | type: 'slug', 20 | options: { 21 | source: 'name', 22 | maxLength: 100, 23 | }, 24 | }), 25 | defineField({ 26 | name: 'image', 27 | title: 'Image', 28 | type: 'image', 29 | options: { 30 | hotspot: true, 31 | }, 32 | }), 33 | ], 34 | preview: { 35 | select: {title: 'name', media: 'image'}, 36 | }, 37 | }) 38 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/plotSummaries.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | 3 | export default defineType({ 4 | title: 'Plot summaries', 5 | name: 'plotSummaries', 6 | type: 'object', 7 | fields: [ 8 | defineField({ 9 | name: 'caption', 10 | title: 'Caption', 11 | type: 'string', 12 | }), 13 | defineField({ 14 | name: 'summaries', 15 | title: 'Summaries', 16 | type: 'array', 17 | of: [{type: 'plotSummary'}], 18 | }), 19 | ], 20 | }) 21 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/plotSummary.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | 3 | export default defineType({ 4 | name: 'plotSummary', 5 | title: 'Plot Summary', 6 | type: 'object', 7 | fields: [ 8 | defineField({ 9 | title: 'Summary', 10 | name: 'summary', 11 | type: 'text', 12 | }), 13 | defineField({ 14 | title: 'Author', 15 | name: 'author', 16 | type: 'string', 17 | }), 18 | defineField({ 19 | title: 'Link to author', 20 | name: 'url', 21 | type: 'url', 22 | }), 23 | ], 24 | }) 25 | -------------------------------------------------------------------------------- /apps/movies/schemaTypes/screening.ts: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | import {MdLocalPlay as icon} from 'react-icons/md' 3 | 4 | export default defineType({ 5 | name: 'screening', 6 | title: 'Screening', 7 | type: 'document', 8 | icon, 9 | fields: [ 10 | defineField({ 11 | name: 'title', 12 | title: 'Title', 13 | type: 'string', 14 | description: 'E.g.: Our first ever screening of Gattaca', 15 | }), 16 | defineField({ 17 | name: 'movie', 18 | title: 'Movie', 19 | type: 'reference', 20 | to: [{type: 'movie'}], 21 | description: 'Which movie are we screening', 22 | }), 23 | defineField({ 24 | name: 'published', 25 | title: 'Published', 26 | type: 'boolean', 27 | description: 'Set to published when this screening should be visible on a front-end', 28 | }), 29 | defineField({ 30 | name: 'location', 31 | title: 'Location', 32 | type: 'geopoint', 33 | description: 'Where will the screening take place?', 34 | hidden: true, 35 | }), 36 | defineField({ 37 | name: 'beginAt', 38 | title: 'Starts at', 39 | type: 'datetime', 40 | description: 'When does the screening start?', 41 | }), 42 | defineField({ 43 | name: 'endAt', 44 | title: 'Ends at', 45 | type: 'datetime', 46 | description: 'When does the screening end?', 47 | }), 48 | defineField({ 49 | name: 'allowedGuests', 50 | title: 'Who can come?', 51 | type: 'string', 52 | options: { 53 | list: [ 54 | {title: 'Members', value: 'members'}, 55 | {title: 'Members and friends', value: 'friends'}, 56 | {title: 'Anyone', value: 'anyone'}, 57 | ], 58 | layout: 'radio', 59 | }, 60 | }), 61 | defineField({ 62 | name: 'infoUrl', 63 | title: 'More info at', 64 | type: 'url', 65 | description: 66 | 'URL to imdb.com, rottentomatoes.com or some other place with reviews, stats, etc', 67 | }), 68 | defineField({ 69 | name: 'ticket', 70 | title: 'Ticket', 71 | type: 'file', 72 | description: 'PDF for printing a physical ticket', 73 | }), 74 | ], 75 | preview: { 76 | select: { 77 | title: 'title', 78 | media: 'movie.poster', 79 | }, 80 | }, 81 | }) 82 | -------------------------------------------------------------------------------- /apps/movies/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | interface ImportMetaEnv { 5 | readonly PUBLIC_SANITY_VISUAL_EDITING_ENABLED: string 6 | readonly SANITY_API_READ_TOKEN: string 7 | } 8 | 9 | interface ImportMeta { 10 | readonly env: ImportMetaEnv 11 | } 12 | -------------------------------------------------------------------------------- /apps/movies/src/layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {VisualEditing} from '@sanity/astro/visual-editing' 3 | const visualEditingEnabled = import.meta.env.PUBLIC_SANITY_VISUAL_EDITING_ENABLED == 'true' 4 | 5 | export type props = { 6 | title: string 7 | } 8 | const {title} = Astro.props 9 | --- 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {title} 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /apps/movies/src/load-query.ts: -------------------------------------------------------------------------------- 1 | import {type QueryParams} from 'sanity' 2 | import {sanityClient} from 'sanity:client' 3 | 4 | const visualEditingEnabled = import.meta.env.PUBLIC_SANITY_VISUAL_EDITING_ENABLED === 'true' 5 | const token = import.meta.env.SANITY_API_READ_TOKEN 6 | 7 | export async function loadQuery({ 8 | query, 9 | params, 10 | }: { 11 | query: string 12 | params?: QueryParams 13 | }) { 14 | if (visualEditingEnabled && !token) { 15 | throw new Error('The `SANITY_API_READ_TOKEN` environment variable is required in Draft Mode.') 16 | } 17 | 18 | const perspective = visualEditingEnabled ? 'drafts' : 'published' 19 | 20 | const {result, resultSourceMap} = await sanityClient.fetch(query, params ?? {}, { 21 | filterResponse: false, 22 | perspective, 23 | resultSourceMap: visualEditingEnabled ? 'withKeyArraySelector' : false, 24 | stega: visualEditingEnabled, 25 | ...(visualEditingEnabled ? {token} : {}), 26 | useCdn: !visualEditingEnabled, 27 | }) 28 | 29 | return { 30 | data: result, 31 | sourceMap: resultSourceMap, 32 | perspective, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /apps/movies/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../layout.astro' 3 | import {loadQuery} from '../load-query' 4 | 5 | const {data: movies} = await loadQuery>({ 6 | query: `*[_type == 'movie']`, 7 | }) 8 | --- 9 | 10 | 11 |

Movies

12 |
    13 | {movies.map((movie) =>
  1. {movie.title}
  2. )} 14 |
15 |
16 | -------------------------------------------------------------------------------- /apps/movies/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strictest" 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astro", 3 | "private": true, 4 | "scripts": { 5 | "build": "turbo run build", 6 | "build:example": "turbo run build --filter=example...", 7 | "build:example-ssr": "turbo run build --filter=example-ssr...", 8 | "build:movies": "turbo run build --filter=movies...", 9 | "clean": "turbo run clean && rimraf .turbo && rimraf node_modules", 10 | "dev": "turbo run dev", 11 | "dev:example": "turbo run dev --filter=example", 12 | "dev:example-ssr": "turbo run dev --filter=example-ssr", 13 | "dev:movies": "turbo run dev --filter=movies", 14 | "format": "prettier --write .", 15 | "lint": "turbo run lint" 16 | }, 17 | "devDependencies": { 18 | "@sanity/prettier-config": "^1.0.3", 19 | "@turbo/gen": "^1.13.4", 20 | "eslint": "^8.57.1", 21 | "eslint-config-custom": "*", 22 | "prettier": "^3.5.3", 23 | "prettier-plugin-astro": "^0.14.1", 24 | "rimraf": "^5.0.7", 25 | "turbo": "^1.13.4" 26 | }, 27 | "packageManager": "pnpm@9.15.9", 28 | "pnpm": { 29 | "overrides": { 30 | "braces@<3.0.3": ">=3.0.3", 31 | "ws@>=8.0.0 <8.17.1": ">=8.17.1" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/sanity-astro/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | package-lock.json -------------------------------------------------------------------------------- /packages/sanity-astro/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 📓 Changelog 4 | 5 | All notable changes to this project will be documented in this file. See 6 | [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 7 | 8 | ## [3.2.6](https://github.com/sanity-io/sanity-astro/compare/v3.2.5...v3.2.6) (2025-03-03) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * **deps:** update dependency @sanity/client to ^6.28.2 ([#318](https://github.com/sanity-io/sanity-astro/issues/318)) ([499fc40](https://github.com/sanity-io/sanity-astro/commit/499fc40deea4ed32ac04f9ff32b26b864c410576)) 14 | * **deps:** Update dependency @sanity/visual-editing to ^2.13.7 ([#317](https://github.com/sanity-io/sanity-astro/issues/317)) ([c3acec9](https://github.com/sanity-io/sanity-astro/commit/c3acec93b6dcd5607a834d399e2faf39095b433e)) 15 | * **deps:** update dependency sanity to ^3.77.2 ([#319](https://github.com/sanity-io/sanity-astro/issues/319)) ([a8ca00d](https://github.com/sanity-io/sanity-astro/commit/a8ca00dd19d438828b7e10f6231773908013d553)) 16 | 17 | ## [3.2.5](https://github.com/sanity-io/sanity-astro/compare/v3.2.4...v3.2.5) (2025-02-18) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * make styled-components a peer ([#310](https://github.com/sanity-io/sanity-astro/issues/310)) ([f5cbec0](https://github.com/sanity-io/sanity-astro/commit/f5cbec0d2966afd893087b8f681a29aeec31a8e9)) 23 | 24 | ## [3.2.4](https://github.com/sanity-io/sanity-astro/compare/v3.2.3...v3.2.4) (2025-02-18) 25 | 26 | 27 | ### Bug Fixes 28 | 29 | * optimize `shallowequal` instead of `styled-components` ([e8684ae](https://github.com/sanity-io/sanity-astro/commit/e8684ae3c6b4734f547b6d6451547c195e087d15)) 30 | 31 | ## [3.2.3](https://github.com/sanity-io/sanity-astro/compare/v3.2.2...v3.2.3) (2025-02-18) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * **deps:** update dependency @sanity/visual-editing to ^2.13.4 ([#304](https://github.com/sanity-io/sanity-astro/issues/304)) ([462ed73](https://github.com/sanity-io/sanity-astro/commit/462ed738c17df445fa637f63f536316b0479a1eb)) 37 | * **deps:** update dependency sanity to ^3.76.1 ([#306](https://github.com/sanity-io/sanity-astro/issues/306)) ([95e2705](https://github.com/sanity-io/sanity-astro/commit/95e2705489af3f4f76c2a590d82acb201cee5557)) 38 | * make visual editing a direct dependency ([#308](https://github.com/sanity-io/sanity-astro/issues/308)) ([0ccae9f](https://github.com/sanity-io/sanity-astro/commit/0ccae9f44677b2d763cdbf4e094de9354c52f8fd)) 39 | 40 | ## [3.2.2](https://github.com/sanity-io/sanity-astro/compare/v3.2.1...v3.2.2) (2025-02-18) 41 | 42 | 43 | ### Bug Fixes 44 | 45 | * configure vite to optimize deps ([#301](https://github.com/sanity-io/sanity-astro/issues/301)) ([4d03ebf](https://github.com/sanity-io/sanity-astro/commit/4d03ebf0f774a5b578dd44ee0a055303948271db)) 46 | * **deps:** update dependency @sanity/client to ^6.28.0 ([#293](https://github.com/sanity-io/sanity-astro/issues/293)) ([9cdb8a5](https://github.com/sanity-io/sanity-astro/commit/9cdb8a552c5c39e7c46bc6354c3489536113d38b)) 47 | * **deps:** update dependency @sanity/visual-editing to ^2.13.3 ([#297](https://github.com/sanity-io/sanity-astro/issues/297)) ([5bf3296](https://github.com/sanity-io/sanity-astro/commit/5bf329657bf832d13cc53ed69d9e980fddb5bf72)) 48 | * **deps:** update dependency sanity to ^3.75.1 ([#298](https://github.com/sanity-io/sanity-astro/issues/298)) ([22baeec](https://github.com/sanity-io/sanity-astro/commit/22baeec8911a35c3dc17b9243cb45470956a478e)) 49 | 50 | ## [3.2.1](https://github.com/sanity-io/sanity-astro/compare/v3.2.0...v3.2.1) (2025-02-12) 51 | 52 | 53 | ### Bug Fixes 54 | 55 | * **deps:** update dependency @sanity/visual-editing to ^2.13.1 ([#286](https://github.com/sanity-io/sanity-astro/issues/286)) ([df4639a](https://github.com/sanity-io/sanity-astro/commit/df4639a4df2e891c681f1a541b5bb551673e8f75)) 56 | * **deps:** update dependency @sanity/visual-editing to ^2.13.2 ([#292](https://github.com/sanity-io/sanity-astro/issues/292)) ([77bb3c4](https://github.com/sanity-io/sanity-astro/commit/77bb3c48218781beae9e90ec3da76f8b17585f7d)) 57 | * **deps:** update dependency sanity to ^3.75.0 ([#287](https://github.com/sanity-io/sanity-astro/issues/287)) ([305b696](https://github.com/sanity-io/sanity-astro/commit/305b696e4513d6a5f7cb5fc34f3c374424b2339f)) 58 | 59 | ## [3.2.0](https://github.com/sanity-io/sanity-astro/compare/v3.1.11...v3.2.0) (2025-01-31) 60 | 61 | 62 | ### Features 63 | 64 | * support embedding studios without ssr ([#275](https://github.com/sanity-io/sanity-astro/issues/275)) ([b1dd953](https://github.com/sanity-io/sanity-astro/commit/b1dd9536a6d778f6898e76a438985c414087222f)) 65 | 66 | ## [3.1.11](https://github.com/sanity-io/sanity-astro/compare/v3.1.10...v3.1.11) (2025-01-29) 67 | 68 | 69 | ### Bug Fixes 70 | 71 | * bump license year ([3b87490](https://github.com/sanity-io/sanity-astro/commit/3b87490bb250e5e1b0253e89d02c37b19d475e39)) 72 | * **deps:** update dependency @sanity/client to ^6.27.2 ([#271](https://github.com/sanity-io/sanity-astro/issues/271)) ([5560c81](https://github.com/sanity-io/sanity-astro/commit/5560c816046058f51c6def4cb298d532ca12d9d3)) 73 | * **deps:** update dependency @sanity/visual-editing to ^2.12.10 ([#270](https://github.com/sanity-io/sanity-astro/issues/270)) ([6cdd08c](https://github.com/sanity-io/sanity-astro/commit/6cdd08c2e923a404e995003b02be3eb61d7368df)) 74 | * **deps:** update dependency sanity to ^3.72.1 ([#272](https://github.com/sanity-io/sanity-astro/issues/272)) ([d2b6890](https://github.com/sanity-io/sanity-astro/commit/d2b6890323cf5817397a3cbb1b87f5f437a773f5)) 75 | * **deps:** update dependency type-fest to ^4.33.0 ([#246](https://github.com/sanity-io/sanity-astro/issues/246)) ([06985bb](https://github.com/sanity-io/sanity-astro/commit/06985bb10b174014efd63471e8bcafda323b8c8d)) 76 | 77 | ## [3.1.10](https://github.com/sanity-io/sanity-astro/compare/v3.1.9...v3.1.10) (2025-01-14) 78 | 79 | 80 | ### Bug Fixes 81 | 82 | * bump visual editing to 2.12.2 to fix refresh connectivity ([#238](https://github.com/sanity-io/sanity-astro/issues/238)) ([3233c60](https://github.com/sanity-io/sanity-astro/commit/3233c60a1264c079a7f1973c809afe20cf39fbe9)) 83 | 84 | ## [3.1.9](https://github.com/sanity-io/sanity-astro/compare/v3.1.8...v3.1.9) (2024-12-18) 85 | 86 | 87 | ### Bug Fixes 88 | 89 | * bump react peer ([#233](https://github.com/sanity-io/sanity-astro/issues/233)) ([debdfbe](https://github.com/sanity-io/sanity-astro/commit/debdfbe20f4f430abbb90028ccfca74d39aa500b)) 90 | 91 | ## [3.1.8](https://github.com/sanity-io/sanity-astro/compare/v3.1.7...v3.1.8) (2024-12-12) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * **deps:** upgrade `@sanity/visual-editing` to `2.10.7` ([7af0441](https://github.com/sanity-io/sanity-astro/commit/7af0441f47b78359af165525dddd76053f96f633)) 97 | 98 | ## [3.1.7](https://github.com/sanity-io/sanity-astro/compare/v3.1.6...v3.1.7) (2024-12-12) 99 | 100 | 101 | ### Bug Fixes 102 | 103 | * bump `sanity` and `@sanity/visual-editing` to `latest` ([#220](https://github.com/sanity-io/sanity-astro/issues/220)) ([a1274ea](https://github.com/sanity-io/sanity-astro/commit/a1274ea9e171d156d5b6bff7ab49a8fe299e30f1)) 104 | 105 | ## [3.1.6](https://github.com/sanity-io/sanity-astro/compare/v3.1.5...v3.1.6) (2024-08-29) 106 | 107 | 108 | ### Bug Fixes 109 | 110 | * error out if studioBasePath looks like an absolute URL ([#211](https://github.com/sanity-io/sanity-astro/issues/211)) ([9dc8b72](https://github.com/sanity-io/sanity-astro/commit/9dc8b72792646c8d1f0f4af1e15bb3c3a9fa5e5a)) 111 | 112 | ## [3.1.5](https://github.com/sanity-io/sanity-astro/compare/v3.1.4...v3.1.5) (2024-08-27) 113 | 114 | 115 | ### Bug Fixes 116 | 117 | * allow integration options to be undefined ([#213](https://github.com/sanity-io/sanity-astro/issues/213)) ([0e8924b](https://github.com/sanity-io/sanity-astro/commit/0e8924bcdf2097efebb0d20edadb5a7db9d59b9c)) 118 | 119 | ## [3.1.4](https://github.com/sanity-io/sanity-astro/compare/v3.1.3...v3.1.4) (2024-06-19) 120 | 121 | 122 | ### Bug Fixes 123 | 124 | * remove wild semicolon in StudioComponent JSX ([#205](https://github.com/sanity-io/sanity-astro/issues/205)) ([03aedc2](https://github.com/sanity-io/sanity-astro/commit/03aedc21f2b085f855b32c19d6d143209cbb1932)) 125 | 126 | ## [3.1.3](https://github.com/sanity-io/sanity-astro/compare/v3.1.2...v3.1.3) (2024-05-29) 127 | 128 | 129 | ### Bug Fixes 130 | 131 | * **visual-editing:** avoid using JSX in the .astro file ([#185](https://github.com/sanity-io/sanity-astro/issues/185)) ([dd92c85](https://github.com/sanity-io/sanity-astro/commit/dd92c8586cd37accdcb859c73cbd9838d5df39b1)) 132 | * **visual-editing:** use VisualEditing React component directly ([#183](https://github.com/sanity-io/sanity-astro/issues/183)) ([01619c0](https://github.com/sanity-io/sanity-astro/commit/01619c0ba6eed5ae90cbde3c0c10e2bb679a5fb9)) 133 | 134 | ## [3.1.2](https://github.com/sanity-io/sanity-astro/compare/v3.1.1...v3.1.2) (2024-05-28) 135 | 136 | 137 | ### Bug Fixes 138 | 139 | * **deps:** update @sanity/visual-editing ([#179](https://github.com/sanity-io/sanity-astro/issues/179)) ([5648919](https://github.com/sanity-io/sanity-astro/commit/564891989b2b5775ccada155439a5639c8b0ed77)) 140 | 141 | ## [3.1.1](https://github.com/sanity-io/sanity-astro/compare/v3.1.0...v3.1.1) (2024-05-27) 142 | 143 | 144 | ### Bug Fixes 145 | 146 | * **deps:** Update dependency @sanity/client to ^6.18.3 ([#139](https://github.com/sanity-io/sanity-astro/issues/139)) ([34bf859](https://github.com/sanity-io/sanity-astro/commit/34bf859431468123c9024e4bf54b62a280149a02)) 147 | * **deps:** update visual-editing ([#177](https://github.com/sanity-io/sanity-astro/issues/177)) ([b872ba7](https://github.com/sanity-io/sanity-astro/commit/b872ba735575712aadb5f9e48f57ecd6f608a9c7)) 148 | 149 | ## [3.1.0](https://github.com/sanity-io/sanity-astro/compare/v3.0.1...v3.1.0) (2024-05-23) 150 | 151 | 152 | ### Features 153 | 154 | * add VisualEditing component ([#167](https://github.com/sanity-io/sanity-astro/issues/167)) ([54dbbb4](https://github.com/sanity-io/sanity-astro/commit/54dbbb497f0a6bd3f01f95618a94a2cbc11cbaef)) 155 | 156 | 157 | ### Bug Fixes 158 | 159 | * allow non-JSON ClientConfig ([#166](https://github.com/sanity-io/sanity-astro/issues/166)) ([ed086ff](https://github.com/sanity-io/sanity-astro/commit/ed086ff19600c6a68059fe0a7590f4863d56b9e4)) 160 | * **deps:** update sanity and @sanity/client ([#173](https://github.com/sanity-io/sanity-astro/issues/173)) ([6fa2fed](https://github.com/sanity-io/sanity-astro/commit/6fa2fed8082db7c5620d9da5034917357b16ffc2)) 161 | * distribute VisualEditing component ([#172](https://github.com/sanity-io/sanity-astro/issues/172)) ([4973aa9](https://github.com/sanity-io/sanity-astro/commit/4973aa9cb6b7ccf4f2ee15495870710fb03ec883)) 162 | 163 | ## [3.0.1](https://github.com/sanity-io/sanity-astro/compare/v3.0.0...v3.0.1) (2024-05-16) 164 | 165 | 166 | ### Bug Fixes 167 | 168 | * studio route should not be prerendered as it's a dynamic spa route ([#153](https://github.com/sanity-io/sanity-astro/issues/153)) ([0926f9f](https://github.com/sanity-io/sanity-astro/commit/0926f9fc073dd860a9373651b1d4bd0dd270b1a6)) 169 | 170 | ## [3.0.0](https://github.com/sanity-io/sanity-astro/compare/v2.2.1...v3.0.0) (2024-03-13) 171 | 172 | 173 | ### ⚠ BREAKING CHANGES 174 | 175 | * **module:** This exposes the integration as a default export to enable `npx astro add @sanity/astro` as an installation method. 176 | * Remove requirement for hybrid/server rendering ([#147](https://github.com/sanity-io/sanity-astro/issues/147)) 177 | 178 | ### Features 179 | 180 | * Remove requirement for hybrid/server rendering ([#147](https://github.com/sanity-io/sanity-astro/issues/147)) ([5e9c011](https://github.com/sanity-io/sanity-astro/commit/5e9c011987176c893fa2451b184f6362b28a9e81)) 181 | 182 | 183 | ### Bug Fixes 184 | 185 | * **module:** export module as default to enable astro add ([#151](https://github.com/sanity-io/sanity-astro/issues/151)) ([ade3dba](https://github.com/sanity-io/sanity-astro/commit/ade3dba5264fa450186987318e565056630c5b0c)) 186 | 187 | ## [2.2.1](https://github.com/sanity-io/sanity-astro/compare/v2.2.0...v2.2.1) (2024-02-16) 188 | 189 | 190 | ### Bug Fixes 191 | 192 | * **deps:** Update dependency @sanity/client to ^6.10.0 ([#113](https://github.com/sanity-io/sanity-astro/issues/113)) ([d376e40](https://github.com/sanity-io/sanity-astro/commit/d376e40cbf9789fe504bc75787ca19e6fee44d19)) 193 | * **module:** add back missing module export ([#140](https://github.com/sanity-io/sanity-astro/issues/140)) ([fc27dd5](https://github.com/sanity-io/sanity-astro/commit/fc27dd5e99f3984ddb313ae835800f8771daf6c8)) 194 | 195 | ## [2.2.0](https://github.com/sanity-io/sanity-astro/compare/v2.1.4...v2.2.0) (2024-01-03) 196 | 197 | 198 | ### Features 199 | 200 | * support Astro v4 ([#128](https://github.com/sanity-io/sanity-astro/issues/128)) ([c2623ea](https://github.com/sanity-io/sanity-astro/commit/c2623eae3f4c265b3ea6a22e87bfc7d7aacf3360)) 201 | 202 | ## [2.1.4](https://github.com/sanity-io/sanity-astro/compare/v2.1.3...v2.1.4) (2023-10-31) 203 | 204 | 205 | ### Bug Fixes 206 | 207 | * **deps:** Update dependency @sanity/ui to ^1.8.3 ([#105](https://github.com/sanity-io/sanity-astro/issues/105)) ([0bb6fe1](https://github.com/sanity-io/sanity-astro/commit/0bb6fe1d1c043a665459ed5523b3ac89a0489115)) 208 | 209 | ## [2.1.3](https://github.com/sanity-io/sanity-astro/compare/v2.1.2...v2.1.3) (2023-10-23) 210 | 211 | 212 | ### Bug Fixes 213 | 214 | * **deps:** Update dependency @sanity/client to ^6.7.0 ([#99](https://github.com/sanity-io/sanity-astro/issues/99)) ([fa7cc1c](https://github.com/sanity-io/sanity-astro/commit/fa7cc1c58df4e7aebd70504c206fac2b95a9f299)) 215 | * **deps:** update dependency vite to ^4.5.0 ([#97](https://github.com/sanity-io/sanity-astro/issues/97)) ([2a855cd](https://github.com/sanity-io/sanity-astro/commit/2a855cd95a0572caf4f7554eb6f8c1216c96ce69)) 216 | 217 | ## [2.1.2](https://github.com/sanity-io/sanity-astro/compare/v2.1.1...v2.1.2) (2023-10-12) 218 | 219 | 220 | ### Bug Fixes 221 | 222 | * exports and config ([#83](https://github.com/sanity-io/sanity-astro/issues/83)) ([48ab268](https://github.com/sanity-io/sanity-astro/commit/48ab2684ca5c4c1c60923e6b6fbd5739528d3a7c)) 223 | 224 | ## [2.1.1](https://github.com/sanity-io/sanity-astro/compare/v2.1.0...v2.1.1) (2023-10-04) 225 | 226 | ### Bug Fixes 227 | 228 | - **ci:** replace semantic-release with release-please ([fe20b74](https://github.com/sanity-io/sanity-astro/commit/fe20b7410b7f5837fad041b78b09a35229e95f51)) 229 | 230 | ## [2.1.0](https://github.com/sanity-io/sanity-astro/compare/v2.0.0...v2.1.0) (2023-10-03) 231 | 232 | ### Features 233 | 234 | - ship typings for virtual modules ([#71](https://github.com/sanity-io/sanity-astro/issues/71)) ([93896fb](https://github.com/sanity-io/sanity-astro/commit/93896fb5dc4f31c9ea3d11bab673e84451926902)) 235 | 236 | ### Bug Fixes 237 | 238 | - add prerelease support ([75321d5](https://github.com/sanity-io/sanity-astro/commit/75321d52192369ffee935a4a637d42f45effac12)) 239 | - remove accidental dependency ([ebabcbe](https://github.com/sanity-io/sanity-astro/commit/ebabcbe423c427b5db1843dee61a41ac00fbc5e4)) 240 | 241 | ## [2.0.1-beta.26](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.25...v2.0.1-beta.26) (2023-10-03) 242 | 243 | ### Bug Fixes 244 | 245 | - finalize env.d.ts strategy ([a670a66](https://github.com/sanity-io/sanity-astro/commit/a670a661d3d69c6868aba4fd212f7440db001061)) 246 | 247 | ## [2.0.1-beta.25](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.24...v2.0.1-beta.25) (2023-10-03) 248 | 249 | ### Bug Fixes 250 | 251 | - try env.d.ts strategy ([42ce2c7](https://github.com/sanity-io/sanity-astro/commit/42ce2c75c4b17183a795815262be15f902cdf84d)) 252 | 253 | ## [2.0.1-beta.24](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.23...v2.0.1-beta.24) (2023-10-03) 254 | 255 | ### Bug Fixes 256 | 257 | - try env.d.ts strategy ([cf13dcb](https://github.com/sanity-io/sanity-astro/commit/cf13dcbad358f3f443752ef92b930474522ab8ea)) 258 | 259 | ## [2.0.1-beta.23](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.22...v2.0.1-beta.23) (2023-10-03) 260 | 261 | ### Bug Fixes 262 | 263 | - try env.d.ts strategy ([c952546](https://github.com/sanity-io/sanity-astro/commit/c952546648ce760fa53d6849686390a397616c62)) 264 | 265 | ## [2.0.1-beta.22](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.21...v2.0.1-beta.22) (2023-10-03) 266 | 267 | ### Bug Fixes 268 | 269 | - try env.d.ts strategy ([6cc44c8](https://github.com/sanity-io/sanity-astro/commit/6cc44c8de32f052128d6ffc4f9d581b71174bf63)) 270 | 271 | ## [2.0.1-beta.21](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.20...v2.0.1-beta.21) (2023-10-03) 272 | 273 | ### Bug Fixes 274 | 275 | - try env.d.ts strategy ([e334e38](https://github.com/sanity-io/sanity-astro/commit/e334e38c5ed21936e8d050822dff79dd4eb0c44c)) 276 | 277 | ## [2.0.1-beta.20](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.19...v2.0.1-beta.20) (2023-10-03) 278 | 279 | ### Bug Fixes 280 | 281 | - try env.d.ts strategy ([455f994](https://github.com/sanity-io/sanity-astro/commit/455f994aabb3decbc5cedcac73813f7806532a75)) 282 | 283 | ### Reverts 284 | 285 | - Revert "chore: add jsx to tsconfig" ([4f767c9](https://github.com/sanity-io/sanity-astro/commit/4f767c96d037e908095091440007be3403ca2cb9)) 286 | 287 | ## [2.0.1-beta.19](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.18...v2.0.1-beta.19) (2023-10-02) 288 | 289 | ### Bug Fixes 290 | 291 | - add [@types](https://github.com/types) ([abcc903](https://github.com/sanity-io/sanity-astro/commit/abcc903a5a96d18f8fd8fcc1dccfaf626e2aed7b)) 292 | 293 | ## [2.0.1-beta.18](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.17...v2.0.1-beta.18) (2023-10-02) 294 | 295 | ### Bug Fixes 296 | 297 | - try including dts in chain ([65c3edb](https://github.com/sanity-io/sanity-astro/commit/65c3edbd1bbc59c353d3170b22a35755d7d61ae3)) 298 | 299 | ## [2.0.1-beta.17](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.16...v2.0.1-beta.17) (2023-10-02) 300 | 301 | ### Bug Fixes 302 | 303 | - config fix ([3c8ea5f](https://github.com/sanity-io/sanity-astro/commit/3c8ea5ff6a6d5e30b647cc41ab5c1d662c44b544)) 304 | 305 | ## [2.0.1-beta.16](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.15...v2.0.1-beta.16) (2023-10-02) 306 | 307 | ### Bug Fixes 308 | 309 | - config fix ([5bbb466](https://github.com/sanity-io/sanity-astro/commit/5bbb466327a27237009cecbb1b9422529d2ec0ea)) 310 | 311 | ## [2.0.1-beta.15](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.14...v2.0.1-beta.15) (2023-10-02) 312 | 313 | ### Bug Fixes 314 | 315 | - config fix ([8785585](https://github.com/sanity-io/sanity-astro/commit/87855852162ebeaf3f31d447fcfdb9b36a706a97)) 316 | 317 | ## [2.0.1-beta.14](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.13...v2.0.1-beta.14) (2023-10-02) 318 | 319 | ### Bug Fixes 320 | 321 | - config fix ([a742296](https://github.com/sanity-io/sanity-astro/commit/a7422965b56919e78ee5fe0e9748800b2f33b840)) 322 | 323 | ## [2.0.1-beta.13](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.12...v2.0.1-beta.13) (2023-10-02) 324 | 325 | ### Bug Fixes 326 | 327 | - config fix ([30916f9](https://github.com/sanity-io/sanity-astro/commit/30916f90abd464aee5bf0094c0072870cb38d955)) 328 | 329 | ## [2.0.1-beta.12](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.11...v2.0.1-beta.12) (2023-10-02) 330 | 331 | ### Bug Fixes 332 | 333 | - config fix ([43db1cd](https://github.com/sanity-io/sanity-astro/commit/43db1cd09cb6fd2d83c732f802d1f7fa64e849e2)) 334 | 335 | ## [2.0.1-beta.11](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.10...v2.0.1-beta.11) (2023-10-02) 336 | 337 | ### Bug Fixes 338 | 339 | - remove dts from files ([a5565cd](https://github.com/sanity-io/sanity-astro/commit/a5565cdf3e52b36ec024a7755dd52161638c1fb4)) 340 | 341 | ## [2.0.1-beta.10](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.9...v2.0.1-beta.10) (2023-10-02) 342 | 343 | ### Bug Fixes 344 | 345 | - add client as peerdep ([6c214cc](https://github.com/sanity-io/sanity-astro/commit/6c214cc1e75698841f0941a65ea4bf684f441d96)) 346 | 347 | ## [2.0.1-beta.9](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.8...v2.0.1-beta.9) (2023-10-02) 348 | 349 | ### Bug Fixes 350 | 351 | - rename plugin ([28d25fe](https://github.com/sanity-io/sanity-astro/commit/28d25febe045fee5a7637799dffb3328109646a4)) 352 | - trying different config ([7cb8a3c](https://github.com/sanity-io/sanity-astro/commit/7cb8a3c3231aaaabe5ff38400599908ee2bd1110)) 353 | 354 | ## [2.0.1-beta.8](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.7...v2.0.1-beta.8) (2023-10-02) 355 | 356 | ### Bug Fixes 357 | 358 | - use mjs for esm ([8af14d0](https://github.com/sanity-io/sanity-astro/commit/8af14d0a294a409dd0fab0b8820188c1c5e4780d)) 359 | - use named export ([e3d04ef](https://github.com/sanity-io/sanity-astro/commit/e3d04effcc6711af42a3dfc5a79ea21d8bda716a)) 360 | 361 | ## [2.0.1-beta.7](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.6...v2.0.1-beta.7) (2023-10-02) 362 | 363 | ### Bug Fixes 364 | 365 | - clean up type files ([fd896af](https://github.com/sanity-io/sanity-astro/commit/fd896afa93e83321b17c1459e23dedf451d92d15)) 366 | - simplify example ([a9433a2](https://github.com/sanity-io/sanity-astro/commit/a9433a28a8d4f62123186acd57a985a52e865450)) 367 | - use named export ([624e0b0](https://github.com/sanity-io/sanity-astro/commit/624e0b05095bcdde84f08be3df533d9dff85d6d8)) 368 | 369 | ## [2.0.1-beta.6](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.5...v2.0.1-beta.6) (2023-09-30) 370 | 371 | ### Bug Fixes 372 | 373 | - export types ([130dfec](https://github.com/sanity-io/sanity-astro/commit/130dfecddaff04bddc7491934ffa59658a2257c9)) 374 | 375 | ## [2.0.1-beta.5](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.4...v2.0.1-beta.5) (2023-09-30) 376 | 377 | ### Bug Fixes 378 | 379 | - use referenece path to include module ([8ceb4e6](https://github.com/sanity-io/sanity-astro/commit/8ceb4e6eada0b294b3d57ef008e0ae0938191e28)) 380 | 381 | ## [2.0.1-beta.4](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.3...v2.0.1-beta.4) (2023-09-30) 382 | 383 | ### Bug Fixes 384 | 385 | - include module declaration in dist ([bb4d04f](https://github.com/sanity-io/sanity-astro/commit/bb4d04fe195220eef474258d65f852bcfa2de089)) 386 | 387 | ## [2.0.1-beta.3](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.2...v2.0.1-beta.3) (2023-09-29) 388 | 389 | ### Bug Fixes 390 | 391 | - more typing ([b0efd78](https://github.com/sanity-io/sanity-astro/commit/b0efd781514fcfcf3ec681f865fb10c0405f3941)) 392 | 393 | ## [2.0.1-beta.2](https://github.com/sanity-io/sanity-astro/compare/v2.0.1-beta.1...v2.0.1-beta.2) (2023-09-29) 394 | 395 | ### Bug Fixes 396 | 397 | - include declaration files in build ([1820681](https://github.com/sanity-io/sanity-astro/commit/182068120922e8b4bbe4f1e758933779538f0701)) 398 | 399 | ## [2.0.1-beta.1](https://github.com/sanity-io/sanity-astro/compare/v2.0.0...v2.0.1-beta.1) (2023-09-29) 400 | 401 | ### Bug Fixes 402 | 403 | - add prerelease support ([53e005d](https://github.com/sanity-io/sanity-astro/commit/53e005db5f9bcac36c2c7f4c1c3baf2f1f80627a)) 404 | - clean up types and add module declarations ([34cf10d](https://github.com/sanity-io/sanity-astro/commit/34cf10dba261f67a58fe597051e8724d0df3d8ab)) 405 | - update lockfile ([77c4062](https://github.com/sanity-io/sanity-astro/commit/77c406208771f547359069b10462aa62a7f05fce)) 406 | 407 | ## [2.0.0](https://github.com/sanity-io/sanity-astro/compare/v1.3.0...v2.0.0) (2023-09-29) 408 | 409 | ### ⚠ BREAKING CHANGES 410 | 411 | - This deprecates the `useSanityClient` hook and exposes `sanityClient` on the 'sanity:client' module 412 | 413 | ### Features 414 | 415 | - remove hook and refactor to virtual module ([9eb2236](https://github.com/sanity-io/sanity-astro/commit/9eb2236b0df5a3ed258a3819ec8ba27fb5a9458e)) 416 | 417 | ### Bug Fixes 418 | 419 | - add mention of examples ([692e80e](https://github.com/sanity-io/sanity-astro/commit/692e80e48954c74c8a5ed5ffd3ccdc33e47dd0bb)) 420 | - **readme:** update documentation for new module names ([0ece721](https://github.com/sanity-io/sanity-astro/commit/0ece721683c54710e216f3ec0a9ab13c55e3381e)) 421 | 422 | ## [1.3.0](https://github.com/sanity-io/sanity-astro/compare/v1.2.1...v1.3.0) (2023-09-01) 423 | 424 | ### Features 425 | 426 | - add Astro 3 support ([#53](https://github.com/sanity-io/sanity-astro/issues/53)) ([8e9f976](https://github.com/sanity-io/sanity-astro/commit/8e9f976ce07dbcfaebc2ab50bc3735a432181168)) 427 | 428 | ## [1.2.1](https://github.com/sanity-io/sanity-astro/compare/v1.2.0...v1.2.1) (2023-08-24) 429 | 430 | ### Bug Fixes 431 | 432 | - **deps:** Update dependency @sanity/ui to ^1.7.10 ([#39](https://github.com/sanity-io/sanity-astro/issues/39)) ([e980ba0](https://github.com/sanity-io/sanity-astro/commit/e980ba057caaf218ba4660b0e903a81fcc99898f)) 433 | - **deps:** update dependency @sanity/ui to ^1.7.11 ([#44](https://github.com/sanity-io/sanity-astro/issues/44)) ([5d833af](https://github.com/sanity-io/sanity-astro/commit/5d833af8dd17eca0488335bf50248be193f47036)) 434 | 435 | ## [1.2.0](https://github.com/sanity-io/sanity-astro/compare/v1.1.5...v1.2.0) (2023-08-24) 436 | 437 | ### Features 438 | 439 | - Make studio embedding optional ([#40](https://github.com/sanity-io/sanity-astro/issues/40)) ([5690114](https://github.com/sanity-io/sanity-astro/commit/5690114eb2a0be761e695daf013e982d2cc30a85)) 440 | - Make studio optional ([#42](https://github.com/sanity-io/sanity-astro/issues/42)) ([c90b3bf](https://github.com/sanity-io/sanity-astro/commit/c90b3bf759bb4d5aea06d6dc8a09101775e21748)) 441 | 442 | ## [1.1.5](https://github.com/sanity-io/sanity-astro/compare/v1.1.4...v1.1.5) (2023-08-22) 443 | 444 | ### Bug Fixes 445 | 446 | - remove styled components peer dependency (again) ([3adb51f](https://github.com/sanity-io/sanity-astro/commit/3adb51f387d44c80723ef0a748310822211a800d)) 447 | 448 | ## [1.1.4](https://github.com/sanity-io/sanity-astro/compare/v1.1.3...v1.1.4) (2023-08-22) 449 | 450 | ### Bug Fixes 451 | 452 | - Remove styled components and preloaded theme support ([#29](https://github.com/sanity-io/sanity-astro/issues/29)) ([8a0f16e](https://github.com/sanity-io/sanity-astro/commit/8a0f16e94e05d6c7ac1a262cb61e18450c8bbd28)) 453 | 454 | ## [1.1.3](https://github.com/sanity-io/sanity-astro/compare/v1.1.2...v1.1.3) (2023-08-22) 455 | 456 | ### Bug Fixes 457 | 458 | - remove support for themed studio container ([#27](https://github.com/sanity-io/sanity-astro/issues/27)) ([9a1722a](https://github.com/sanity-io/sanity-astro/commit/9a1722a118f9b01d532da42602f056b5852b0f5c)) 459 | 460 | ## [1.1.2](https://github.com/sanity-io/sanity-astro/compare/v1.1.1...v1.1.2) (2023-08-22) 461 | 462 | ### Bug Fixes 463 | 464 | - add styled components as peer dependency ([#26](https://github.com/sanity-io/sanity-astro/issues/26)) ([1a2b797](https://github.com/sanity-io/sanity-astro/commit/1a2b797e8284541a4837b4d6e0b896ea55a59358)) 465 | 466 | ## [1.1.1](https://github.com/sanity-io/sanity-astro/compare/v1.1.0...v1.1.1) (2023-08-22) 467 | 468 | ### Bug Fixes 469 | 470 | - use node friendlier export conditions ([04ac44b](https://github.com/sanity-io/sanity-astro/commit/04ac44b61870dd287766e851894cbf20f17a6aa5)) 471 | 472 | ## [1.1.0](https://github.com/sanity-io/sanity-astro/compare/v1.0.2...v1.1.0) (2023-08-22) 473 | 474 | ### Features 475 | 476 | - add embedded studio ([#20](https://github.com/sanity-io/sanity-astro/issues/20)) ([77b62b0](https://github.com/sanity-io/sanity-astro/commit/77b62b0080aa806c078844d471da6c6c1e454de8)) 477 | 478 | ### Bug Fixes 479 | 480 | - **deps:** Update dependency @sanity/ui to ^1.7.9 ([#22](https://github.com/sanity-io/sanity-astro/issues/22)) ([4e06b99](https://github.com/sanity-io/sanity-astro/commit/4e06b997c65c5098ff455efe3a4a28218809d020)) 481 | 482 | ## [1.0.2](https://github.com/sanity-io/sanity-astro/compare/v1.0.1...v1.0.2) (2023-08-22) 483 | 484 | ### Bug Fixes 485 | 486 | - **deps:** update dependency @sanity/client to ^6.4.9 ([9ca2da9](https://github.com/sanity-io/sanity-astro/commit/9ca2da948d3136e6377d4825f5f49ff76614e57d)) 487 | 488 | ## [1.0.1](https://github.com/sanity-io/sanity-astro/compare/v1.0.0...v1.0.1) (2023-08-09) 489 | 490 | ### Bug Fixes 491 | 492 | - declare types in package.json ([#9](https://github.com/sanity-io/sanity-astro/issues/9)) ([8e729af](https://github.com/sanity-io/sanity-astro/commit/8e729afb9de44a1e049759d6491fcf8adb2d9f71)) 493 | 494 | ## 1.0.0 (2023-08-09) 495 | 496 | Initial release 497 | -------------------------------------------------------------------------------- /packages/sanity-astro/README.md: -------------------------------------------------------------------------------- 1 | # The Official Sanity integration for Astro 2 | 3 | This integration enables the [Sanity Client][sanity-client] in your [Astro][astro] project and lets you embed Sanity Studio on a route. Astro is an all-in-one web framework that supports a range of UI languages and can be deployed in most places. 4 | 5 | - [Installation](#installation) 6 | - [Manual installation of dependencies](#manual-installation-of-dependencies) 7 | - [Adding types for `sanity:client`](#adding-types-for-sanityclient) 8 | - [Usage](#usage) 9 | - [Setting up the Sanity client](#setting-up-the-sanity-client) 10 | - [Embedding Sanity Studio on a route](#embedding-sanity-studio-on-a-route) 11 | - [Rendering rich text and block content with Portable Text](#rendering-rich-text-and-block-content-with-portable-text) 12 | - [Presenting images](#presenting-images) 13 | - [Resources](#resources) 14 | - [Enabling Visual Editing](#enabling-visual-editing) 15 | 16 | ## Installation 17 | 18 | In your Astro project, run the following command to install the Sanity integration: 19 | 20 | ```bash 21 | npx astro add @sanity/astro @astrojs/react 22 | ``` 23 | 24 | Note: `@astrojs/react` is only needed if you plan to embed a Sanity Studio in your project. 25 | 26 | ### Manual installation of dependencies 27 | 28 | ```bash 29 | npm install @astrojs/react @sanity/astro @sanity/client sanity @types/react-dom @types/react-is @types/react react-dom react-is react styled-components 30 | ``` 31 | 32 | ### Adding types for `sanity:client` 33 | 34 | This integration leverages [Vite.js' virtual modules][vite-virtual-modules] with Astro's naming convention (e.g. `astro:assets`). Since it's not possible to automatically include module declarations from npm packages, you'll have to add the following line to the `env.d.ts` file that usually resides in the `src` folder of an Astro project: 35 | 36 | ```dts 37 | /// 38 | /// 39 | ``` 40 | 41 | You might have to restart the TS Server running in your code editor to get it to resolve types after updating this file. The easiest way to do this is to restart the application. 42 | 43 | ## Usage 44 | 45 | ### Setting up the Sanity client 46 | 47 | Configure the integration in your `astro.config.mjs` file. The configuration options and methods are the same as for [@sanity/client](https://github.com/sanity-io/client#readme): 48 | 49 | ```typescript 50 | import sanity from '@sanity/astro' 51 | import {defineConfig} from 'astro/config' 52 | 53 | // https://astro.build/config 54 | export default defineConfig({ 55 | integrations: [ 56 | sanity({ 57 | projectId: '', 58 | dataset: '', 59 | // Set useCdn to false if you're building statically. 60 | useCdn: false, 61 | }), 62 | ], 63 | }) 64 | ``` 65 | 66 | This enables the use of `sanityClient` in your template files. For example: 67 | 68 | ```mdx 69 | --- 70 | // /blog/index.astro 71 | import { sanityClient } from "sanity:client"; 72 | 73 | const posts = await sanityClient.fetch(`*[_type == "post" && defined(slug)] | order(publishedAt desc)`); 74 | --- 75 | 76 |

Blog

77 | 86 | ``` 87 | 88 | [Check out this guide][guide] for a more elaborate introduction to how to integrate content from Sanity into Astro. You can also look in the `examples` folder in this repository for complete implementation examples. 89 | 90 | ### Embedding Sanity Studio on a route 91 | 92 | Sanity Studio is a customizable content workspace where you can edit your content. It‘s a Single Page Application that you can keep in its own repository, together with your Astro project as a monorepo, or embedded in your website. 93 | 94 | To initialize a Studio in a dedicated folder, you can run `npm create sanity@latest` and follow the instructions. 95 | 96 | This integration lets you embed a Sanity Studio on a route in your Astro project. To enable it: 97 | 98 | 1. Create a new file in your project root called `sanity.config.ts` (or `.js`) 99 | 2. Add the following code, and add your `projectId` and `dataset` to it: 100 | 101 | ```typescript 102 | // sanity.config.ts 103 | import {defineConfig} from 'sanity' 104 | import {structureTool} from 'sanity/structure' 105 | 106 | export default defineConfig({ 107 | name: 'project-name', 108 | title: 'Project Name', 109 | projectId: '', 110 | dataset: '', 111 | plugins: [structureTool()], 112 | schema: { 113 | types: [ 114 | /* your content types here*/ 115 | ], 116 | }, 117 | }) 118 | ``` 119 | 120 | You can use this configuration file to install plugins, add a schema with document types, add customizations etc. Note that the Studio will be using Astro‘s development server which is built on top of [Vite][vite]. 121 | 122 | 1. Add the following to your `astro.config.mjs`: 123 | - `studioBasePath: '/admin'`: The route/path for where you want to access your studio 124 | - Import the [React integration for Astro][astro-react], and add it to the `integrations` array. 125 | 126 | ```javascript 127 | // astro.config.mjs 128 | import sanity from '@sanity/astro' 129 | import {defineConfig} from 'astro/config' 130 | import react from '@astrojs/react' 131 | 132 | export default defineConfig({ 133 | integrations: [ 134 | sanity({ 135 | projectId: '3do82whm', 136 | dataset: 'next', 137 | // Set useCdn to false if you're building statically. 138 | useCdn: false, 139 | // Access the Studio on your.url/admin 140 | studioBasePath: '/admin', 141 | }), 142 | react(), 143 | ], 144 | }) 145 | ``` 146 | 147 | 2. You have to [enable CORS origins for authenticated requests][cors] for the domains you're running your website project on. The Studio should automatically detect and let you add this when you access the Studio on a new URL. Typically you need to add your local development server URL and your production URL to the CORS origin settings. It's important that you only enable CORS for authenticated requests on domains that _you_ control. 148 | 149 | ## Rendering rich text and block content with Portable Text 150 | 151 | Sanity uses an open specification for rich text and block content called [Portable Text][portabletext]. Portable Text stores content from the editor as JSON (and not HTML or Markdown). This makes it platform/framework agnostic, and also queryable (for example, you can query for blog posts that have more than 4 TypeScript code blocks). 152 | 153 | While it's possible to loop over the JSON structure manually, we recommend using a Portable Text library to do the heavy lifting. It will automatically render the default editor configuration to HTML. If you do customizations like adding custom block types, then you need to map those to a component in your front end. 154 | 155 | We recommend using [astro-portabletext][astro-portabletext] to render your PortableText fields in Astro. See an example of this in [apps/example/src/components/PortableText.astro](../../blob/main/apps/example/src/components/PortableText.astro), including using custom components to render custom blocks and annotations. 156 | 157 | ```mdx 158 | --- 159 | import {PortableText as PortableTextInternal} from "astro-portabletext" 160 | import CallToActionBox from "./CallToActionBox.astro"; 161 | import Code from "./Code.astro"; 162 | import SanityImage from "./SanityImage.astro"; 163 | import YouTube from "./YouTube.astro"; 164 | import InternalLink from "./InternalLink.astro"; 165 | 166 | const components = { 167 | type: { 168 | callToActionBox: CallToActionBox, 169 | code: Code, 170 | image: SanityImage, 171 | youtube: YouTube, 172 | }, 173 | mark: { 174 | internalLink: InternalLink 175 | } 176 | }; 177 | 178 | --- 179 | 180 | 181 | ``` 182 | 183 | ## Presenting images 184 | 185 | Sanity comes with [a native asset pipeline for your images and files][image-urls]. It has on-demand transforms, automatic optimization for browsers that supports webp, and serves images from a global CDN network. When you upload images to Sanity, it will also automatically analyze the image and add [a metadata document][image-document] with information like dimensions, color palette, generate blurhash, and LQIP strings. 186 | 187 | We recommend using [@sanity/image-url](https://www.sanity.io/docs/image-url) to help you generate URLs for presenting Sanity images in your Astro app. See an example of this in [apps/example/src/components/SanityImage.astro](https://github.com/sanity-io/sanity-astro/blob/main/apps/example/src/components/SanityImage.astro) 188 | 189 | You can also use community-contributed integrations like [astro-sanity-picture][astro-sanity-picture] to integrate images from Sanity into your website. 190 | 191 | ## Enabling Visual Editing 192 | 193 | To enable [Visual Editing][visual-editing], you need to: 194 | 195 | 1. [Enable Overlays using the `VisualEditing` component](#1-enable-overlays-using-the-visualediting-component) 196 | 2. [Add the Presentation tool to the Studio](#2-add-the-presentation-tool-to-the-studio) 197 | 3. [Enable Stega](#3-enable-stega) 198 | 199 | **Please note that Visual Editing only works for [server-side rendered](https://docs.astro.build/en/guides/server-side-rendering/) pages.** This means you probably want to configure your Astro project something like this: 200 | 201 | ```js 202 | import vercel from '@astrojs/vercel' 203 | 204 | // astro.config.mjs 205 | export default defineConfig({ 206 | integrations: [ 207 | sanity({ 208 | useCdn: true, 209 | // ... 210 | }), 211 | // ... 212 | ], 213 | output: 'server', 214 | adapter: vercel(), 215 | }) 216 | ``` 217 | 218 | ### 1. Enable [Overlays][overlays] using the `VisualEditing` component 219 | 220 | Add `VisualEditing` from `@sanity/astro/visual-editing` in your ["page shell" layout](https://docs.astro.build/en/basics/layouts/): 221 | 222 | ```ts 223 | --- 224 | import {VisualEditing} from '@sanity/astro/visual-editing' 225 | 226 | export type props = { 227 | title: string 228 | } 229 | const {title} = Astro.props 230 | const visualEditingEnabled = import.meta.env.PUBLIC_SANITY_VISUAL_EDITING_ENABLED == 'true' 231 | --- 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | {title} 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | ``` 248 | 249 | `VisualEditing` is needed to render Overlays. It's a React component under the hood, so you'll need the [React integration for Astro][astro-react] if you don't already use that at this point. 250 | 251 | `VisualEditing` takes two props: 252 | 253 | - `enabled`: so you can control whether or not visual editing is enabled depending on your environment. 254 | - `zIndex` (optional): allows you to change the `z-index` of overlay elements. 255 | 256 | In the example above, `enabled` is controlled using an [environment variable](https://docs.astro.build/en/guides/environment-variables/): 257 | 258 | ```sh 259 | // .env.local 260 | PUBLIC_SANITY_VISUAL_EDITING_ENABLED="true" 261 | ``` 262 | 263 | ### 2. Add the Presentation tool to the Studio 264 | 265 | Follow the instructions on [how to configure the Presentation tool][presentation-tool]. 266 | 267 | ### 3. Enable [Stega][stega] 268 | 269 | If you already run Studio on an Astro route, then you can set the `stega.studioUrl` to the same relative path: 270 | 271 | ```js 272 | export default defineConfig({ 273 | integrations: [ 274 | sanity({ 275 | studioBasePath: '/admin', 276 | stega: { 277 | studioUrl: '/admin', 278 | }, 279 | }), 280 | ], 281 | }) 282 | ``` 283 | 284 | Now, all you need is a `loadQuery` helper function akin to this one: 285 | 286 | ```ts 287 | // load-query.ts 288 | import {type QueryParams} from 'sanity' 289 | import {sanityClient} from 'sanity:client' 290 | 291 | const visualEditingEnabled = import.meta.env.PUBLIC_SANITY_VISUAL_EDITING_ENABLED === 'true' 292 | const token = import.meta.env.SANITY_API_READ_TOKEN 293 | 294 | export async function loadQuery({ 295 | query, 296 | params, 297 | }: { 298 | query: string 299 | params?: QueryParams 300 | }) { 301 | if (visualEditingEnabled && !token) { 302 | throw new Error( 303 | 'The `SANITY_API_READ_TOKEN` environment variable is required during Visual Editing.', 304 | ) 305 | } 306 | 307 | const perspective = visualEditingEnabled ? 'drafts' : 'published' 308 | 309 | const {result, resultSourceMap} = await sanityClient.fetch(query, params ?? {}, { 310 | filterResponse: false, 311 | perspective, 312 | resultSourceMap: visualEditingEnabled ? 'withKeyArraySelector' : false, 313 | stega: visualEditingEnabled, 314 | ...(visualEditingEnabled ? {token} : {}), 315 | useCdn: !visualEditingEnabled, 316 | }) 317 | 318 | return { 319 | data: result, 320 | sourceMap: resultSourceMap, 321 | perspective, 322 | } 323 | } 324 | ``` 325 | 326 | You'll notice that we rely on a "read token" which is required in order to enable stega encoding and for authentication when Sanity Studio is live previewing your application. 327 | 328 | 1. Go to https://sanity.io/manage and select your project. 329 | 2. Click on the 🔌 API tab. 330 | 3. Click on + Add API token. 331 | 4. Name it "SANITY_API_READ_TOKEN" and set Permissions to Viewer and hit Save. 332 | 5. Copy the token and add it to your `.env.local` file: `SANITY_API_READ_TOKEN=""` 333 | 334 | Now, you can query and interact with stega-enabled data using the visual editing overlays: 335 | 336 | ```ts 337 | // some.astro file 338 | import {loadQuery} from '../load-query' 339 | 340 | const {data: movies} = await loadQuery>({ 341 | query: `*[_type == 'movie']`, 342 | }) 343 | ``` 344 | 345 | ### Resources 346 | 347 | - [The official Astro + Sanity guide][guide] 348 | - [Sanity documentation][docs] 349 | - [Portable Text integration for Astro][astro-portabletext] 350 | - [Astro Sanity Picture][astro-sanity-picture] 351 | - [Egghead's Introduction to GROQ][groq-intro] 352 | 353 | [astro]: https://astro.build 354 | [astro-react]: https://docs.astro.build/en/guides/integrations-guide/react/ 355 | [guide]: https://www.sanity.io/guides/sanity-astro-blog 356 | [docs]: https://www.sanity.io/docs 357 | [astro-portabletext]: https://github.com/theisel/astro-portabletext 358 | [cors]: https://www.sanity.io/docs/cors 359 | [vite]: https://vitejs.dev 360 | [portabletext]: https://portabletext.org 361 | [image-document]: https://www.sanity.io/docs/image-metadata 362 | [astro-sanity-picture]: https://github.com/otterdev-io/astro-sanity-picture 363 | [groq-intro]: https://egghead.io/courses/introduction-to-groq-query-language-6e9c6fc0 364 | [sanity-client]: https://www.sanity.io/docs/js-client 365 | [image-urls]: https://www.sanity.io/docs/image-urls 366 | [vite-virtual-modules]: https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention 367 | [visual-editing]: https://www.sanity.io/docs/introduction-to-visual-editing 368 | [presentation-tool]: https://www.sanity.io/docs/configuring-the-presentation-tool 369 | [overlays]: https://www.sanity.io/docs/visual-editing-overlays 370 | [stega]: https://www.sanity.io/docs/stega 371 | -------------------------------------------------------------------------------- /packages/sanity-astro/module.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'sanity:client' { 2 | export const sanityClient: import('@sanity/client').SanityClient 3 | } 4 | 5 | declare module 'sanity:studio' { 6 | export const studioConfig: import('sanity').Config 7 | } 8 | -------------------------------------------------------------------------------- /packages/sanity-astro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sanity/astro", 3 | "version": "3.2.6", 4 | "description": "Official Sanity Astro integration", 5 | "keywords": [ 6 | "astro-integration", 7 | "withastro", 8 | "sanity" 9 | ], 10 | "homepage": "https://www.sanity.io/plugins/sanity-astro", 11 | "bugs": { 12 | "url": "https://github.com/sanity-io/sanity-astro/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/sanity-io/sanity-astro.git", 17 | "directory": "packages/sanity-astro" 18 | }, 19 | "license": "MIT", 20 | "author": "Sanity.io ", 21 | "exports": { 22 | ".": { 23 | "types": "./dist/types/index.d.ts", 24 | "module": "./dist/sanity-astro.mjs", 25 | "default": "./dist/sanity-astro.mjs" 26 | }, 27 | "./module": "./module.d.ts", 28 | "./studio/studio-route.astro": "./dist/studio/studio-route.astro", 29 | "./studio/studio-route-hash.astro": "./dist/studio/studio-route-hash.astro", 30 | "./studio/studio-component.tsx": { 31 | "types": "./src/studio/studio-component.tsx", 32 | "default": "./src/studio/studio-component.tsx" 33 | }, 34 | "./visual-editing": { 35 | "import": "./dist/visual-editing/index.ts", 36 | "default": "./dist/visual-editing/index.ts" 37 | } 38 | }, 39 | "types": "./dist/types/index.d.ts", 40 | "files": [ 41 | "dist", 42 | "src/studio", 43 | "src/visual-editing", 44 | "module.d.ts" 45 | ], 46 | "scripts": { 47 | "build": "rimraf dist && vite build && pnpm copyStudio && pnpm copy:visual-editing", 48 | "clean": "rimraf dist && rimraf .turbo && rimraf node_modules", 49 | "copy:visual-editing": "cp -r src/visual-editing dist/visual-editing", 50 | "copyStudio": "cp -r src/studio dist/studio", 51 | "dev": "vite build --watch", 52 | "prepublishOnly": "pnpm build" 53 | }, 54 | "dependencies": { 55 | "@sanity/visual-editing": "^2.14.0", 56 | "history": "^5.3.0" 57 | }, 58 | "devDependencies": { 59 | "@sanity/client": "^7.3.0", 60 | "@types/serialize-javascript": "^5.0.4", 61 | "astro": "5.4.1", 62 | "react": "^19.0.0", 63 | "react-dom": "^19.0.0", 64 | "sanity": "^3.90.0", 65 | "serialize-javascript": "^6.0.2", 66 | "type-fest": "^4.41.0", 67 | "vite": "^6.2.0", 68 | "vite-plugin-dts": "^4.5.4" 69 | }, 70 | "peerDependencies": { 71 | "@sanity/client": "^7.3.0", 72 | "astro": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", 73 | "react": "^18.2.0 || ^19.0.0", 74 | "react-dom": "^18.2.0 || ^19.0.0", 75 | "react-is": "^18.2.0 || ^19.0.0", 76 | "sanity": "^3.90.0", 77 | "styled-components": "^6.1.18" 78 | }, 79 | "engines": { 80 | "node": ">=18.14.1" 81 | }, 82 | "publishConfig": { 83 | "access": "public" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/index.ts: -------------------------------------------------------------------------------- 1 | import type {AstroIntegration} from 'astro' 2 | import {vitePluginSanityClient} from './vite-plugin-sanity-client' 3 | import {vitePluginSanityStudio} from './vite-plugin-sanity-studio' 4 | import {vitePluginSanityStudioHashRouter} from './vite-plugin-sanity-studio-hash-router' 5 | import type {ClientConfig} from '@sanity/client' 6 | 7 | type IntegrationOptions = ClientConfig & { 8 | studioBasePath?: string 9 | studioRouterHistory?: 'browser' | 'hash' 10 | } 11 | 12 | const defaultClientConfig: ClientConfig = { 13 | apiVersion: 'v2023-08-24', 14 | } 15 | 16 | export default function sanityIntegration( 17 | integrationConfig: IntegrationOptions = {}, 18 | ): AstroIntegration { 19 | const studioBasePath = integrationConfig.studioBasePath 20 | const studioRouterHistory = integrationConfig.studioRouterHistory === 'hash' ? 'hash' : 'browser' 21 | const clientConfig = integrationConfig 22 | delete clientConfig.studioBasePath 23 | delete clientConfig.studioRouterHistory 24 | 25 | if (!!studioBasePath && studioBasePath.match(/https?:\/\//)) { 26 | throw new Error( 27 | "[@sanity/astro]: The `studioBasePath` option should be a relative URL. For example — `studioBasePath: '/admin'`", 28 | ) 29 | } 30 | 31 | return { 32 | name: '@sanity/astro', 33 | hooks: { 34 | 'astro:config:setup': ({injectScript, injectRoute, updateConfig}) => { 35 | updateConfig({ 36 | vite: { 37 | optimizeDeps: { 38 | include: [ 39 | 'react-compiler-runtime', 40 | 'react-is', 41 | 'styled-components', 42 | 'lodash/startCase.js', 43 | ], 44 | }, 45 | plugins: [ 46 | vitePluginSanityClient({ 47 | ...defaultClientConfig, 48 | ...clientConfig, 49 | }), 50 | vitePluginSanityStudio({studioBasePath}), 51 | vitePluginSanityStudioHashRouter(), 52 | ], 53 | }, 54 | }) 55 | // only load this route if `studioBasePath` is set 56 | if (studioBasePath) { 57 | // If the studio router history is set to hash, we can load a studio route that doesn't need a server adapter 58 | if (studioRouterHistory === 'hash') { 59 | injectRoute({ 60 | // @ts-expect-error 61 | entryPoint: '@sanity/astro/studio/studio-route-hash.astro', // Astro <= 3 62 | entrypoint: '@sanity/astro/studio/studio-route-hash.astro', // Astro > 3 63 | pattern: `/${studioBasePath}`, 64 | prerender: true, 65 | }) 66 | } else { 67 | injectRoute({ 68 | // @ts-expect-error 69 | entryPoint: '@sanity/astro/studio/studio-route.astro', // Astro <= 3 70 | entrypoint: '@sanity/astro/studio/studio-route.astro', // Astro > 3 71 | pattern: `/${studioBasePath}/[...params]`, 72 | prerender: false, 73 | }) 74 | } 75 | } 76 | injectScript( 77 | 'page-ssr', 78 | ` 79 | import { sanityClient } from "sanity:client"; 80 | globalThis.sanityClient = sanityClient; 81 | `, 82 | ) 83 | }, 84 | }, 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/studio/studio-component.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {createHashHistory, type History, type Listener} from 'history' 3 | // @ts-ignore 4 | import {config} from 'sanity:studio' 5 | import {Studio} from 'sanity' 6 | 7 | if (!config) { 8 | throw new Error( 9 | "[@sanity/astro]: Can't load Sanity Studio. Check that you've configured it in `sanity.config.js|ts`.", 10 | ) 11 | } 12 | 13 | export function StudioComponent(props: {history?: 'browser' | 'hash'}) { 14 | const history = React.useMemo( 15 | () => (props.history === 'hash' ? createHashHistoryForStudio() : undefined), 16 | [props.history], 17 | ) 18 | return ( 19 |
29 | 30 |
31 | ) 32 | } 33 | 34 | function createHashHistoryForStudio(): History { 35 | const history = createHashHistory() 36 | return { 37 | get action() { 38 | return history.action 39 | }, 40 | get location() { 41 | return history.location 42 | }, 43 | get createHref() { 44 | return history.createHref 45 | }, 46 | get push() { 47 | return history.push 48 | }, 49 | get replace() { 50 | return history.replace 51 | }, 52 | get go() { 53 | return history.go 54 | }, 55 | get back() { 56 | return history.back 57 | }, 58 | get forward() { 59 | return history.forward 60 | }, 61 | get block() { 62 | return history.block 63 | }, 64 | // Overriding listen to workaround a problem where native history provides history.listen(location => void), but the npm package is history.listen(({action, location}) => void) 65 | listen(listener: Listener) { 66 | return history.listen(({location}) => { 67 | // @ts-expect-error -- working around a bug? in studio 68 | listener(location) 69 | }) 70 | }, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/studio/studio-route-hash.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {StudioComponent} from './studio-component' 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | Sanity Studio 18 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/studio/studio-route.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {StudioComponent} from './studio-component' 3 | // Astro will warn about this being ignore, but it has to be there. 4 | export async function getStaticPaths() { 5 | return [{params: {path: 'admin'}}] 6 | } 7 | // This route needs to run in "SPA" mode, so we need to set `prerender` to `false` 8 | export const prerender = false 9 | --- 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | Sanity Studio 24 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/studio/studio-route.ts: -------------------------------------------------------------------------------- 1 | import StudioRoute from './studio-route.astro' 2 | export default StudioRoute 3 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/visual-editing/index.ts: -------------------------------------------------------------------------------- 1 | export {default as VisualEditing} from './visual-editing.astro' 2 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/visual-editing/visual-editing-component.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | VisualEditing as InternalVisualEditing, 4 | type VisualEditingOptions as InternalVisualEditingOptions, 5 | } from '@sanity/visual-editing/react' 6 | 7 | export type VisualEditingOptions = Pick 8 | 9 | export function VisualEditingComponent(props: VisualEditingOptions) { 10 | return ( 11 | { 15 | return new Promise((resolve) => { 16 | window.location.reload() 17 | resolve() 18 | }) 19 | }} 20 | /> 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/visual-editing/visual-editing.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {VisualEditingComponent, type VisualEditingOptions} from './visual-editing-component' 3 | 4 | export interface Props extends VisualEditingOptions { 5 | enabled?: boolean 6 | } 7 | 8 | const {enabled, zIndex} = Astro.props 9 | --- 10 | 11 | {enabled ? : null} 12 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/vite-plugin-sanity-client.ts: -------------------------------------------------------------------------------- 1 | import type {ClientConfig} from '@sanity/client' 2 | import type {PartialDeep} from 'type-fest' 3 | import serialize from 'serialize-javascript' 4 | import type {PluginOption} from 'vite' 5 | 6 | const virtualModuleId = 'sanity:client' 7 | const resolvedVirtualModuleId = '\0' + virtualModuleId 8 | 9 | export function vitePluginSanityClient(config: ClientConfig) { 10 | return { 11 | name: 'sanity:client', 12 | resolveId(id: string) { 13 | if (id === virtualModuleId) { 14 | return resolvedVirtualModuleId 15 | } 16 | }, 17 | load(id: string) { 18 | if (id === resolvedVirtualModuleId) { 19 | return ` 20 | import { createClient } from "@sanity/client"; 21 | export const sanityClient = createClient( 22 | ${serialize(config)} 23 | ); 24 | ` 25 | } 26 | }, 27 | } satisfies PartialDeep 28 | } 29 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/vite-plugin-sanity-studio-hash-router.ts: -------------------------------------------------------------------------------- 1 | import type {PartialDeep} from 'type-fest' 2 | import type {PluginOption} from 'vite' 3 | 4 | export function vitePluginSanityStudioHashRouter() { 5 | const virtualModuleId = 'sanity:studio-hash-router' 6 | const resolvedVirtualModuleId = virtualModuleId 7 | 8 | return { 9 | name: 'sanity:studio-hash-router', 10 | resolveId(id: string) { 11 | if (id === virtualModuleId) { 12 | return resolvedVirtualModuleId 13 | } 14 | return null 15 | }, 16 | async load(id: string) { 17 | if (id === virtualModuleId) { 18 | const studioConfig = await this.resolve('/sanity.config') 19 | if (!studioConfig) { 20 | throw new Error( 21 | '[@sanity/astro]: Sanity Studio requires a `sanity.config.ts|js` file in your project root.', 22 | ) 23 | } 24 | 25 | return `export {default} from "${studioConfig.id}";` 26 | } 27 | return null 28 | }, 29 | } satisfies PartialDeep 30 | } 31 | -------------------------------------------------------------------------------- /packages/sanity-astro/src/vite-plugin-sanity-studio.ts: -------------------------------------------------------------------------------- 1 | import type {PartialDeep} from 'type-fest' 2 | import type {PluginOption} from 'vite' 3 | 4 | export function vitePluginSanityStudio(resolvedOptions: {studioBasePath?: string}) { 5 | const virtualModuleId = 'sanity:studio' 6 | const resolvedVirtualModuleId = virtualModuleId 7 | 8 | return { 9 | name: 'sanity:studio', 10 | resolveId(id: string) { 11 | if (id === virtualModuleId) { 12 | return resolvedVirtualModuleId 13 | } 14 | return null 15 | }, 16 | async load(id: string) { 17 | if (id === virtualModuleId) { 18 | const studioConfig = await this.resolve('/sanity.config') 19 | if (!studioConfig) { 20 | throw new Error( 21 | '[@sanity/astro]: Sanity Studio requires a `sanity.config.ts|js` file in your project root.', 22 | ) 23 | } 24 | if (!resolvedOptions.studioBasePath) { 25 | throw new Error( 26 | "[@sanity/astro]: The `studioBasePath` option is required in `astro.config.mjs`. For example — `studioBasePath: '/admin'`", 27 | ) 28 | } 29 | return ` 30 | import studioConfig from "${studioConfig.id}"; 31 | 32 | if (studioConfig.basePath) { 33 | if (studioConfig.basePath !== "/${resolvedOptions.studioBasePath}") { 34 | console.warn( 35 | "[@sanity/astro]: This integration ignores the basePath setting in sanity.config.ts|js. To set the basePath for Sanity Studio, use the studioBasePath option in astro.config.mjs and remove it from sanity.config.ts."); 36 | } 37 | } 38 | 39 | export const config = { 40 | ...studioConfig, 41 | // override basePath from sanity.config.ts|js with plugin setting 42 | basePath: "${resolvedOptions.studioBasePath}", 43 | } 44 | ` 45 | } 46 | return null 47 | }, 48 | } satisfies PartialDeep 49 | } 50 | -------------------------------------------------------------------------------- /packages/sanity-astro/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/base", 3 | "$schema": "https://json.schemastore.org/tsconfig", 4 | "include": ["src"], 5 | "exclude": ["node_modules/*", "dist"], 6 | "compilerOptions": { 7 | "baseUrl": "src", 8 | "outDir": "./dist", 9 | "declaration": true, 10 | "declarationDir": "./dist" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/sanity-astro/vite.config.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig, type Plugin} from 'vite' 2 | import path from 'path' 3 | import dts from 'vite-plugin-dts' 4 | 5 | const name = 'sanity-astro' 6 | 7 | export default defineConfig(() => { 8 | return { 9 | base: '/src', 10 | build: { 11 | lib: { 12 | entry: [path.resolve(__dirname, 'src/index.ts')], 13 | name, 14 | fileName: (format) => (format === 'es' ? `${name}.mjs` : `${name}.js`), 15 | }, 16 | }, 17 | plugins: [ 18 | dts({ 19 | outDir: 'dist/types', 20 | }) as unknown as Plugin, 21 | ], 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'apps/*' 3 | - 'packages/*' 4 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "pipeline": { 5 | "clean": { 6 | "cache": false 7 | }, 8 | "build": { 9 | "env": [ 10 | "PUBLIC_SANITY_PROJECT_ID", 11 | "PUBLIC_SANITY_DATASET", 12 | "PUBLIC_SANITY_VISUAL_EDITING_ENABLED", 13 | "SANITY_API_READ_TOKEN" 14 | ], 15 | "dependsOn": ["^build"], 16 | "outputs": [ 17 | "dist/**", 18 | ".next/**", 19 | "!.next/cache/**", 20 | "build/**", 21 | "public/**", 22 | ".vercel/output/**" 23 | ] 24 | }, 25 | "lint": {}, 26 | "dev": { 27 | "dependsOn": ["^build"], 28 | "cache": false, 29 | "persistent": true 30 | } 31 | } 32 | } 33 | --------------------------------------------------------------------------------