diff --git a/.env.example b/.env.example
index 566291bd..7d2d0cb8 100644
--- a/.env.example
+++ b/.env.example
@@ -2,4 +2,7 @@ NEXT_PUBLIC_BASE_URL =
NEXT_PUBLIC_SANITY_PROJECT_ID =
NEXT_PUBLIC_SANITY_DATASET =
-NEXT_PUBLIC_SANITY_TOKEN = # "Viewer" token from https://sanity.io/manage
+
+SANITY_API_READ_TOKEN = # "Viewer" token from https://sanity.io/manage
+
+NEXT_PUBLIC_GITHUB_TOKEN = # used for Reputation blocks
diff --git a/README.md b/README.md
index 8ee5e223..5f630739 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
An opinionated, fully customizable Next.js (App Router) and Sanity starter template with Tailwind CSS and pre-built schema for rapid website development.
-[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fnuotsu%2Fsanitypress&env=NEXT_PUBLIC_BASE_URL,NEXT_PUBLIC_SANITY_PROJECT_ID,NEXT_PUBLIC_SANITY_DATASET,NEXT_PUBLIC_SANITY_TOKEN&envDescription=Values%20needed%20to%20connect%20a%20Sanity%20CMS&envLink=https%3A%2F%2Fsanitypress.dev%2Fdocs%2Fgetting-started&demo-title=SanityPress&demo-description=Official%20website%20and%20blog%20for%20SanityPress%2C%20built%20with%20SanityPress&demo-url=https%3A%2F%2Fsanitypress.dev&demo-image=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Felyfelq1%2Fproduction%2F7fb61a2b110f509582f0f43cb1e397f8fa9e5c07-2814x1798.png%3Fw%3D1600)
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fnuotsu%2Fsanitypress&env=NEXT_PUBLIC_BASE_URL,NEXT_PUBLIC_SANITY_PROJECT_ID,NEXT_PUBLIC_SANITY_DATASET,SANITY_API_READ_TOKEN&envDescription=Values%20needed%20to%20connect%20a%20Sanity%20CMS&envLink=https%3A%2F%2Fsanitypress.dev%2Fdocs%2Fgetting-started&demo-title=SanityPress&demo-description=Official%20website%20and%20blog%20for%20SanityPress%2C%20built%20with%20SanityPress&demo-url=https%3A%2F%2Fsanitypress.dev&demo-image=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Felyfelq1%2Fproduction%2F7fb61a2b110f509582f0f43cb1e397f8fa9e5c07-2814x1798.png%3Fw%3D1600)
![](https://cdn.sanity.io/images/elyfelq1/production/a095b5478b3173381915c5a0a973fdb3d8898094-5088x3458.jpg)
@@ -49,7 +49,8 @@ From the [Sanity.io Manage](https://sanity.io/manage) dashboard, create a new pr
NEXT_PUBLIC_BASE_URL = ... # https://sanitypress.dev
NEXT_PUBLIC_SANITY_PROJECT_ID = ... # abcdefgh
NEXT_PUBLIC_SANITY_DATASET = ... # production
-NEXT_PUBLIC_SANITY_TOKEN = ... # "Viewer" token from https://sanity.io/manage
+
+SANITY_API_READ_TOKEN = ... # "Viewer" token from https://sanity.io/manage
```
### 4. Populate the Studio with your content
diff --git a/next.config.ts b/next.config.ts
index 492295b1..cce90c91 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,11 +1,12 @@
import { createClient, groq } from 'next-sanity'
+// import { token } from '@/lib/sanity/token'
import type { NextConfig } from 'next'
const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
- // token: process.env.NEXT_PUBLIC_SANITY_TOKEN for private datasets
- apiVersion: '2024-10-30',
+ // token, // for private datasets
+ apiVersion: '2024-11-01',
useCdn: true,
})
@@ -27,6 +28,10 @@ const nextConfig: NextConfig = {
}`)
},
+ env: {
+ SC_DISABLE_SPEEDY: 'false',
+ },
+
// logging: {
// fetches: {
// fullUrl: true,
diff --git a/package-lock.json b/package-lock.json
index b752034d..930e60e3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "sanitypress",
- "version": "4.11.1",
+ "version": "4.11.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sanitypress",
- "version": "4.11.1",
+ "version": "4.11.3",
"license": "ISC",
"dependencies": {
"@next/third-parties": "^15.0.2",
@@ -29,7 +29,6 @@
"react-dom": "^18",
"react-icons": "^5.3.0",
"react-is": "^18.3.1",
- "rxjs": "^7.8.1",
"sanity": "^3.62.3",
"sanity-plugin-dashboard-widget-vercel": "^2.0.1",
"shiki": "^1.22.2",
diff --git a/package.json b/package.json
index cddec6da..38770fad 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"license": "ISC",
"scripts": {
"dev": "next dev",
+ "dev:turbo": "next dev --turbo",
"build": "next build",
"start": "next start",
"lint": "next lint"
@@ -31,7 +32,6 @@
"react-dom": "^18",
"react-icons": "^5.3.0",
"react-is": "^18.3.1",
- "rxjs": "^7.8.1",
"sanity": "^3.62.3",
"sanity-plugin-dashboard-widget-vercel": "^2.0.1",
"shiki": "^1.22.2",
diff --git a/sanity/sanity.cli.ts b/sanity/sanity.cli.ts
index 23aa3a22..9e57a5d9 100644
--- a/sanity/sanity.cli.ts
+++ b/sanity/sanity.cli.ts
@@ -2,7 +2,7 @@ import { defineCliConfig } from 'sanity/cli'
export default defineCliConfig({
api: {
- projectId: '',
- dataset: '',
+ projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
+ dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
},
})
diff --git a/sanity/sanity.config.ts b/sanity/sanity.config.ts
index a8aad70f..87d1a644 100644
--- a/sanity/sanity.config.ts
+++ b/sanity/sanity.config.ts
@@ -1,9 +1,9 @@
import { defineConfig } from 'sanity'
-import { BASE_URL, projectId, dataset } from './src/env'
+import { projectId, dataset } from './src/env'
import { structureTool } from 'sanity/structure'
import structure from './src/structure'
import { presentationTool } from 'sanity/presentation'
-import { locations } from './src/presentation'
+import { resolve } from './src/presentation/resolve'
import {
dashboardTool,
projectInfoWidget,
@@ -35,11 +35,11 @@ export default defineConfig({
name: 'editor',
title: 'Editor',
previewUrl: {
- draftMode: {
- enable: `${BASE_URL}/api/draft`,
+ previewMode: {
+ enable: '/api/draft-mode/enable',
},
},
- resolve: { locations },
+ resolve,
}),
dashboardTool({
name: 'deployment',
diff --git a/sanity/src/presentation.ts b/sanity/src/presentation.ts
deleted file mode 100644
index a924440f..00000000
--- a/sanity/src/presentation.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { map } from 'rxjs'
-import type { DocumentLocationResolver } from 'sanity/presentation'
-
-export const locations: DocumentLocationResolver = (params, context) => {
- if (['page', 'blog.post'].includes(params.type)) {
- const doc$ = context.documentStore.listenQuery(
- `*[_id == $id][0]{title,metadata}`,
- params,
- { perspective: 'previewDrafts' },
- )
-
- return doc$.pipe(
- map((doc) => {
- if (!doc?.metadata?.slug?.current) return null
-
- const segment = params.type === 'blog.post' ? '/blog' : ''
- const slug = doc.metadata.slug.current
- const path = slug === 'index' ? '' : `/${slug}`
-
- return {
- locations: [
- {
- title: doc.title || doc.metadata.title || 'Untitled',
- href: [segment, path].filter(Boolean).join(''),
- },
- ],
- }
- }),
- )
- }
-
- return null
-}
diff --git a/sanity/src/presentation/resolve.ts b/sanity/src/presentation/resolve.ts
new file mode 100644
index 00000000..3e9a9dc4
--- /dev/null
+++ b/sanity/src/presentation/resolve.ts
@@ -0,0 +1,40 @@
+import {
+ defineLocations,
+ type PresentationPluginOptions,
+} from 'sanity/presentation'
+
+export const resolve: PresentationPluginOptions['resolve'] = {
+ locations: {
+ page: defineLocations({
+ select: {
+ metadata: 'metadata',
+ },
+ resolve: (doc) => {
+ const slug = doc?.metadata?.slug?.current
+
+ return {
+ locations: [
+ {
+ title: doc?.metadata?.title,
+ href: slug === 'index' ? '/' : `/${slug}`,
+ },
+ ],
+ }
+ },
+ }),
+
+ 'blog.post': defineLocations({
+ select: {
+ metadata: 'metadata',
+ },
+ resolve: (doc) => ({
+ locations: [
+ {
+ title: doc?.metadata?.title,
+ href: `/blog/${doc?.metadata?.slug?.current}`,
+ },
+ ],
+ }),
+ }),
+ },
+}
diff --git a/src/app/(frontend)/api/draft-mode/disable/route.ts b/src/app/(frontend)/api/draft-mode/disable/route.ts
new file mode 100644
index 00000000..fe54fe47
--- /dev/null
+++ b/src/app/(frontend)/api/draft-mode/disable/route.ts
@@ -0,0 +1,10 @@
+import { draftMode } from 'next/headers'
+import { NextRequest, NextResponse } from 'next/server'
+
+export async function GET(request: NextRequest) {
+ ;(await draftMode()).disable()
+
+ const url = new URL(request.nextUrl)
+
+ return NextResponse.redirect(new URL('/', url.origin))
+}
diff --git a/src/app/(frontend)/api/draft-mode/enable/route.ts b/src/app/(frontend)/api/draft-mode/enable/route.ts
new file mode 100644
index 00000000..b5334bd6
--- /dev/null
+++ b/src/app/(frontend)/api/draft-mode/enable/route.ts
@@ -0,0 +1,7 @@
+import { defineEnableDraftMode } from 'next-sanity/draft-mode'
+import client from '@/lib/sanity/client'
+import { token } from '@/lib/sanity/token'
+
+export const { GET } = defineEnableDraftMode({
+ client: client.withConfig({ token }),
+})
diff --git a/src/app/(frontend)/api/draft/route.ts b/src/app/(frontend)/api/draft/route.ts
deleted file mode 100644
index 9fa77c89..00000000
--- a/src/app/(frontend)/api/draft/route.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import client from '@/lib/sanity/client'
-import { validatePreviewUrl } from '@sanity/preview-url-secret'
-import { draftMode } from 'next/headers'
-import { redirect } from 'next/navigation'
-
-const clientWithToken = client.withConfig({
- token: process.env.NEXT_PUBLIC_SANITY_TOKEN,
-})
-
-export async function GET(request: Request) {
- const { isValid, redirectTo = '/' } = await validatePreviewUrl(
- clientWithToken,
- request.url,
- )
-
- if (!isValid) {
- return new Response('Invalid secret', { status: 401 })
- }
-
- (await draftMode()).enable()
-
- redirect(redirectTo)
-}
diff --git a/src/app/(frontend)/layout.tsx b/src/app/(frontend)/layout.tsx
index 9f739a55..03abf4da 100644
--- a/src/app/(frontend)/layout.tsx
+++ b/src/app/(frontend)/layout.tsx
@@ -3,9 +3,10 @@ import SkipToContent from '@/ui/SkipToContent'
import Announcement from '@/ui/Announcement'
import Header from '@/ui/header'
import Footer from '@/ui/footer'
+import { SanityLive } from '@/lib/sanity/fetch'
+import VisualEditingControls from '@/ui/VisualEditingControls'
import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'
-import VisualEditingControls from '@/ui/VisualEditingControls'
import '@/styles/app.css'
export default async function RootLayout({
@@ -26,9 +27,11 @@ export default async function RootLayout({
+
+
+
-