Skip to content

Commit

Permalink
adjust current studio and add shared studio
Browse files Browse the repository at this point in the history
  • Loading branch information
christinaroise committed Aug 26, 2024
1 parent 79da6d5 commit d2fdbb2
Show file tree
Hide file tree
Showing 17 changed files with 6,936 additions and 5,398 deletions.
12,052 changes: 6,662 additions & 5,390 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions src/app/shared/[[...index]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

/**
* This route is responsible for the built-in authoring environment using Sanity Studio.
* All routes under your studio path is handled by this file using Next.js' catch-all routes:
* https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes
*
* You can learn more about the next-sanity package here:
* https://github.com/sanity-io/next-sanity
*/

import { NextStudio } from "next-sanity/studio";

import config from "../../../../studioShared/sanity.config";

export default function StudioPage() {
return <NextStudio config={config} />;
}
2 changes: 1 addition & 1 deletion src/app/studio/[[...index]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import { NextStudio } from "next-sanity/studio";

import config from "../../../../sanity.config";
import config from "../../../../studio/sanity.config";

export default function StudioPage() {
return <NextStudio config={config} />;
Expand Down
4 changes: 0 additions & 4 deletions sanity.cli.ts → studio/sanity.cli.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/**
* This configuration file lets you run `$ sanity [command]` in this folder
* Go to https://www.sanity.io/docs/cli to learn more.
**/
import { defineCliConfig } from "sanity/cli";

const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;
Expand Down
6 changes: 3 additions & 3 deletions sanity.config.ts → studio/sanity.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { visionTool } from "@sanity/vision";
import { defineConfig } from "sanity";
import { presentationTool } from "sanity/presentation";
import { structureTool } from "sanity/structure";
import deskStructure from "./studio/schemas/deskStructure";

// Go to https://www.sanity.io/docs/api-versioning to learn how API versioning works
import { apiVersion, dataset, projectId } from "./studio/env";
import { schema } from "./studio/schema";
import { apiVersion, dataset, projectId } from "./env";
import { schema } from "./schema";
import deskStructure from "./schemas/deskStructure";

export default defineConfig({
basePath: "/studio",
Expand Down
6 changes: 6 additions & 0 deletions studio/schemas/objects/sections/blogPosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import callToActionField from "../../../schemas/fields/callToActionFields";

export const articleID = "blogPostsID";

/*
* DEPRECATED: The `blogPosts` object is deprecated.
* Please avoid using this field in new schemas or content types.
* Consider using a different structure for blog posts.
*/

export const blogPosts = defineField({
name: articleID,
title: "Blog Posts",
Expand Down
23 changes: 23 additions & 0 deletions studioShared/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Client-Safe Variables

export const apiVersion =
process.env.NEXT_PUBLIC_SANITY_SHARED_API_VERSION || "v2024-04-29";

export const dataset = assertValue(
process.env.NEXT_PUBLIC_SANITY_SHARED_DATASET,
"Missing environment variable: NEXT_PUBLIC_SANITY_SHARED_DATASET"
);

export const projectId = assertValue(
process.env.NEXT_PUBLIC_SANITY_SHARED_PROJECT_ID,
"Missing environment variable: NEXT_PUBLIC_SANITY_SHARED_PROJECT_ID"
);

export const useCdn = process.env.NODE_ENV === "production";

function assertValue<T>(v: T | undefined, errorMessage: string): T {
if (v === undefined) {
throw new Error(errorMessage);
}
return v;
}
17 changes: 17 additions & 0 deletions studioShared/lib/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Sanity Client Configuration

import { createClient } from "next-sanity";
import { apiVersion, dataset, projectId, useCdn } from "../env";

export const sharedClient = createClient({
apiVersion,
dataset,
projectId,
useCdn,
perspective:
process.env.NODE_ENV === "development" ? "previewDrafts" : "published",
stega: {
enabled: false,
studioUrl: "/shared",
},
});
38 changes: 38 additions & 0 deletions studioShared/lib/fetchWithToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* fetchWithToken
*
* Utility function to securely fetch data from the server using an API route.
* This function sends a POST request to the /api/fetchData route with a GROQ query
* and optional parameters. It returns the fetched data as a Promise of type T.
*
* This function should be used in client-side components where data needs to be
* fetched securely using the server-side token without exposing it in the client code.
*
* @template T - The expected return type of the fetched data.
* @param {string} query - The GROQ query string to be executed on the server.
* @param {Record<string, any>} [params] - Optional parameters to be passed along with the query.
* @returns {Promise<T>} - A promise that resolves to the fetched data of type T.
*
* @throws Will throw an error if the fetch operation fails or if the response is not ok.
*
* @example
* const data = await fetchWithToken<MyDataType>("*[_type == 'myType']", { param1: 'value' });
*/
export const fetchWithToken = async <T>(
query: string,
params?: Record<string, any>
): Promise<T> => {
const response = await fetch("/api/fetchData", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query, params }),
});

if (!response.ok) {
throw new Error("Failed to fetch data");
}

return await response.json();
};
9 changes: 9 additions & 0 deletions studioShared/lib/image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import imageUrlBuilder from "@sanity/image-url";
import { sharedClient } from "./client";
import { SanityImageSource } from "@sanity/image-url/lib/types/types";

const builder = imageUrlBuilder(sharedClient);

export function urlForShared(source: SanityImageSource) {
return builder.image(source);
}
8 changes: 8 additions & 0 deletions studioShared/lib/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as queryStore from "@sanity/react-loader";

import { sharedClient } from "./client";
import { token } from "./token";

queryStore.setServerClient(sharedClient.withConfig({ token }));

export const { loadQuery: loadSharedQuery } = queryStore;
23 changes: 23 additions & 0 deletions studioShared/lib/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Server-Only Token Management

import "server-only";
import { experimental_taintUniqueValue } from "react";

export const token =
process.env.NODE_ENV === "development"
? process.env.SANITY_API_TOKEN_DEV
: process.env.SANITY_API_TOKEN_PROD;

if (!token) {
throw new Error(
`Missing SANITY_API_TOKEN for ${
process.env.NODE_ENV === "development" ? "development" : "production"
} environment`
);
}

experimental_taintUniqueValue(
"Do not pass the sanity API read token to the client.",
process,
token
);
6 changes: 6 additions & 0 deletions studioShared/sanity.cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineCliConfig } from "sanity/cli";

const projectId = process.env.NEXT_PUBLIC_SANITY_SHARED_PROJECT_ID;
const dataset = process.env.NEXT_PUBLIC_SANITY_SHARED_DATASET;

export default defineCliConfig({ api: { projectId, dataset } });
16 changes: 16 additions & 0 deletions studioShared/sanity.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineConfig } from "sanity";
import { structureTool } from "sanity/structure";
import { dataset, projectId } from "./env";
import { schema } from "./schema";

/**
* This configuration is used for the Sanity Studio that’s mounted on the `/app/shared/[[...index]]/page.tsx` route
*/

export default defineConfig({
basePath: "/shared",
projectId,
dataset,
schema,
plugins: [structureTool()],
});
7 changes: 7 additions & 0 deletions studioShared/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type SchemaTypeDefinition } from "sanity";
import blogPosts from "./schemas/documents/blogPosts";
import customerCases from "./schemas/documents/customerCases";

export const schema: { types: SchemaTypeDefinition[] } = {
types: [blogPosts, customerCases],
};
69 changes: 69 additions & 0 deletions studioShared/schemas/documents/blogPosts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { defineField, defineType } from "sanity";
import { format, parseISO } from "date-fns";
import { richText, title } from "studio/schemas/fields/text";
import { titleSlug } from "studio/schemas/schemaTypes/slug";

export const blogPostsID = "blogPosts";

const blogPosts = defineType({
name: blogPostsID,
type: "document",
title: "Blog posts",
fields: [
title,
titleSlug,
defineField({
name: "date",
title: "Publish Date",
description: "Select the date and time when this post will be published.",
type: "datetime",
initialValue: () => new Date().toISOString(),
validation: (Rule) =>
Rule.required().custom((date, context) => {
// Ensure date is not undefined or null
if (!date) return "The publish date is required.";

// Ensure context.document is defined and _createdAt exists
if (!context.document || !context.document._createdAt) {
return "Creation date is missing.";
}

const selectedDate = new Date(date);
const createdAt = new Date(context.document._createdAt as string);
const now = new Date();

// Add a small buffer of 1 second (1000 milliseconds)
const buffer = 1000;

// Check if the selected date is older than today
if (selectedDate.getTime() < now.getTime() - buffer) {
// If the date is older than today, it cannot be older than _createdAt
if (selectedDate.getTime() < createdAt.getTime()) {
return "The publish date cannot be older than the creation date.";
}
}

return true;
}),
}),
defineField({
...richText,
description: "Enter the body content of the post.",
}),
],
preview: {
select: {
title: "basicTitle",
date: "date",
},
prepare({ title, date }) {
const subtitles = [date && format(parseISO(date), "LLL d, yyyy")].filter(
Boolean
);

return { title, subtitle: subtitles.join(" ") };
},
},
});

export default blogPosts;
30 changes: 30 additions & 0 deletions studioShared/schemas/documents/customerCases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineField, defineType } from "sanity";
import { format, parseISO } from "date-fns";
import { richText, title } from "studio/schemas/fields/text";
import { titleSlug } from "studio/schemas/schemaTypes/slug";

export const customerCasesID = "costumerCases";

const customerCases = defineType({
name: customerCasesID,
type: "document",
title: "Costumer Cases",
fields: [
title,
titleSlug,
defineField({
...richText,
description: "Enter the body content of the costumer case.",
}),
],
preview: {
select: {
title: "basicTitle",
},
prepare({ title }) {
return { title, subtitle: "Costumer case" };
},
},
});

export default customerCases;

0 comments on commit d2fdbb2

Please sign in to comment.