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({