11/**
2- * Sanity Studio configuration for standalone deployment
3- * Migrated from Next.js embedded studio to standalone Sanity Studio app
2+ * Sanity Studio configuration with dev/production workspaces.
3+ *
4+ * Both workspaces share the same schemas, plugins, and structure.
5+ * They differ only in dataset and presentation tool preview URL.
6+ *
7+ * Workspace switcher appears in the Studio top-left corner.
48 */
59import { visionTool } from "@sanity/vision" ;
610import { type PluginOptions , defineConfig } from "sanity" ;
@@ -46,15 +50,15 @@ import podcastSeries from "./schemas/documents/podcastSeries";
4650import category from "./schemas/documents/category" ;
4751import short from "./schemas/documents/short" ;
4852
49- // Sanity Studio env vars (SANITY_STUDIO_ prefix is auto-exposed by Sanity CLI)
53+ // ── Shared constants ─────────────────────────────────────────────────
5054const projectId = process . env . SANITY_STUDIO_PROJECT_ID || "hfh83o0w" ;
51- const dataset = process . env . SANITY_STUDIO_DATASET || "production" ;
5255const apiVersion = process . env . SANITY_STUDIO_API_VERSION || "2025-09-30" ;
53- const studioUrl = "/" ;
56+
5457// Set SANITY_STUDIO_DISABLE_PRESENTATION=true if you get network errors to api.sanity.io (e.g. firewall/VPN)
5558const presentationEnabled =
5659 process . env . SANITY_STUDIO_DISABLE_PRESENTATION !== "true" ;
5760
61+ // ── Shared helpers ───────────────────────────────────────────────────
5862function resolveHref ( type : string , slug ?: string ) : string | undefined {
5963 switch ( type ) {
6064 case "post" :
@@ -71,6 +75,45 @@ const homeLocation = {
7175 href : "/" ,
7276} satisfies DocumentLocation ;
7377
78+ // ── Shared schema types ──────────────────────────────────────────────
79+ const schemaTypes = [
80+ // Portable text block types (table)
81+ tableSchema ,
82+ rowType ,
83+ // Singletons
84+ settings ,
85+ engineConfig ,
86+ // Documents
87+ author ,
88+ guest ,
89+ page ,
90+ podcast ,
91+ podcastType ,
92+ post ,
93+ sponsor ,
94+ previewSession ,
95+ sponsorshipRequest ,
96+ contentIdea ,
97+ automatedVideo ,
98+ mediaAsset ,
99+ videoAnalytics ,
100+ sponsorLead ,
101+ sponsorPool ,
102+ // New document types
103+ podcastSeries ,
104+ category ,
105+ short ,
106+ ] ;
107+
108+ // ── Shared document actions ──────────────────────────────────────────
109+ const documentActions = ( prev : any [ ] , context : { schemaType : string } ) => {
110+ if ( context . schemaType === "post" || context . schemaType === "podcast" ) {
111+ return [ sharePreviewAction , ...prev ] ;
112+ }
113+ return prev ;
114+ } ;
115+
116+ // ── Shared podcast structure ─────────────────────────────────────────
74117export const podcastStructure = ( ) : StructureResolver => {
75118 return ( S ) => {
76119 return S . list ( )
@@ -138,49 +181,9 @@ export const podcastStructure = (): StructureResolver => {
138181 } ;
139182} ;
140183
141- export default defineConfig ( {
142- basePath : studioUrl ,
143- projectId,
144- dataset,
145- schema : {
146- types : [
147- // Portable text block types (table)
148- tableSchema ,
149- rowType ,
150- // Singletons
151- settings ,
152- engineConfig ,
153- // Documents
154- author ,
155- guest ,
156- page ,
157- podcast ,
158- podcastType ,
159- post ,
160- sponsor ,
161- previewSession ,
162- sponsorshipRequest ,
163- contentIdea ,
164- automatedVideo ,
165- mediaAsset ,
166- videoAnalytics ,
167- sponsorLead ,
168- sponsorPool ,
169- // New document types
170- podcastSeries ,
171- category ,
172- short ,
173- ] ,
174- } ,
175- document : {
176- actions : ( prev , context ) => {
177- if ( context . schemaType === "post" || context . schemaType === "podcast" ) {
178- return [ sharePreviewAction , ...prev ] ;
179- }
180- return prev ;
181- } ,
182- } ,
183- plugins : [
184+ // ── Build plugins for a given preview URL ────────────────────────────
185+ function buildPlugins ( previewUrl : string ) : PluginOptions [ ] {
186+ return [
184187 ...( presentationEnabled
185188 ? [
186189 presentationTool ( {
@@ -216,6 +219,7 @@ export default defineConfig({
216219 } ,
217220 } ,
218221 previewUrl : {
222+ origin : previewUrl ,
219223 previewMode : {
220224 enable : "/api/draft-mode/enable" ,
221225 disable : "/api/draft-mode/disable" ,
@@ -225,12 +229,10 @@ export default defineConfig({
225229 ]
226230 : [ ] ) ,
227231 structureTool ( { structure : podcastStructure ( ) } ) ,
228- // Configures the global "new document" button, and document actions, to suit the Settings document singleton
229232 singletonPlugin ( [
230233 settings . name ,
231234 engineConfig . name ,
232235 ] ) ,
233- // Sets up AI Assist with preset prompts
234236 assistWithPresets ( ) ,
235237 media ( ) ,
236238 codeInput ( ) ,
@@ -242,7 +244,30 @@ export default defineConfig({
242244 } ,
243245 ] ,
244246 } ) ,
245- // Vision lets you query your content with GROQ in the studio
246247 visionTool ( { defaultApiVersion : apiVersion } ) ,
247- ] . filter ( Boolean ) as PluginOptions [ ] ,
248- } ) ;
248+ ] . filter ( Boolean ) as PluginOptions [ ] ;
249+ }
250+
251+ // ── Workspace definitions ────────────────────────────────────────────
252+ export default defineConfig ( [
253+ {
254+ name : "production" ,
255+ title : "CodingCat.dev (Production)" ,
256+ projectId,
257+ dataset : "production" ,
258+ basePath : "/production" ,
259+ schema : { types : schemaTypes } ,
260+ document : { actions : documentActions } ,
261+ plugins : buildPlugins ( "https://codingcat.dev" ) ,
262+ } ,
263+ {
264+ name : "dev" ,
265+ title : "CodingCat.dev (Dev)" ,
266+ projectId,
267+ dataset : "dev" ,
268+ basePath : "/dev" ,
269+ schema : { types : schemaTypes } ,
270+ document : { actions : documentActions } ,
271+ plugins : buildPlugins ( "https://dev.codingcat.dev" ) ,
272+ } ,
273+ ] ) ;
0 commit comments