├── .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 |
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 |
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 |
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 &&
}
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 |
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 |
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 |
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 &&
}
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 |
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) => - {movie.title}
)}
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 |
--------------------------------------------------------------------------------