mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 16:07:01 +00:00
Merge pull request #7 from kodamera/feature/implement-next-cache-tags
Feature/implement next cache tags
This commit is contained in:
commit
be084be733
@ -1,18 +1,19 @@
|
||||
import CategoryPage from '@/components/pages/category-page';
|
||||
import CategoryPagePreview from '@/components/pages/category-page-preview';
|
||||
import ProductPage from '@/components/pages/product-page';
|
||||
import ProductPagePreview from '@/components/pages/product-page-preview';
|
||||
import SearchPage from '@/components/pages/search-page';
|
||||
import SearchPagePreview from '@/components/pages/search-page-preview';
|
||||
import SinglePage from '@/components/pages/single-page';
|
||||
import SinglePagePreview from '@/components/pages/single-page-preview';
|
||||
import PreviewProvider from '@/components/preview-provider';
|
||||
import getQueryFromSlug from '@/helpers/get-query-from-slug';
|
||||
import { getCachedClient } from 'lib/sanity/sanity.client';
|
||||
import { categoryQuery, pageQuery, productQuery, searchPageQuery } from '@/lib/sanity/queries';
|
||||
import { getCategory, getPage, getProduct, getSearch } from '@/lib/sanity/sanity.fetch';
|
||||
import type { Metadata } from 'next';
|
||||
import { LiveQuery } from 'next-sanity/preview/live-query';
|
||||
import { draftMode } from 'next/headers';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export async function generateMetadata({
|
||||
params
|
||||
}: {
|
||||
@ -20,18 +21,28 @@ export async function generateMetadata({
|
||||
}): Promise<Metadata> {
|
||||
const { slug, locale } = params;
|
||||
|
||||
const { query = '', queryParams } = getQueryFromSlug(slug, locale);
|
||||
const { queryParams, docType } = getQueryFromSlug(slug, locale);
|
||||
|
||||
const page = await getCachedClient()(query, queryParams);
|
||||
let page;
|
||||
|
||||
if (docType === 'page') {
|
||||
page = await getPage(queryParams.slug, queryParams.locale);
|
||||
} else if (docType === 'product') {
|
||||
page = await getProduct(queryParams.slug, queryParams.locale);
|
||||
} else if (docType === 'category') {
|
||||
page = await getCategory(queryParams.slug, queryParams.locale);
|
||||
} else if (docType === 'search') {
|
||||
page = await getSearch(queryParams.slug, queryParams.locale);
|
||||
}
|
||||
|
||||
if (!page) return notFound();
|
||||
|
||||
return {
|
||||
title: `${page.seo?.title || page.title}`,
|
||||
description: page.seo?.description || page.bodySummary,
|
||||
description: page.seo?.description,
|
||||
openGraph: {
|
||||
publishedTime: page.createdAt,
|
||||
modifiedTime: page.updatedAt,
|
||||
// publishedTime: page.createdAt,
|
||||
// modifiedTime: page.updatedAt,
|
||||
type: 'article'
|
||||
}
|
||||
};
|
||||
@ -39,49 +50,70 @@ export async function generateMetadata({
|
||||
|
||||
interface PageParams {
|
||||
params: {
|
||||
locale: string;
|
||||
slug: string[];
|
||||
locale: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default async function Page({ params }: PageParams) {
|
||||
const preview = draftMode().isEnabled ? { token: process.env.SANITY_API_READ_TOKEN } : undefined;
|
||||
|
||||
const { slug, locale } = params;
|
||||
|
||||
const { query = '', queryParams, docType } = getQueryFromSlug(slug, locale);
|
||||
const { queryParams, docType } = getQueryFromSlug(slug, locale);
|
||||
|
||||
let pageData;
|
||||
let data;
|
||||
|
||||
if (docType === 'page') {
|
||||
pageData = await getCachedClient()(query, queryParams);
|
||||
data = await getPage(queryParams.slug, queryParams.locale);
|
||||
} else if (docType === 'product') {
|
||||
pageData = await getCachedClient()(query, queryParams);
|
||||
data = await getProduct(queryParams.slug, queryParams.locale);
|
||||
} else if (docType === 'category') {
|
||||
pageData = await getCachedClient()(query, queryParams);
|
||||
data = await getCategory(queryParams.slug, queryParams.locale);
|
||||
} else if (docType === 'search') {
|
||||
pageData = await getCachedClient()(query, queryParams);
|
||||
} else {
|
||||
return;
|
||||
data = await getSearch(queryParams.slug, queryParams.locale);
|
||||
}
|
||||
|
||||
if (!pageData) return notFound();
|
||||
let PagePreview;
|
||||
|
||||
if (preview && preview.token) {
|
||||
return (
|
||||
<PreviewProvider token={preview.token}>
|
||||
{docType === 'page' && <SinglePagePreview initialData={pageData} params={queryParams} />}
|
||||
{docType === 'search' && <SearchPagePreview initialData={pageData} params={queryParams} />}
|
||||
</PreviewProvider>
|
||||
);
|
||||
if (docType === 'page') {
|
||||
PagePreview = SinglePagePreview;
|
||||
} else if (docType === 'product') {
|
||||
PagePreview = ProductPagePreview;
|
||||
} else if (docType === 'category') {
|
||||
PagePreview = CategoryPagePreview;
|
||||
} else if (docType === 'search') {
|
||||
PagePreview = SearchPagePreview;
|
||||
}
|
||||
|
||||
let query = '';
|
||||
|
||||
if (docType === 'page') {
|
||||
query = pageQuery;
|
||||
} else if (docType === 'product') {
|
||||
query = productQuery;
|
||||
} else if (docType === 'category') {
|
||||
query = categoryQuery;
|
||||
} else if (docType === 'search') {
|
||||
query = searchPageQuery;
|
||||
}
|
||||
|
||||
if (!query && !PagePreview && !data && !draftMode().isEnabled) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{docType === 'page' && <SinglePage data={pageData} />}
|
||||
{docType === 'product' && <ProductPage data={pageData} />}
|
||||
{docType === 'category' && <CategoryPage data={pageData} />}
|
||||
{docType === 'search' && <SearchPage data={pageData} />}
|
||||
</>
|
||||
<LiveQuery
|
||||
enabled={draftMode().isEnabled}
|
||||
query={query}
|
||||
params={{ slug: queryParams.slug, locale: queryParams.locale }}
|
||||
initialData={data}
|
||||
as={PagePreview}
|
||||
>
|
||||
<>
|
||||
{docType === 'page' && <SinglePage data={data} />}
|
||||
{docType === 'product' && <ProductPage data={data} />}
|
||||
{docType === 'category' && <CategoryPage data={data} />}
|
||||
{docType === 'search' && <SearchPage data={data} />}
|
||||
</>
|
||||
</LiveQuery>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
import PreviewProvider from '@/components/preview/preview-provider';
|
||||
import { token } from '@/lib/sanity/sanity.fetch';
|
||||
import { Analytics } from '@vercel/analytics/react';
|
||||
import Footer from 'components/layout/footer/footer';
|
||||
import Header from 'components/layout/header/header';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { Inter } from 'next/font/google';
|
||||
import { draftMode } from 'next/headers';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { ReactNode, Suspense } from 'react';
|
||||
import { supportedLanguages } from '../../../i18n-config';
|
||||
@ -54,7 +57,9 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
const isDraftMode = draftMode().isEnabled;
|
||||
|
||||
const layout = (
|
||||
<html lang={locale} className={inter.variable}>
|
||||
<body className="flex min-h-screen flex-col">
|
||||
<NextIntlClientProvider locale={locale} messages={messages}>
|
||||
@ -70,4 +75,10 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
if (isDraftMode) {
|
||||
return <PreviewProvider token={token!}>{layout}</PreviewProvider>;
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
@ -1,27 +1,26 @@
|
||||
import HomePage from '@/components/pages/home-page';
|
||||
import HomePagePreview from '@/components/pages/home-page-preview';
|
||||
import PreviewProvider from '@/components/preview-provider';
|
||||
import { homePageQuery } from 'lib/sanity/queries';
|
||||
import { getCachedClient } from 'lib/sanity/sanity.client';
|
||||
import { homePageQuery } from '@/lib/sanity/queries';
|
||||
import { getHomePage } from '@/lib/sanity/sanity.fetch';
|
||||
import { Metadata } from 'next';
|
||||
import { LiveQuery } from 'next-sanity/preview/live-query';
|
||||
import { draftMode } from 'next/headers';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
export const runtime = 'edge';
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
export async function generateMetadata({
|
||||
params
|
||||
}: {
|
||||
params: { slug: string; locale: string };
|
||||
params: { locale: string };
|
||||
}): Promise<Metadata> {
|
||||
const homePage = await getCachedClient()(homePageQuery, params);
|
||||
const homePage = await getHomePage(params.locale);
|
||||
|
||||
if (!homePage) return notFound();
|
||||
|
||||
return {
|
||||
title: homePage.seo.title || homePage.title,
|
||||
description: homePage.seo.description || homePage.description
|
||||
title: homePage?.seo?.title || homePage.title,
|
||||
description: homePage?.seo?.description
|
||||
};
|
||||
}
|
||||
interface HomePageParams {
|
||||
@ -31,21 +30,21 @@ interface HomePageParams {
|
||||
}
|
||||
|
||||
export default async function IndexPage({ params }: HomePageParams) {
|
||||
const preview = draftMode().isEnabled ? { token: process.env.SANITY_API_READ_TOKEN } : undefined;
|
||||
const data = await getHomePage(params.locale);
|
||||
|
||||
const data = await getCachedClient(preview)(homePageQuery, params);
|
||||
|
||||
if (!data) return notFound();
|
||||
|
||||
if (preview && preview.token) {
|
||||
return (
|
||||
<PreviewProvider token={preview.token}>
|
||||
<HomePagePreview initialData={data} params={params} />
|
||||
</PreviewProvider>
|
||||
);
|
||||
if (!data && !draftMode().isEnabled) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<HomePage data={data} />
|
||||
<LiveQuery
|
||||
enabled={draftMode().isEnabled}
|
||||
query={homePageQuery}
|
||||
params={{ locale: params.locale }}
|
||||
initialData={data}
|
||||
as={HomePagePreview}
|
||||
>
|
||||
<HomePage data={data} />
|
||||
</LiveQuery>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { previewSecretId } from '@/lib/sanity/sanity.api'
|
||||
import { client } from '@/lib/sanity/sanity.client'
|
||||
import { token } from '@/lib/sanity/sanity.fetch'
|
||||
import { draftMode } from 'next/headers'
|
||||
import { isValidSecret } from 'sanity-plugin-iframe-pane/is-valid-secret'
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url)
|
||||
@ -7,10 +11,26 @@ export async function GET(request: Request) {
|
||||
const type = searchParams.get('type')
|
||||
const locale = searchParams.get('locale')
|
||||
|
||||
// Check the secret and next parameters
|
||||
// This secret should only be known to this route handler and the CMS
|
||||
if (secret !== process.env.SANITY_API_READ_TOKEN) {
|
||||
return new Response('Invalid token', { status: 401 })
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
'The `SANITY_API_READ_TOKEN` environment variable is required.',
|
||||
)
|
||||
}
|
||||
|
||||
if (!secret) {
|
||||
return new Response('Invalid secret', { status: 401 })
|
||||
}
|
||||
|
||||
const authenticatedClient = client.withConfig({ token })
|
||||
|
||||
const validSecret = await isValidSecret(
|
||||
authenticatedClient,
|
||||
previewSecretId,
|
||||
secret,
|
||||
)
|
||||
|
||||
if (!validSecret) {
|
||||
return new Response('Invalid secret', { status: 401 })
|
||||
}
|
||||
|
||||
draftMode().enable()
|
||||
|
64
app/api/revalidate/sanity/route.ts
Normal file
64
app/api/revalidate/sanity/route.ts
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* This code is responsible for revalidating queries as the dataset is updated.
|
||||
*
|
||||
* It is set up to receive a validated GROQ-powered Webhook from Sanity.io:
|
||||
* https://www.sanity.io/docs/webhooks
|
||||
*
|
||||
* 1. Go to the API section of your Sanity project on sanity.io/manage or run `npx sanity hook create`
|
||||
* 2. Click "Create webhook"
|
||||
* 3. Set the URL to https://YOUR_NEXTJS_SITE_URL/api/revalidate
|
||||
* 4. Dataset: Choose desired dataset or leave at default "all datasets"
|
||||
* 5. Trigger on: "Create", "Update", and "Delete"
|
||||
* 6. Filter: Leave empty
|
||||
* 7. Projection: {_type, "slug": slug.current}
|
||||
* 8. Status: Enable webhook
|
||||
* 9. HTTP method: POST
|
||||
* 10. HTTP Headers: Leave empty
|
||||
* 11. API version: v2021-03-25
|
||||
* 12. Include drafts: No
|
||||
* 13. Secret: Set to the same value as SANITY_REVALIDATE_SECRET (create a random secret if you haven't yet, for example by running `Math.random().toString(36).slice(2)` in your console)
|
||||
* 14. Save the cofiguration
|
||||
* 15. Add the secret to Vercel: `npx vercel env add SANITY_REVALIDATE_SECRET`
|
||||
* 16. Redeploy with `npx vercel --prod` to apply the new environment variable
|
||||
*/
|
||||
|
||||
import { revalidateSecret } from '@/lib/sanity/sanity.api'
|
||||
import { parseBody } from 'next-sanity/webhook'
|
||||
import { revalidateTag } from 'next/cache'
|
||||
import { NextResponse, type NextRequest } from 'next/server'
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const { body, isValidSignature } = await parseBody<{
|
||||
_type: string
|
||||
slug?: string | undefined
|
||||
language: string | undefined
|
||||
}>(req, revalidateSecret)
|
||||
if (!isValidSignature) {
|
||||
const message = 'Invalid signature'
|
||||
return new Response(message, { status: 401 })
|
||||
}
|
||||
|
||||
if (!body?._type) {
|
||||
return new Response('Bad Request', { status: 400 })
|
||||
}
|
||||
|
||||
revalidateTag(body._type)
|
||||
|
||||
if (body.slug) {
|
||||
revalidateTag(`${body._type}:${body.slug}`)
|
||||
} else {
|
||||
revalidateTag(`${body._type}`)
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
revalidated: true,
|
||||
now: Date.now(),
|
||||
body,
|
||||
})
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
return new Response(err.message, { status: 500 })
|
||||
}
|
||||
}
|
@ -36,39 +36,12 @@
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
/* Code for Firefox */
|
||||
color: #ffffff;
|
||||
@ -82,7 +55,7 @@
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply h-full bg-white font-sans text-high-contrast;
|
||||
@apply h-full bg-background text-foreground;
|
||||
|
||||
box-sizing: border-box;
|
||||
touch-action: manipulation;
|
||||
@ -91,9 +64,6 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overscroll-behavior-x: none;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import Text from '@/components/ui/text';
|
||||
import { footerMenusQuery } from '@/lib/sanity/queries';
|
||||
import { getCachedClient } from '@/lib/sanity/sanity.client';
|
||||
import Text from '@/components/ui/text/text';
|
||||
import { getFooterMenus } from '@/lib/sanity/sanity.fetch';
|
||||
import LocaleSwitcher from 'components/ui/locale-switcher/locale-switcher';
|
||||
import Logo from 'components/ui/logo/logo';
|
||||
import Link from 'next/link';
|
||||
@ -15,7 +14,7 @@ export default async function Footer({ locale }: FooterProps) {
|
||||
locale: locale
|
||||
};
|
||||
|
||||
const footerMenus = await getCachedClient()(footerMenusQuery, params);
|
||||
const footerMenus = await getFooterMenus(params.locale);
|
||||
|
||||
return (
|
||||
<footer className="border-t border-ui-border bg-app">
|
||||
@ -27,12 +26,14 @@ export default async function Footer({ locale }: FooterProps) {
|
||||
<LocaleSwitcher />
|
||||
</div>
|
||||
|
||||
{footerMenus.length > 0 && (
|
||||
{footerMenus && (
|
||||
<div className="grid w-full grid-cols-2 gap-4 p-4 lg:grid-cols-4 lg:gap-8 lg:px-8 lg:py-6 2xl:px-16 2xl:py-8">
|
||||
{/* @ts-ignore */}
|
||||
{footerMenus.map((menu: object | any, index: number) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
<Text variant="label">{menu.title}</Text>
|
||||
|
||||
<ul className="mt-4 flex flex-col space-y-2" aria-label={menu.title}>
|
||||
{menu.menu.links.map((link: object | any, index: number) => {
|
||||
return (
|
||||
|
@ -3,6 +3,10 @@
|
||||
import Link from 'next-intl/link';
|
||||
|
||||
export default function DesktopMenu({ items }: { items: [] }) {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex gap-6">
|
||||
{items.map((item: { title: string; slug: string }, i: number) => {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { categoriesQuery } from '@/lib/sanity/queries';
|
||||
import { getCachedClient } from '@/lib/sanity/sanity.client';
|
||||
import Cart from 'components/cart';
|
||||
import OpenCart from 'components/cart/open-cart';
|
||||
import Logo from 'components/ui/logo/logo';
|
||||
|
||||
import { getMainMenu } from '@/lib/sanity/sanity.fetch';
|
||||
import Link from 'next/link';
|
||||
import { Suspense } from 'react';
|
||||
import DesktopMenu from './desktop-menu/desktop-menu';
|
||||
@ -21,7 +20,7 @@ export default async function Header({ locale }: HeaderProps) {
|
||||
const params = {
|
||||
locale: locale
|
||||
};
|
||||
const mainMenu = await getCachedClient()(categoriesQuery, params);
|
||||
const mainMenu = await getMainMenu(params.locale);
|
||||
|
||||
return (
|
||||
<HeaderRoot>
|
||||
@ -29,6 +28,7 @@ export default async function Header({ locale }: HeaderProps) {
|
||||
<div className="relative flex w-full items-center justify-between px-4 py-2 lg:px-8 2xl:px-16">
|
||||
<div className="-translate-x-2 transform md:hidden">
|
||||
<Suspense fallback={<OpenMobileMenu />}>
|
||||
{/* @ts-ignore */}
|
||||
<MobileMenuModal items={mainMenu} />
|
||||
</Suspense>
|
||||
</div>
|
||||
@ -45,6 +45,7 @@ export default async function Header({ locale }: HeaderProps) {
|
||||
|
||||
<div className="absolute left-1/2 top-1/2 hidden -translate-x-1/2 -translate-y-1/2 transform md:flex">
|
||||
<Suspense>
|
||||
{/* @ts-ignore */}
|
||||
<DesktopMenu items={mainMenu} />
|
||||
</Suspense>
|
||||
</div>
|
||||
|
@ -6,12 +6,16 @@ import { useState } from 'react';
|
||||
import OpenMobileMenu from './open-mobile-menu';
|
||||
|
||||
interface MobileMenuModalProps {
|
||||
items: [];
|
||||
items: [] | null;
|
||||
}
|
||||
|
||||
export default function MobileMenuModal({ items }: MobileMenuModalProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sheet open={isOpen} onOpenChange={() => setIsOpen(!isOpen)}>
|
||||
|
@ -7,7 +7,7 @@ interface HeroProps {
|
||||
text?: string;
|
||||
label?: string;
|
||||
title: string;
|
||||
image: object | any;
|
||||
image?: { asset?: any };
|
||||
color?: string;
|
||||
overlay?: boolean;
|
||||
link: {
|
||||
@ -38,14 +38,13 @@ const Hero = ({ variant, title, text, label, image, link, color, overlay }: Hero
|
||||
{image && (
|
||||
<SanityImage
|
||||
image={image}
|
||||
alt={image.alt}
|
||||
priority={true}
|
||||
className="absolute inset-0 z-10 h-full w-full object-cover"
|
||||
sizes="100vw"
|
||||
size="100vw"
|
||||
fill
|
||||
/>
|
||||
)}
|
||||
{overlay && <div className="absolute inset-0 z-10 h-full w-full bg-black/70" />}
|
||||
{overlay && <div className="absolute inset-0 z-10 h-full w-full bg-black/60" />}
|
||||
<div
|
||||
className={`${
|
||||
color === 'dark' ? 'text-high-contrast' : 'text-white'
|
||||
|
@ -1,27 +1,23 @@
|
||||
'use client'
|
||||
|
||||
import DynamicContentManager from 'components/layout/dynamic-content-manager'
|
||||
import DynamicContentManager from 'components/layout/dynamic-content-manager';
|
||||
|
||||
interface ReusableSectionProps {
|
||||
section: {
|
||||
existingSection: {
|
||||
section: {
|
||||
sectionType: []
|
||||
}
|
||||
}
|
||||
sectionType: [];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const ReusableSection = ({ section }: ReusableSectionProps) => {
|
||||
const data = section.existingSection.section.sectionType;
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const ReusableSection = ({ section }:ReusableSectionProps) => {
|
||||
const data = section.existingSection.section.sectionType;
|
||||
return <DynamicContentManager content={data} />;
|
||||
};
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<DynamicContentManager content={data} />
|
||||
)
|
||||
}
|
||||
|
||||
export default ReusableSection;
|
||||
export default ReusableSection;
|
||||
|
@ -3,9 +3,9 @@
|
||||
import Text from 'components/ui/text';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { Carousel, CarouselItem } from '@/components/modules/carousel/carousel';
|
||||
import CategoryCard from '@/components/ui/category-card/category-card';
|
||||
import ProductCard from '@/components/ui/product-card/product-card';
|
||||
import { Carousel, CarouselItem } from '@/components/modules/carousel/carousel';
|
||||
|
||||
interface SliderProps {
|
||||
products: [] | any;
|
||||
|
@ -1,5 +1,3 @@
|
||||
'use client';
|
||||
|
||||
import SanityImage from '../../ui/sanity-image';
|
||||
|
||||
interface USPSectionProps {
|
||||
@ -24,7 +22,7 @@ const USPSection = ({ usps }: USPSectionProps) => {
|
||||
alt={usp.name || 'USP image'}
|
||||
width={96}
|
||||
height={96}
|
||||
sizes="96px"
|
||||
size="96px"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
24
components/pages/category-page-preview.tsx
Normal file
24
components/pages/category-page-preview.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import PreviewBanner from '../ui/preview-banner/preview-banner';
|
||||
import { CategoryPageParams } from './category-page';
|
||||
|
||||
const CategoryPage = dynamic(() => import('./category-page'));
|
||||
|
||||
export default function CategoryPagePreview({ data }: CategoryPageParams) {
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="text-center">
|
||||
Please start editing your Product document to see the preview!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<CategoryPage data={data} />
|
||||
<PreviewBanner title={data?.title ? data.title : ''} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -2,9 +2,9 @@ import Search from '@/components/search/search';
|
||||
import SearchResult from '@/components/search/search-result';
|
||||
import Text from '@/components/ui/text/text';
|
||||
|
||||
interface CategoryPageParams {
|
||||
export type CategoryPageParams = {
|
||||
data: object | any;
|
||||
}
|
||||
};
|
||||
|
||||
export default function CategoryPage({ data }: CategoryPageParams) {
|
||||
const category = data;
|
||||
|
@ -1,24 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import { homePageQuery } from '@/lib/sanity/queries';
|
||||
import { useLiveQuery } from '@sanity/preview-kit';
|
||||
import dynamic from 'next/dynamic';
|
||||
import PreviewBanner from '../ui/preview-banner';
|
||||
import HomePage from './home-page';
|
||||
import type { IndexPageParams } from './home-page';
|
||||
|
||||
interface HomePagePreviewParams {
|
||||
initialData: [];
|
||||
params: {
|
||||
locale: string;
|
||||
};
|
||||
}
|
||||
const HomePage = dynamic(() => import('./home-page'));
|
||||
|
||||
export default function HomePagePreview({ initialData, params }: HomePagePreviewParams) {
|
||||
const [data] = useLiveQuery(initialData, homePageQuery, params);
|
||||
export default function HomePagePreview({ data }: IndexPageParams) {
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="text-center">Please start editing your Home document to see the preview!</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<HomePage data={data} />;{/* @ts-ignore */}
|
||||
<PreviewBanner title={data?.title} type={data?._type} />
|
||||
<HomePage data={data} />
|
||||
<PreviewBanner title={data?.title ? data.title : ''} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import DynamicContentManager from '@/components/layout/dynamic-content-manager/dynamic-content-manager';
|
||||
import type { HomePagePayload } from '@/lib/sanity/sanity.types';
|
||||
|
||||
interface IndexPageParams {
|
||||
data: object | any;
|
||||
}
|
||||
export type IndexPageParams = {
|
||||
data: HomePagePayload | null;
|
||||
};
|
||||
|
||||
export default function HomePage({ data }: IndexPageParams) {
|
||||
return (
|
||||
|
24
components/pages/product-page-preview.tsx
Normal file
24
components/pages/product-page-preview.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import PreviewBanner from '../ui/preview-banner/preview-banner';
|
||||
import type { ProductPageParams } from './product-page';
|
||||
|
||||
const ProductPage = dynamic(() => import('./product-page'));
|
||||
|
||||
export default function ProductPagePreview({ data }: ProductPageParams) {
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="text-center">
|
||||
Please start editing your Product document to see the preview!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProductPage data={data} />
|
||||
<PreviewBanner title={data?.title ? data.title : ''} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import ProductView from '@/components/product/product-view';
|
||||
interface ProductPageParams {
|
||||
export type ProductPageParams = {
|
||||
data: object | any;
|
||||
}
|
||||
};
|
||||
|
||||
export default function ProductPage({ data }: ProductPageParams) {
|
||||
const product = data;
|
||||
|
@ -1,26 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import PreviewBanner from '@/components/ui/preview-banner';
|
||||
import { searchPageQuery } from '@/lib/sanity/queries';
|
||||
import { useLiveQuery } from '@sanity/preview-kit';
|
||||
import SearchPage from './search-page';
|
||||
import dynamic from 'next/dynamic';
|
||||
import PreviewBanner from '../ui/preview-banner';
|
||||
import type { SearchPageParams } from './search-page';
|
||||
|
||||
interface SearchPagePreviewParams {
|
||||
initialData: [];
|
||||
params: {
|
||||
locale: string;
|
||||
slug: string;
|
||||
};
|
||||
}
|
||||
const SearchPage = dynamic(() => import('./search-page'));
|
||||
|
||||
export default function SearchPagePreview({ initialData, params }: SearchPagePreviewParams) {
|
||||
const [data] = useLiveQuery(initialData, searchPageQuery, params);
|
||||
export default function SearchPagePreview({ data }: SearchPageParams) {
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="text-center">
|
||||
Please start editing your Search page document to see the preview!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchPage data={data && data} />
|
||||
{/* @ts-ignore */}
|
||||
<PreviewBanner title={data?.title} type={data?._type} />
|
||||
<SearchPage data={data} />
|
||||
<PreviewBanner title={data?.title ? data.title : ''} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ import Search from '@/components/search/search';
|
||||
import SearchResult from '@/components/search/search-result';
|
||||
import Text from '@/components/ui/text/text';
|
||||
|
||||
interface SearchPageParams {
|
||||
export type SearchPageParams = {
|
||||
data: object | any;
|
||||
}
|
||||
};
|
||||
|
||||
export default function SearchPage({ data }: SearchPageParams) {
|
||||
return (
|
||||
|
@ -1,26 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import PreviewBanner from '@/components/ui/preview-banner';
|
||||
import { pageQuery } from '@/lib/sanity/queries';
|
||||
import { useLiveQuery } from '@sanity/preview-kit';
|
||||
import SinglePage from './single-page';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { SinglePageParams } from './single-page';
|
||||
|
||||
interface SinglePagePreviewParams {
|
||||
initialData: [];
|
||||
params: {
|
||||
locale: string;
|
||||
slug: string;
|
||||
};
|
||||
}
|
||||
const SinglePage = dynamic(() => import('./single-page'));
|
||||
const PreviewBanner = dynamic(() => import('../ui/preview-banner/preview-banner'));
|
||||
|
||||
export default function SinglePagePreview({ initialData, params }: SinglePagePreviewParams) {
|
||||
const [data] = useLiveQuery(initialData, pageQuery, params);
|
||||
export default function SinglePagePreview({ data }: SinglePageParams) {
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="text-center">Please start editing your Page document to see the preview!</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SinglePage data={data && data} />
|
||||
{/* @ts-ignore */}
|
||||
<PreviewBanner title={data?.title} type={data?._type} />
|
||||
<SinglePage data={data} />
|
||||
<PreviewBanner title={data?.title ? data.title : ''} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
import DynamicContentManager from '@/components/layout/dynamic-content-manager/dynamic-content-manager';
|
||||
|
||||
interface SinglePageParams {
|
||||
export type SinglePageParams = {
|
||||
data: object | any;
|
||||
}
|
||||
};
|
||||
|
||||
export default function SinglePage({ data }: SinglePageParams) {
|
||||
return (
|
||||
<>
|
||||
<DynamicContentManager content={data?.content} />;
|
||||
<DynamicContentManager content={data?.content} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { getClient } from '@/lib/sanity/sanity.client';
|
||||
import { LiveQueryProvider } from '@sanity/preview-kit';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export default function PreviewProvider({
|
||||
children,
|
||||
token
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
token: string;
|
||||
}) {
|
||||
const client = useMemo(() => getClient({ token }), [token]);
|
||||
return <LiveQueryProvider client={client}>{children}</LiveQueryProvider>;
|
||||
}
|
25
components/preview/preview-provider.tsx
Normal file
25
components/preview/preview-provider.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
'use client';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import { suspend } from 'suspend-react';
|
||||
|
||||
const LiveQueryProvider = dynamic(() => import('next-sanity/preview'));
|
||||
|
||||
// suspend-react cache is global, so we use a unique key to avoid collisions
|
||||
const UniqueKey = Symbol('@/lib/sanity/sanity.client');
|
||||
|
||||
export default function PreviewProvider({
|
||||
children,
|
||||
token
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
token?: string;
|
||||
}) {
|
||||
const { client } = suspend(() => import('@/lib/sanity/sanity.client'), [UniqueKey]);
|
||||
if (!token) throw new TypeError('Missing token');
|
||||
return (
|
||||
<LiveQueryProvider client={client} token={token} logger={console}>
|
||||
{children}
|
||||
</LiveQueryProvider>
|
||||
);
|
||||
}
|
@ -49,7 +49,7 @@ const Card: FC<CardProps> = ({ className, title, image, link, text, imageFormat
|
||||
className={imageClasses}
|
||||
image={image}
|
||||
alt={image.alt || ''}
|
||||
sizes="(max-width: 1024px) 50vw, 90vw"
|
||||
size="(max-width: 1024px) 50vw, 20vw"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@ -71,7 +71,7 @@ const Card: FC<CardProps> = ({ className, title, image, link, text, imageFormat
|
||||
className={imageClasses}
|
||||
image={image}
|
||||
alt={image.alt || ''}
|
||||
sizes="(max-width: 1024px) 50vw, 20vw"
|
||||
size="(max-width: 1024px) 50vw, 20vw"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -20,9 +20,9 @@ const CategoryCard: FC<Props> = ({ category, className }) => {
|
||||
<SanityImage
|
||||
image={category.image}
|
||||
alt={category.name || 'Category Image'}
|
||||
width={300}
|
||||
height={400}
|
||||
sizes="(max-width: 1024px) 50vw, 25vw"
|
||||
width={400}
|
||||
height={600}
|
||||
size="(max-width: 1024px) 50vw, 25vw"
|
||||
/>
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-high-contrast px-6 py-3 font-medium text-white md:px-10 md:py-5">
|
||||
{category.title}
|
||||
|
@ -4,7 +4,7 @@ import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface PreviewBannerProps {
|
||||
title: string;
|
||||
title?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,14 @@ const ProductCard: FC<Props> = ({ product, className, variant = 'default' }) =>
|
||||
>
|
||||
{variant === 'default' && (
|
||||
<div className={'relative flex h-full w-full flex-col justify-center'}>
|
||||
<div className="relative h-full w-full overflow-hidden">
|
||||
<div className="relative aspect-square h-full w-full overflow-hidden">
|
||||
{product?.images && (
|
||||
<SanityImage
|
||||
image={product?.images[0]}
|
||||
width={400}
|
||||
height={400}
|
||||
alt={product.title || 'Product Image'}
|
||||
sizes="(max-width: 1024px) 50vw, 20vw"
|
||||
size="(max-width: 1024px) 50vw, 20vw"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,78 +1,118 @@
|
||||
'use client';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { urlForImage } from 'lib/sanity/sanity.image';
|
||||
import { cn } from 'lib/utils';
|
||||
import Image from 'next/image';
|
||||
|
||||
interface SanityImageProps {
|
||||
image: object | any;
|
||||
alt: string;
|
||||
alt?: string;
|
||||
priority?: boolean;
|
||||
width?: number;
|
||||
height?: number;
|
||||
quality?: number;
|
||||
sizes?: string;
|
||||
size?: string;
|
||||
className?: string;
|
||||
fill?: boolean;
|
||||
}
|
||||
|
||||
const placeholderImg = '/product-img-placeholder.svg';
|
||||
// const placeholderImg = '/product-img-placeholder.svg';
|
||||
|
||||
export default function SanityImage(props: SanityImageProps) {
|
||||
const {
|
||||
image: source,
|
||||
priority = false,
|
||||
quality = 75,
|
||||
alt = '',
|
||||
height = 1080,
|
||||
width = 1080,
|
||||
sizes = '100vw',
|
||||
className,
|
||||
fill = false
|
||||
} = props;
|
||||
export default function SanityImage({
|
||||
image,
|
||||
alt = '',
|
||||
width = 3500,
|
||||
height = 2000,
|
||||
size = '100vw',
|
||||
fill = false,
|
||||
priority = false,
|
||||
className
|
||||
}: SanityImageProps) {
|
||||
const imageUrl = image && urlForImage(image)?.height(height).width(width).fit('crop').url();
|
||||
|
||||
const rootClassName = cn('w-full h-auto', className);
|
||||
|
||||
const image = source?.asset?._rev ? (
|
||||
<>
|
||||
{fill ? (
|
||||
return (
|
||||
<div className={cn('w-full overflow-hidden bg-subtle', className)}>
|
||||
{fill && imageUrl && (
|
||||
<Image
|
||||
className={`${rootClassName}`}
|
||||
placeholder="blur"
|
||||
fill
|
||||
fill={fill}
|
||||
className="absolute h-full w-full object-cover"
|
||||
alt={alt}
|
||||
src={urlForImage(source).quality(quality).url()}
|
||||
sizes={sizes}
|
||||
priority={priority}
|
||||
blurDataURL={source.asset.metadata.lqip}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className={`${rootClassName}`}
|
||||
sizes={size}
|
||||
src={imageUrl}
|
||||
placeholder="blur"
|
||||
width={width}
|
||||
height={height}
|
||||
alt={alt}
|
||||
src={urlForImage(source).width(width).height(height).quality(quality).url()}
|
||||
sizes={sizes}
|
||||
priority={priority}
|
||||
blurDataURL={source.asset.metadata.lqip}
|
||||
blurDataURL={image.asset.metadata.lqip}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Image
|
||||
className={`${rootClassName}`}
|
||||
width={width}
|
||||
height={height}
|
||||
alt={alt}
|
||||
src={placeholderImg}
|
||||
sizes={sizes}
|
||||
priority={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
return image;
|
||||
{imageUrl && (
|
||||
<Image
|
||||
className="absolute h-full w-full bg-subtle object-cover"
|
||||
alt={alt ? alt : ''}
|
||||
width={width}
|
||||
height={height}
|
||||
sizes={size}
|
||||
src={imageUrl}
|
||||
placeholder="blur"
|
||||
priority={priority}
|
||||
blurDataURL={image.asset.metadata.lqip}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// export default function SanityImage(props: SanityImageProps) {
|
||||
// const {
|
||||
// image: source,
|
||||
// priority = false,
|
||||
// alt = '',
|
||||
// height = 1080,
|
||||
// width = 1080,
|
||||
// sizes = '100vw',
|
||||
// className,
|
||||
// fill = false
|
||||
// } = props;
|
||||
|
||||
// const rootClassName = cn('w-full h-auto', className);
|
||||
|
||||
// const image = source?.asset ? (
|
||||
// <>
|
||||
// {fill ? (
|
||||
// <Image
|
||||
// className={`${rootClassName}`}
|
||||
// placeholder="blur"
|
||||
// fill
|
||||
// alt={alt}
|
||||
// src={urlForImage(source).url()}
|
||||
// sizes={sizes}
|
||||
// priority={priority}
|
||||
// blurDataURL={source.asset.metadata.lqip}
|
||||
// />
|
||||
// ) : (
|
||||
// <Image
|
||||
// className={`${rootClassName}`}
|
||||
// placeholder="blur"
|
||||
// width={width}
|
||||
// height={height}
|
||||
// alt={alt}
|
||||
// src={urlForImage(source).width(width).height(height).url()}
|
||||
// sizes={sizes}
|
||||
// priority={priority}
|
||||
// blurDataURL={source.asset.metadata.lqip}
|
||||
// />
|
||||
// )}
|
||||
// </>
|
||||
// ) : (
|
||||
// <>
|
||||
// <Image
|
||||
// className={`${rootClassName}`}
|
||||
// width={width}
|
||||
// height={height}
|
||||
// alt={alt}
|
||||
// src={placeholderImg}
|
||||
// sizes={sizes}
|
||||
// priority={false}
|
||||
// />
|
||||
// </>
|
||||
// );
|
||||
|
||||
// return image;
|
||||
// }
|
||||
|
@ -24,7 +24,7 @@ const SheetOverlay = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-foreground/70 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
'bg-foreground/70 fixed inset-0 z-50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@ -34,7 +34,7 @@ const SheetOverlay = React.forwardRef<
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
||||
|
||||
const sheetVariants = cva(
|
||||
'fixed z-50 gap-4 bg-background p-4 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 lg:p-6',
|
||||
'fixed z-50 gap-4 bg-white p-4 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 lg:p-6',
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
@ -64,7 +64,7 @@ const SheetContent = React.forwardRef<
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary md:right-6 md:top-6">
|
||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-blue-500 data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none md:right-6 md:top-6">
|
||||
<XMarkIcon className="h-6 w-6" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
@ -92,7 +92,7 @@ const SheetTitle = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold text-foreground', className)}
|
||||
className={cn('text-foreground text-lg font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
@ -104,7 +104,7 @@ const SheetDescription = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
@ -19,7 +19,6 @@ export const PAGE_REFERENCES = [
|
||||
{type: 'home'},
|
||||
{type: 'page'},
|
||||
{type: 'product'},
|
||||
{type: 'productVariant'},
|
||||
]
|
||||
|
||||
// Objects to include in page building arrays.
|
||||
@ -34,15 +33,4 @@ export const COMPONENT_REFERENCES = [
|
||||
|
||||
// API version to use when using the Sanity client within the studio
|
||||
// https://www.sanity.io/help/studio-client-specify-api-version
|
||||
export const SANITY_API_VERSION = '2022-10-25'
|
||||
|
||||
// Your Shopify store ID.
|
||||
// This is your unique store URL (e.g. 'my-store-name.myshopify.com').
|
||||
// Set this to enable helper links in document status banners and shortcut links on products and collections.
|
||||
export const STORM_STORE_ID = ''
|
||||
|
||||
// Project preview URLs
|
||||
export const localStorefrontUrl = 'http://localhost:3000';
|
||||
export const localStorefrontPreviewUrl = 'http://localhost:3000/api/preview';
|
||||
export const publicStorefrontUrl = 'https://km-storefront.vercel.app';
|
||||
export const publicStorefrontPreviewUrl = 'https://km-storefront.vercel.app/api/preview';
|
||||
export const SANITY_API_VERSION = '2022-10-25'
|
@ -1,9 +1,8 @@
|
||||
import {ListItemBuilder} from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
import { iframeOptions } from '@/sanity.config'
|
||||
import { EyeOpenIcon, MasterDetailIcon } from '@sanity/icons'
|
||||
import Iframe from 'sanity-plugin-iframe-pane'
|
||||
import {SanityDocument} from 'sanity'
|
||||
import {EyeOpenIcon, MasterDetailIcon} from '@sanity/icons'
|
||||
import getPreviewUrl from '../utils/get-preview-url'
|
||||
import { ListItemBuilder } from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
|
||||
export default defineStructure<ListItemBuilder>((S) =>
|
||||
S.listItem()
|
||||
@ -16,16 +15,8 @@ export default defineStructure<ListItemBuilder>((S) =>
|
||||
.schemaType("category")
|
||||
.id(id)
|
||||
.views([
|
||||
S.view
|
||||
.form()
|
||||
.icon(MasterDetailIcon),
|
||||
S.view
|
||||
.component(Iframe)
|
||||
.icon(EyeOpenIcon)
|
||||
.options({
|
||||
url: (doc: SanityDocument) => getPreviewUrl(doc),
|
||||
})
|
||||
.title('Preview')
|
||||
S.view.form().icon(MasterDetailIcon),
|
||||
S.view.component(Iframe).icon(EyeOpenIcon).options(iframeOptions).title('Preview')
|
||||
])
|
||||
)
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { iframeOptions } from '@/sanity.config'
|
||||
import { EyeOpenIcon, MasterDetailIcon } from '@sanity/icons'
|
||||
import { SanityDocument } from 'sanity'
|
||||
import Iframe from 'sanity-plugin-iframe-pane'
|
||||
import { ListItemBuilder } from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
import getPreviewUrl from '../utils/get-preview-url'
|
||||
|
||||
export default defineStructure<ListItemBuilder>((S) =>
|
||||
S.listItem()
|
||||
@ -18,16 +17,8 @@ export default defineStructure<ListItemBuilder>((S) =>
|
||||
.schemaType("home")
|
||||
.id(id)
|
||||
.views([
|
||||
S.view
|
||||
.form()
|
||||
.icon(MasterDetailIcon),
|
||||
S.view
|
||||
.component(Iframe)
|
||||
.icon(EyeOpenIcon)
|
||||
.options({
|
||||
url: (doc: SanityDocument) => getPreviewUrl(doc),
|
||||
})
|
||||
.title('Preview')
|
||||
S.view.form().icon(MasterDetailIcon),
|
||||
S.view.component(Iframe).icon(EyeOpenIcon).options(iframeOptions).title('Preview')
|
||||
])
|
||||
)
|
||||
)
|
||||
|
@ -59,16 +59,16 @@ export const structure: StructureResolver = (S, context) =>
|
||||
home(S, context),
|
||||
pages(S, context),
|
||||
S.divider(),
|
||||
products(S, context),
|
||||
categories(S, context),
|
||||
products(S, context),
|
||||
S.divider(),
|
||||
blurbs(S, context),
|
||||
usps(S, context),
|
||||
sections(S, context),
|
||||
usps(S, context),
|
||||
S.divider(),
|
||||
settings(S, context),
|
||||
search(S, context),
|
||||
navigation(S, context),
|
||||
search(S, context),
|
||||
settings(S, context),
|
||||
S.divider(),
|
||||
...S.documentTypeListItems().filter(hiddenDocTypes),
|
||||
S.divider(),
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { iframeOptions } from '@/sanity.config'
|
||||
import { DocumentsIcon, EyeOpenIcon, MasterDetailIcon } from '@sanity/icons'
|
||||
import { SanityDocument } from 'sanity'
|
||||
import Iframe from 'sanity-plugin-iframe-pane'
|
||||
import { ListItemBuilder } from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
import getPreviewUrl from '../utils/get-preview-url'
|
||||
|
||||
export default defineStructure<ListItemBuilder>((S) =>
|
||||
S.listItem()
|
||||
@ -17,16 +16,8 @@ export default defineStructure<ListItemBuilder>((S) =>
|
||||
.schemaType("page")
|
||||
.id(id)
|
||||
.views([
|
||||
S.view
|
||||
.form()
|
||||
.icon(MasterDetailIcon),
|
||||
S.view
|
||||
.component(Iframe)
|
||||
.icon(EyeOpenIcon)
|
||||
.options({
|
||||
url: (doc: SanityDocument) => getPreviewUrl(doc),
|
||||
})
|
||||
.title('Preview')
|
||||
S.view.form().icon(MasterDetailIcon),
|
||||
S.view.component(Iframe).icon(EyeOpenIcon).options(iframeOptions).title('Preview')
|
||||
])
|
||||
)
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import {ListItemBuilder} from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
import { iframeOptions } from '@/sanity.config'
|
||||
import { EyeOpenIcon, MasterDetailIcon } from '@sanity/icons'
|
||||
import Iframe from 'sanity-plugin-iframe-pane'
|
||||
import {SanityDocument} from 'sanity'
|
||||
import {EyeOpenIcon, MasterDetailIcon} from '@sanity/icons'
|
||||
import getPreviewUrl from '../utils/get-preview-url'
|
||||
import { ListItemBuilder } from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
|
||||
export default defineStructure<ListItemBuilder>((S) =>
|
||||
S.listItem()
|
||||
@ -16,58 +15,10 @@ export default defineStructure<ListItemBuilder>((S) =>
|
||||
.schemaType("product")
|
||||
.id(id)
|
||||
.views([
|
||||
S.view
|
||||
.form()
|
||||
.icon(MasterDetailIcon),
|
||||
S.view
|
||||
.component(Iframe)
|
||||
.icon(EyeOpenIcon)
|
||||
.options({
|
||||
url: (doc: SanityDocument) => getPreviewUrl(doc),
|
||||
})
|
||||
.title('Preview')
|
||||
S.view.form().icon(MasterDetailIcon),
|
||||
S.view.component(Iframe).icon(EyeOpenIcon).options(iframeOptions).title('Preview')
|
||||
])
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
// @TODO - FIX THIS STRUCTURE.
|
||||
// export default defineStructure<ListItemBuilder>((S) =>
|
||||
// S.listItem()
|
||||
// .title('Products')
|
||||
// .schemaType('product')
|
||||
// .child(
|
||||
// S.documentTypeList('product')
|
||||
// // .defaultLayout('detail')
|
||||
// .child(async (id) =>
|
||||
// S.list()
|
||||
// .title('Product')
|
||||
// .items([
|
||||
// // Details
|
||||
// S.listItem()
|
||||
// .title('Details')
|
||||
// .icon(InfoOutlineIcon)
|
||||
// .child(S.document().schemaType('product').documentId(id)),
|
||||
// // Product variants
|
||||
// S.listItem()
|
||||
// .title('Variants')
|
||||
// .schemaType('productVariant')
|
||||
// .child(
|
||||
// S.documentList()
|
||||
// .title('Variants')
|
||||
// .schemaType('productVariant')
|
||||
// .filter(
|
||||
// `
|
||||
// _type == "productVariant"
|
||||
// && store.productId == $productId
|
||||
// `
|
||||
// )
|
||||
// .params({
|
||||
// productId: Number(id.replace('shopifyProduct-', '')),
|
||||
// })
|
||||
// ),
|
||||
// ])
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
)
|
@ -1,9 +1,8 @@
|
||||
import { iframeOptions } from '@/sanity.config'
|
||||
import { EyeOpenIcon, MasterDetailIcon } from '@sanity/icons'
|
||||
import { SanityDocument } from 'sanity'
|
||||
import Iframe from 'sanity-plugin-iframe-pane'
|
||||
import { ListItemBuilder } from 'sanity/desk'
|
||||
import defineStructure from '../utils/define-structure'
|
||||
import getPreviewUrl from '../utils/get-preview-url'
|
||||
|
||||
export default defineStructure<ListItemBuilder>((S) =>
|
||||
S.listItem()
|
||||
@ -18,16 +17,8 @@ export default defineStructure<ListItemBuilder>((S) =>
|
||||
.schemaType("search")
|
||||
.id(id)
|
||||
.views([
|
||||
S.view
|
||||
.form()
|
||||
.icon(MasterDetailIcon),
|
||||
S.view
|
||||
.component(Iframe)
|
||||
.icon(EyeOpenIcon)
|
||||
.options({
|
||||
url: (doc: SanityDocument) => getPreviewUrl(doc),
|
||||
})
|
||||
.title('Preview')
|
||||
S.view.form().icon(MasterDetailIcon),
|
||||
S.view.component(Iframe).icon(EyeOpenIcon).options(iframeOptions).title('Preview')
|
||||
])
|
||||
)
|
||||
)
|
||||
|
@ -269,7 +269,7 @@ export const categoryQuery = `*[_type == "category" && slug.current == $slug &&
|
||||
}`;
|
||||
|
||||
// Categories query
|
||||
export const categoriesQuery = `*[_type == "category" && language == $locale] | order(title asc) {
|
||||
export const mainMenuQuery = `*[_type == "category" && language == $locale] | order(title asc) {
|
||||
_type,
|
||||
title,
|
||||
"slug": slug.current,
|
||||
|
33
lib/sanity/sanity.api.ts
Normal file
33
lib/sanity/sanity.api.ts
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* As this file is reused in several other files, try to keep it lean and small.
|
||||
* Importing other npm packages here could lead to needlessly increasing the client bundle size, or end up in a server-only function that don't need it.
|
||||
*/
|
||||
|
||||
export const dataset = assertValue(
|
||||
process.env.NEXT_PUBLIC_SANITY_DATASET,
|
||||
'Missing environment variable: NEXT_PUBLIC_SANITY_DATASET',
|
||||
)
|
||||
|
||||
export const projectId = assertValue(
|
||||
process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
|
||||
'Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID',
|
||||
)
|
||||
|
||||
// see https://www.sanity.io/docs/api-versioning for how versioning works
|
||||
export const apiVersion =
|
||||
process.env.NEXT_PUBLIC_SANITY_API_VERSION || '2023-06-21'
|
||||
|
||||
// This is the document id used for the preview secret that's stored in your dataset.
|
||||
// The secret protects against unauthorized access to your draft content and have a lifetime of 60 minutes, to protect against bruteforcing.
|
||||
export const previewSecretId: `${string}.${string}` = 'preview.secret'
|
||||
|
||||
// See the app/api/revalidate/route.ts for how this is used
|
||||
export const revalidateSecret = process.env.SANITY_REVALIDATE_SECRET
|
||||
|
||||
function assertValue<T>(v: T | undefined, errorMessage: string): T {
|
||||
if (v === undefined) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
@ -1,31 +1,16 @@
|
||||
import type { SanityClient } from "@sanity/client";
|
||||
import { createClient } from "@sanity/client";
|
||||
import { cache } from "react";
|
||||
import { createClient } from 'next-sanity'
|
||||
import {
|
||||
apiVersion,
|
||||
dataset,
|
||||
projectId,
|
||||
revalidateSecret,
|
||||
} from './sanity.api'
|
||||
|
||||
export function getClient(preview?: {token?: string}): SanityClient {
|
||||
const client = createClient({
|
||||
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
|
||||
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
|
||||
apiVersion: process.env.NEXT_PUBLIC_SANITY_API_VERSION,
|
||||
useCdn: true,
|
||||
perspective: 'published',
|
||||
})
|
||||
if (preview) {
|
||||
if (!preview.token) {
|
||||
throw new Error('You must provide a token to preview drafts')
|
||||
}
|
||||
return client.withConfig({
|
||||
token: preview.token,
|
||||
useCdn: false,
|
||||
ignoreBrowserTokenWarning: true,
|
||||
perspective: 'previewDrafts',
|
||||
})
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
export const getCachedClient = (preview?: {token?: string}) => {
|
||||
const client = getClient(preview);
|
||||
|
||||
return cache(client.fetch.bind(client));
|
||||
};
|
||||
export const client = createClient({
|
||||
projectId,
|
||||
dataset,
|
||||
apiVersion,
|
||||
// If webhook revalidation is setup we want the freshest content, if not then it's best to use the speedy CDN
|
||||
useCdn: revalidateSecret ? false : true,
|
||||
perspective: 'published',
|
||||
})
|
109
lib/sanity/sanity.fetch.ts
Normal file
109
lib/sanity/sanity.fetch.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import 'server-only'
|
||||
|
||||
import type { QueryParams } from '@sanity/client'
|
||||
import { client } from './sanity.client'
|
||||
|
||||
import { draftMode } from 'next/headers'
|
||||
|
||||
import { revalidateSecret } from './sanity.api'
|
||||
|
||||
import { categoryQuery, footerMenusQuery, homePageQuery, mainMenuQuery, pageQuery, productQuery, searchPageQuery } from './queries'
|
||||
|
||||
import { CategoryPayload, FooterMenusPayload, HomePagePayload, MainMenuPayload, PagePayload, ProductPayload, SearchPayload } from './sanity.types'
|
||||
|
||||
export const token = process.env.SANITY_API_READ_TOKEN
|
||||
|
||||
const DEFAULT_PARAMS = {} as QueryParams
|
||||
const DEFAULT_TAGS = [] as string[]
|
||||
|
||||
export async function sanityFetch<QueryResponse>({
|
||||
query,
|
||||
params = DEFAULT_PARAMS,
|
||||
tags = DEFAULT_TAGS,
|
||||
}: {
|
||||
query: string
|
||||
params?: QueryParams
|
||||
tags: string[]
|
||||
}): Promise<QueryResponse> {
|
||||
const isDraftMode = draftMode().isEnabled
|
||||
if (isDraftMode && !token) {
|
||||
throw new Error(
|
||||
'The `SANITY_API_READ_TOKEN` environment variable is required.',
|
||||
)
|
||||
}
|
||||
|
||||
// @TODO this won't be necessary after https://github.com/sanity-io/client/pull/299 lands
|
||||
const sanityClient =
|
||||
client.config().useCdn && isDraftMode
|
||||
? client.withConfig({ useCdn: false })
|
||||
: client
|
||||
return sanityClient.fetch<QueryResponse>(query, params, {
|
||||
// We only cache if there's a revalidation webhook setup
|
||||
cache: revalidateSecret ? 'force-cache' : 'no-store',
|
||||
...(isDraftMode && {
|
||||
cache: undefined,
|
||||
token: token,
|
||||
perspective: 'previewDrafts',
|
||||
}),
|
||||
next: {
|
||||
...(isDraftMode && { revalidate: 30 }),
|
||||
tags,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function getHomePage(locale: string) {
|
||||
return sanityFetch<HomePagePayload | null>({
|
||||
query: homePageQuery,
|
||||
params: { locale },
|
||||
tags: ['home', 'product', 'category', 'page', 'menu'],
|
||||
})
|
||||
}
|
||||
|
||||
export function getPage(slug: string, locale: string) {
|
||||
return sanityFetch<PagePayload | null>({
|
||||
query: pageQuery,
|
||||
params: { slug, locale },
|
||||
tags: ['page'],
|
||||
})
|
||||
}
|
||||
|
||||
export function getProduct(slug: string, locale: string) {
|
||||
return sanityFetch<ProductPayload | null>({
|
||||
query: productQuery,
|
||||
params: { slug, locale },
|
||||
tags: ['product'],
|
||||
})
|
||||
}
|
||||
|
||||
export function getCategory(slug: string, locale: string) {
|
||||
return sanityFetch<CategoryPayload | null>({
|
||||
query: categoryQuery,
|
||||
params: { slug, locale },
|
||||
tags: ['category'],
|
||||
})
|
||||
}
|
||||
|
||||
export function getSearch(slug: string, locale: string) {
|
||||
return sanityFetch<SearchPayload | null>({
|
||||
query: searchPageQuery,
|
||||
params: { slug, locale },
|
||||
tags: ['search'],
|
||||
})
|
||||
}
|
||||
|
||||
export function getMainMenu(locale: string) {
|
||||
return sanityFetch<MainMenuPayload | null>({
|
||||
query: mainMenuQuery,
|
||||
params: { locale },
|
||||
tags: ['menu'],
|
||||
})
|
||||
}
|
||||
|
||||
export function getFooterMenus(locale: string) {
|
||||
return sanityFetch<FooterMenusPayload | null>({
|
||||
query: footerMenusQuery,
|
||||
params: { locale },
|
||||
tags: ['menu'],
|
||||
})
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
import createImageUrlBuilder from '@sanity/image-url'
|
||||
import { getClient } from './sanity.client'
|
||||
import { dataset, projectId } from './sanity.api'
|
||||
|
||||
export const imageBuilder = createImageUrlBuilder(getClient())
|
||||
const imageBuilder = createImageUrlBuilder({
|
||||
projectId: projectId || '',
|
||||
dataset: dataset || '',
|
||||
})
|
||||
|
||||
export const urlForImage = (source: any) =>
|
||||
imageBuilder.image(source).auto('format').fit('crop')
|
||||
|
79
lib/sanity/sanity.types.ts
Normal file
79
lib/sanity/sanity.types.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import type { Image } from 'sanity'
|
||||
|
||||
export interface MenuItem {
|
||||
_type: string
|
||||
slug?: string
|
||||
title?: string
|
||||
}
|
||||
|
||||
export interface HomePagePayload {
|
||||
content?: []
|
||||
title?: string
|
||||
_type?: string
|
||||
seo?: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
image: Image
|
||||
}
|
||||
}
|
||||
|
||||
export interface PagePayload {
|
||||
content?: []
|
||||
title?: string
|
||||
_type?: string
|
||||
slug?: string
|
||||
seo?: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
image: Image
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProductPayload {
|
||||
title?: string
|
||||
name?: string
|
||||
description?: string
|
||||
images?: Image[]
|
||||
currencyCode?: string
|
||||
_type?: string
|
||||
slug?: string
|
||||
seo?: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
image: Image
|
||||
}
|
||||
}
|
||||
|
||||
export interface CategoryPayload {
|
||||
title?: string
|
||||
_type?: string
|
||||
slug?: string
|
||||
seo?: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
image: Image
|
||||
}
|
||||
}
|
||||
|
||||
export interface SearchPayload {
|
||||
title?: string
|
||||
_type?: string
|
||||
slug?: string
|
||||
seo?: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
image: Image
|
||||
}
|
||||
}
|
||||
|
||||
export interface MainMenuPayload {
|
||||
title?: string
|
||||
_type?: string
|
||||
items?: MenuItem[]
|
||||
}
|
||||
|
||||
export interface FooterMenusPayload {
|
||||
title?: string
|
||||
_type?: string
|
||||
menu?: MenuItem[]
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import {CommentIcon} from '@sanity/icons'
|
||||
import {defineField} from 'sanity'
|
||||
import {languages} from '../../languages'
|
||||
import {validateImage} from '../../utils/validation'
|
||||
import { CommentIcon } from '@sanity/icons';
|
||||
import { defineField } from 'sanity';
|
||||
import { languages } from '../../languages';
|
||||
import { validateImage } from '../../utils/validation';
|
||||
|
||||
export default defineField({
|
||||
name: 'blurb',
|
||||
@ -13,7 +13,7 @@ export default defineField({
|
||||
name: 'language',
|
||||
type: 'string',
|
||||
readOnly: true,
|
||||
description: 'Language of this document.',
|
||||
description: 'Language of this document.'
|
||||
// hidden: true,
|
||||
}),
|
||||
// Title
|
||||
@ -22,14 +22,14 @@ export default defineField({
|
||||
title: 'Title',
|
||||
type: 'string',
|
||||
description: 'What do you want to convey?',
|
||||
validation: (Rule) => Rule.required(),
|
||||
validation: (Rule) => Rule.required()
|
||||
}),
|
||||
// Image
|
||||
defineField({
|
||||
name: 'image',
|
||||
title: 'Image',
|
||||
type: 'mainImage',
|
||||
validation: (Rule) => validateImage(Rule, true),
|
||||
validation: (Rule) => validateImage(Rule, true)
|
||||
}),
|
||||
// Text
|
||||
defineField({
|
||||
@ -37,7 +37,7 @@ export default defineField({
|
||||
title: 'Text',
|
||||
type: 'text',
|
||||
description: 'Small text displayed below title.',
|
||||
rows: 5,
|
||||
rows: 5
|
||||
}),
|
||||
// Link
|
||||
{
|
||||
@ -54,69 +54,69 @@ export default defineField({
|
||||
validation: (Rule) => Rule.required(),
|
||||
options: {
|
||||
list: ['internal', 'external'],
|
||||
layout: 'radio',
|
||||
},
|
||||
layout: 'radio'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'internalLink',
|
||||
type: 'linkInternal',
|
||||
title: 'Internal link',
|
||||
hidden: ({parent}) => parent?.linkType !== 'internal',
|
||||
hidden: ({ parent }) => parent?.linkType !== 'internal',
|
||||
options: {
|
||||
collapsible: false,
|
||||
collapsible: false
|
||||
},
|
||||
validation: (Rule) =>
|
||||
Rule.custom((value: any, context: any) => {
|
||||
if (context.parent.linkType == 'internal') {
|
||||
const currentLink = value && value.reference
|
||||
const currentLink = value && value.reference;
|
||||
if (!currentLink) {
|
||||
return 'Reference is required'
|
||||
return 'Reference is required';
|
||||
}
|
||||
}
|
||||
return true
|
||||
}),
|
||||
return true;
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'externalLink',
|
||||
type: 'linkExternal',
|
||||
title: 'External link',
|
||||
hidden: ({parent}) => parent?.linkType !== 'external',
|
||||
hidden: ({ parent }) => parent?.linkType !== 'external',
|
||||
options: {
|
||||
collapsible: false,
|
||||
collapsible: false
|
||||
},
|
||||
validation: (Rule) =>
|
||||
Rule.custom((value: any, context: any) => {
|
||||
if (context.parent.linkType == 'external') {
|
||||
const currentTitle = value?.title
|
||||
const currentUrl = value?.url
|
||||
const currentTitle = value?.title;
|
||||
const currentUrl = value?.url;
|
||||
if (!currentTitle) {
|
||||
return 'Title is required'
|
||||
return 'Title is required';
|
||||
} else if (!currentUrl) {
|
||||
return 'URL is required'
|
||||
return 'URL is required';
|
||||
}
|
||||
}
|
||||
return true
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
return true;
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
image: 'image',
|
||||
language: 'language',
|
||||
language: 'language'
|
||||
},
|
||||
prepare(selection) {
|
||||
const {image, title, language} = selection
|
||||
const { image, title, language } = selection;
|
||||
|
||||
const currentLang = languages.find((lang) => lang.id === language)
|
||||
const currentLang = languages.find((lang) => lang.id === language);
|
||||
|
||||
return {
|
||||
media: image,
|
||||
title,
|
||||
subtitle: `${currentLang ? currentLang.title : ''}`,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
subtitle: `${currentLang ? currentLang.title : ''}`
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,30 +0,0 @@
|
||||
import {CopyIcon} from '@sanity/icons'
|
||||
import {defineField, defineType} from 'sanity'
|
||||
|
||||
export default defineType({
|
||||
name: 'productVariant',
|
||||
title: 'Product variant',
|
||||
type: 'document',
|
||||
icon: CopyIcon,
|
||||
fields: [
|
||||
// Title
|
||||
defineField({
|
||||
title: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
description: 'Product variant title/name.'
|
||||
}),
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {title} = selection
|
||||
|
||||
return {
|
||||
title,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
@ -17,7 +17,6 @@ import category from './documents/category'
|
||||
import footerMenu from './documents/footerMenu'
|
||||
import page from './documents/page'
|
||||
import product from './documents/product'
|
||||
import productVariant from './documents/productVariant'
|
||||
import section from './documents/section'
|
||||
import usp from './documents/usp'
|
||||
|
||||
@ -25,7 +24,6 @@ const documents = [
|
||||
category,
|
||||
page,
|
||||
product,
|
||||
productVariant,
|
||||
blurb,
|
||||
section,
|
||||
usp,
|
||||
|
@ -1,24 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import { isDev, SanityDocument } from 'sanity'
|
||||
import { localStorefrontPreviewUrl, publicStorefrontPreviewUrl } from '../constants'
|
||||
|
||||
const SANITY_STUDIO_API_READ_TOKEN = "skYG2HXNga8uxSL7rFIreJEnP0SdVjCZ2nzB8rUHD4wRWxXPGceXTuR5vCVBP99mWZ9ULhghmpUyX7EtzDmJusSk6Gwvdr3nLAsdWI9ZktIWvSWUNpHbu0Xfrrt0UUaktrLglk7ToABvjXlaPHLpOIR3dnjl4MGByutPmyra0b5t20kgDrmF"
|
||||
// Customise this function to show the correct URL based on the current document
|
||||
export default async function getPreviewUrl(doc: SanityDocument) {
|
||||
|
||||
if (isDev) {
|
||||
// Home page have no slugs.
|
||||
if (!doc.slug) {
|
||||
return `${localStorefrontPreviewUrl}?locale=${doc.language}&type=${doc._type}&secret=${SANITY_STUDIO_API_READ_TOKEN}`
|
||||
}
|
||||
|
||||
return `${localStorefrontPreviewUrl}?slug=${doc.slug.current}&locale=${doc.language}&type=${doc._type}&secret=${SANITY_STUDIO_API_READ_TOKEN}`
|
||||
} else {
|
||||
// Home page have no slugs.
|
||||
if (!doc.slug) {
|
||||
return `${publicStorefrontPreviewUrl}?locale=${doc.language}&type=${doc._type}&secret=${SANITY_STUDIO_API_READ_TOKEN}`
|
||||
}
|
||||
|
||||
return `${publicStorefrontPreviewUrl}?slug=${doc.slug.current}&locale=${doc.language}&type=${doc._type}&secret=${SANITY_STUDIO_API_READ_TOKEN}`
|
||||
}
|
||||
}
|
@ -1,35 +1,34 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
enabled: process.env.BUNDLE_ANALYZE === 'true',
|
||||
})
|
||||
enabled: process.env.BUNDLE_ANALYZE === 'true'
|
||||
});
|
||||
|
||||
module.exports = withBundleAnalyzer(
|
||||
{
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/en/search',
|
||||
destination: '/en/sok',
|
||||
locale: false
|
||||
},
|
||||
]
|
||||
},
|
||||
eslint: {
|
||||
// Disabling on production builds because we're running checks on PRs via GitHub Actions.
|
||||
ignoreDuringBuilds: true
|
||||
},
|
||||
experimental: {
|
||||
scrollRestoration: true,
|
||||
serverActions: true,
|
||||
},
|
||||
images: {
|
||||
formats: ['image/avif', 'image/webp'],
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'cdn.sanity.io',
|
||||
},
|
||||
],
|
||||
},
|
||||
module.exports = withBundleAnalyzer({
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/en/search',
|
||||
destination: '/en/sok',
|
||||
locale: false
|
||||
}
|
||||
];
|
||||
},
|
||||
eslint: {
|
||||
// Disabling on production builds because we're running checks on PRs via GitHub Actions.
|
||||
ignoreDuringBuilds: true
|
||||
},
|
||||
experimental: {
|
||||
scrollRestoration: true,
|
||||
serverActions: true,
|
||||
logging: 'verbose'
|
||||
},
|
||||
images: {
|
||||
formats: ['image/avif', 'image/webp'],
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'cdn.sanity.io'
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
43
package.json
43
package.json
@ -23,46 +23,47 @@
|
||||
"@portabletext/react": "^3.0.4",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||
"@radix-ui/react-navigation-menu": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.5",
|
||||
"@radix-ui/react-navigation-menu": "^1.1.3",
|
||||
"@sanity/client": "^6.4.4",
|
||||
"@sanity/document-internationalization": "^2.0.1",
|
||||
"@sanity/icons": "^2.4.1",
|
||||
"@sanity/image-url": "^1.0.2",
|
||||
"@sanity/preview-kit": "^2.4.9",
|
||||
"@sanity/types": "^3.11.1",
|
||||
"@sanity/ui": "^1.3.3",
|
||||
"@sanity/types": "^3.15.0",
|
||||
"@sanity/ui": "^1.7.4",
|
||||
"@sanity/vision": "^3.0.0",
|
||||
"@sanity/webhook": "^2.0.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@vercel/analytics": "^1.0.2",
|
||||
"@vercel/og": "^0.1.0",
|
||||
"algoliasearch": "^4.19.1",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"clsx": "^1.2.1",
|
||||
"framer-motion": "^8.5.5",
|
||||
"is-empty-iterable": "^3.0.0",
|
||||
"next": "13.4.13",
|
||||
"next": "13.4.19",
|
||||
"next-intl": "2.19.1",
|
||||
"next-sanity": "^5.3.0",
|
||||
"next-sanity": "^5.4.6",
|
||||
"react": "18.2.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-glider": "^4.0.2",
|
||||
"react-instantsearch": "^7.0.1",
|
||||
"sanity": "^3.11.1",
|
||||
"sanity-plugin-iframe-pane": "^2.3.0",
|
||||
"sanity": "^3.15.0",
|
||||
"sanity-plugin-iframe-pane": "^2.5.5",
|
||||
"sanity-plugin-media": "^2.0.4",
|
||||
"sharp": "^0.32.1",
|
||||
"sharp": "^0.32.4",
|
||||
"slug": "^8.2.2",
|
||||
"slugify": "^1.6.5",
|
||||
"styled-components": "^5.3.10",
|
||||
"tailwind-merge": "^1.12.0",
|
||||
"tailwindcss-animate": "^1.0.5"
|
||||
"styled-components": "^5.3.11",
|
||||
"suspend-react": "^0.1.3",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss-animate": "^1.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^13.4.13",
|
||||
"@playwright/test": "^1.34.1",
|
||||
"@playwright/test": "^1.36.2",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@types/negotiator": "^0.6.1",
|
||||
"@types/node": "18.13.0",
|
||||
@ -72,15 +73,15 @@
|
||||
"@vercel/git-hooks": "^1.0.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-next": "^13.4.3",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint": "^8.46.0",
|
||||
"eslint-config-next": "^13.4.13",
|
||||
"eslint-config-prettier": "^8.10.0",
|
||||
"eslint-plugin-unicorn": "^45.0.2",
|
||||
"lint-staged": "^13.2.2",
|
||||
"postcss": "^8.4.23",
|
||||
"lint-staged": "^13.2.3",
|
||||
"postcss": "^8.4.27",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-tailwindcss": "^0.2.8",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^5.1.3"
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
||||
|
99
plugins/settings.tsx
Normal file
99
plugins/settings.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* This plugin contains all the logic for setting up the singletons
|
||||
*/
|
||||
|
||||
import { type DocumentDefinition } from 'sanity';
|
||||
import { Iframe } from 'sanity-plugin-iframe-pane';
|
||||
import { ListItemBuilder, type StructureResolver } from 'sanity/desk';
|
||||
|
||||
import { iframeOptions, PREVIEWABLE_DOCUMENT_TYPES } from '../sanity.config';
|
||||
|
||||
const hiddenDocTypes = (listItem: ListItemBuilder) => {
|
||||
const id = listItem.getId();
|
||||
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ![
|
||||
// 'category',
|
||||
// 'home',
|
||||
'media.tag',
|
||||
// 'page',
|
||||
// 'product',
|
||||
// 'settings',
|
||||
// 'blurb',
|
||||
// 'section',
|
||||
// 'usp',
|
||||
'navigation',
|
||||
'footerMenu',
|
||||
'utilityMenu'
|
||||
].includes(id);
|
||||
};
|
||||
|
||||
export const singletonPlugin = (types: string[]) => {
|
||||
return {
|
||||
name: 'singletonPlugin',
|
||||
document: {
|
||||
// Hide 'Singletons (such as Home)' from new document options
|
||||
// https://user-images.githubusercontent.com/81981/195728798-e0c6cf7e-d442-4e58-af3a-8cd99d7fcc28.png
|
||||
newDocumentOptions: (prev, { creationContext }) => {
|
||||
if (creationContext.type === 'global') {
|
||||
return prev.filter((templateItem) => !types.includes(templateItem.templateId));
|
||||
}
|
||||
|
||||
return prev;
|
||||
},
|
||||
// Removes the "duplicate" action on the Singletons (such as Home)
|
||||
actions: (prev, { schemaType }) => {
|
||||
if (types.includes(schemaType)) {
|
||||
return prev.filter(({ action }) => action !== 'duplicate');
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// The StructureResolver is how we're changing the DeskTool structure to linking to document (named Singleton)
|
||||
// like how "Home" is handled.
|
||||
export const pageStructure = (typeDefArray: DocumentDefinition[]): StructureResolver => {
|
||||
return (S) => {
|
||||
// Goes through all of the singletons that were provided and translates them into something the
|
||||
// Desktool can understand
|
||||
const singletonItems = typeDefArray.map((typeDef) => {
|
||||
return S.listItem()
|
||||
.title(typeDef.title)
|
||||
.icon(typeDef.icon)
|
||||
.child(
|
||||
S.documentList()
|
||||
.title(typeDef.name)
|
||||
.filter(`_type == "${typeDef.name}"`)
|
||||
.child((id = typeDef.name) =>
|
||||
S.document()
|
||||
.schemaType(typeDef.name)
|
||||
.id(id)
|
||||
.views([
|
||||
S.view.form(),
|
||||
// Preview
|
||||
...(PREVIEWABLE_DOCUMENT_TYPES.includes(typeDef.name as any)
|
||||
? [S.view.component(Iframe).options(iframeOptions).title('Preview')]
|
||||
: [])
|
||||
])
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
// The default root list items (except custom ones)
|
||||
const defaultListItems = S.documentTypeListItems()
|
||||
.filter((listItem) => !typeDefArray.find((singleton) => singleton.name === listItem.getId()))
|
||||
.filter(hiddenDocTypes);
|
||||
|
||||
return S.list()
|
||||
.title('Content')
|
||||
.items([...singletonItems, S.divider(), ...defaultListItems]);
|
||||
};
|
||||
};
|
251
pnpm-lock.yaml
generated
251
pnpm-lock.yaml
generated
@ -18,10 +18,10 @@ dependencies:
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.19)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-dropdown-menu':
|
||||
specifier: ^2.0.4
|
||||
specifier: ^2.0.5
|
||||
version: 2.0.5(@types/react-dom@18.2.7)(@types/react@18.2.19)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-navigation-menu':
|
||||
specifier: ^1.1.2
|
||||
specifier: ^1.1.3
|
||||
version: 1.1.3(@types/react-dom@18.2.7)(@types/react@18.2.19)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@sanity/client':
|
||||
specifier: ^6.4.4
|
||||
@ -39,14 +39,14 @@ dependencies:
|
||||
specifier: ^2.4.9
|
||||
version: 2.4.9(@sanity/client@6.4.4)(react@18.2.0)
|
||||
'@sanity/types':
|
||||
specifier: ^3.11.1
|
||||
specifier: ^3.15.0
|
||||
version: 3.15.0
|
||||
'@sanity/ui':
|
||||
specifier: ^1.3.3
|
||||
specifier: ^1.7.4
|
||||
version: 1.7.4(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@5.3.11)
|
||||
'@sanity/vision':
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0(@babel/runtime@7.22.10)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.3)(@sanity/client@6.4.4)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@5.3.11)
|
||||
version: 3.0.0(@babel/runtime@7.22.10)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.4)(@sanity/client@6.4.4)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@5.3.11)
|
||||
'@sanity/webhook':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
@ -63,7 +63,7 @@ dependencies:
|
||||
specifier: ^4.19.1
|
||||
version: 4.19.1
|
||||
class-variance-authority:
|
||||
specifier: ^0.6.0
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1
|
||||
clsx:
|
||||
specifier: ^1.2.1
|
||||
@ -75,14 +75,14 @@ dependencies:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
next:
|
||||
specifier: 13.4.13
|
||||
version: 13.4.13(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: 13.4.19
|
||||
version: 13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
|
||||
next-intl:
|
||||
specifier: 2.19.1
|
||||
version: 2.19.1(next@13.4.13)(react@18.2.0)
|
||||
version: 2.19.1(next@13.4.19)(react@18.2.0)
|
||||
next-sanity:
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0(@sanity/client@6.4.4)(@sanity/icons@2.4.1)(@sanity/types@3.15.0)(@sanity/ui@1.7.4)(@types/styled-components@5.1.26)(next@13.4.13)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11)
|
||||
specifier: ^5.4.6
|
||||
version: 5.4.6(@sanity/client@6.4.4)(@sanity/icons@2.4.1)(@sanity/types@3.15.0)(@sanity/ui@1.7.4)(next@13.4.19)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11)
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
@ -99,16 +99,16 @@ dependencies:
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1(algoliasearch@4.19.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
sanity:
|
||||
specifier: ^3.11.1
|
||||
specifier: ^3.15.0
|
||||
version: 3.15.0(@types/node@18.13.0)(@types/react@18.2.19)(react-dom@18.2.0)(react@18.2.0)(styled-components@5.3.11)
|
||||
sanity-plugin-iframe-pane:
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11)
|
||||
specifier: ^2.5.5
|
||||
version: 2.5.5(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11)
|
||||
sanity-plugin-media:
|
||||
specifier: ^2.0.4
|
||||
version: 2.0.4(@sanity/color@2.2.5)(@sanity/icons@2.4.1)(@types/react@18.2.19)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11)
|
||||
sharp:
|
||||
specifier: ^0.32.1
|
||||
specifier: ^0.32.4
|
||||
version: 0.32.4
|
||||
slug:
|
||||
specifier: ^8.2.2
|
||||
@ -117,13 +117,16 @@ dependencies:
|
||||
specifier: ^1.6.5
|
||||
version: 1.6.5
|
||||
styled-components:
|
||||
specifier: ^5.3.10
|
||||
specifier: ^5.3.11
|
||||
version: 5.3.11(@babel/core@7.22.10)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)
|
||||
suspend-react:
|
||||
specifier: ^0.1.3
|
||||
version: 0.1.3(react@18.2.0)
|
||||
tailwind-merge:
|
||||
specifier: ^1.12.0
|
||||
specifier: ^1.14.0
|
||||
version: 1.14.0
|
||||
tailwindcss-animate:
|
||||
specifier: ^1.0.5
|
||||
specifier: ^1.0.6
|
||||
version: 1.0.6(tailwindcss@3.3.3)
|
||||
|
||||
devDependencies:
|
||||
@ -131,7 +134,7 @@ devDependencies:
|
||||
specifier: ^13.4.13
|
||||
version: 13.4.13
|
||||
'@playwright/test':
|
||||
specifier: ^1.34.1
|
||||
specifier: ^1.36.2
|
||||
version: 1.36.2
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.9
|
||||
@ -161,22 +164,22 @@ devDependencies:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.3
|
||||
eslint:
|
||||
specifier: ^8.41.0
|
||||
specifier: ^8.46.0
|
||||
version: 8.46.0
|
||||
eslint-config-next:
|
||||
specifier: ^13.4.3
|
||||
specifier: ^13.4.13
|
||||
version: 13.4.13(eslint@8.46.0)(typescript@5.1.6)
|
||||
eslint-config-prettier:
|
||||
specifier: ^8.8.0
|
||||
specifier: ^8.10.0
|
||||
version: 8.10.0(eslint@8.46.0)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^45.0.2
|
||||
version: 45.0.2(eslint@8.46.0)
|
||||
lint-staged:
|
||||
specifier: ^13.2.2
|
||||
specifier: ^13.2.3
|
||||
version: 13.2.3
|
||||
postcss:
|
||||
specifier: ^8.4.23
|
||||
specifier: ^8.4.27
|
||||
version: 8.4.27
|
||||
prettier:
|
||||
specifier: ^2.8.8
|
||||
@ -185,10 +188,10 @@ devDependencies:
|
||||
specifier: ^0.2.8
|
||||
version: 0.2.8(prettier@2.8.8)
|
||||
tailwindcss:
|
||||
specifier: ^3.3.2
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
typescript:
|
||||
specifier: ^5.1.3
|
||||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
|
||||
packages:
|
||||
@ -565,6 +568,20 @@ packages:
|
||||
'@lezer/common': 1.0.3
|
||||
dev: false
|
||||
|
||||
/@codemirror/autocomplete@6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==}
|
||||
peerDependencies:
|
||||
'@codemirror/language': ^6.0.0
|
||||
'@codemirror/state': ^6.0.0
|
||||
'@codemirror/view': ^6.0.0
|
||||
'@lezer/common': ^1.0.0
|
||||
dependencies:
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
dev: false
|
||||
|
||||
/@codemirror/commands@6.2.4:
|
||||
resolution: {integrity: sha512-42lmDqVH0ttfilLShReLXsDfASKLXzfyC36bzwcqzox9PlHulMcsUOfHXNo2X2aFMVNUoQ7j+d4q5bnfseYoOA==}
|
||||
dependencies:
|
||||
@ -597,6 +614,17 @@ packages:
|
||||
style-mod: 4.0.3
|
||||
dev: false
|
||||
|
||||
/@codemirror/language@6.9.0:
|
||||
resolution: {integrity: sha512-nFu311/0ne/qGuGCL3oKuktBgzVOaxCHZPZv1tLSZkNjPYxxvkjSbzno3MlErG2tgw1Yw1yF8BxMCegeMXqpiw==}
|
||||
dependencies:
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/common': 1.0.4
|
||||
'@lezer/highlight': 1.1.6
|
||||
'@lezer/lr': 1.3.10
|
||||
style-mod: 4.1.0
|
||||
dev: false
|
||||
|
||||
/@codemirror/lint@6.4.0:
|
||||
resolution: {integrity: sha512-6VZ44Ysh/Zn07xrGkdtNfmHCbGSHZzFBdzWi0pbd7chAQ/iUcpLGX99NYRZTa7Ugqg4kEHCqiHhcZnH0gLIgSg==}
|
||||
dependencies:
|
||||
@ -620,7 +648,7 @@ packages:
|
||||
/@codemirror/theme-one-dark@6.1.2:
|
||||
resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.8.0
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/state': 6.2.1
|
||||
'@codemirror/view': 6.16.0
|
||||
'@lezer/highlight': 1.1.6
|
||||
@ -1206,6 +1234,10 @@ packages:
|
||||
resolution: {integrity: sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA==}
|
||||
dev: false
|
||||
|
||||
/@lezer/common@1.0.4:
|
||||
resolution: {integrity: sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg==}
|
||||
dev: false
|
||||
|
||||
/@lezer/highlight@1.1.6:
|
||||
resolution: {integrity: sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==}
|
||||
dependencies:
|
||||
@ -1219,6 +1251,12 @@ packages:
|
||||
'@lezer/lr': 1.3.9
|
||||
dev: false
|
||||
|
||||
/@lezer/lr@1.3.10:
|
||||
resolution: {integrity: sha512-BZfVvf7Re5BIwJHlZXbJn9L8lus5EonxQghyn+ih8Wl36XMFBPTXC0KM0IdUtj9w/diPHsKlXVgL+AlX2jYJ0Q==}
|
||||
dependencies:
|
||||
'@lezer/common': 1.0.4
|
||||
dev: false
|
||||
|
||||
/@lezer/lr@1.3.9:
|
||||
resolution: {integrity: sha512-XPz6dzuTHlnsbA5M2DZgjflNQ+9Hi5Swhic0RULdp3oOs3rh6bqGZolosVqN/fQIT8uNiepzINJDnS39oweTHQ==}
|
||||
dependencies:
|
||||
@ -1281,8 +1319,8 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@next/env@13.4.13:
|
||||
resolution: {integrity: sha512-fwz2QgVg08v7ZL7KmbQBLF2PubR/6zQdKBgmHEl3BCyWTEDsAQEijjw2gbFhI1tcKfLdOOJUXntz5vZ4S0Polg==}
|
||||
/@next/env@13.4.19:
|
||||
resolution: {integrity: sha512-FsAT5x0jF2kkhNkKkukhsyYOrRqtSxrEhfliniIq0bwWbuXLgyt3Gv0Ml+b91XwjwArmuP7NxCiGd++GGKdNMQ==}
|
||||
dev: false
|
||||
|
||||
/@next/eslint-plugin-next@13.4.13:
|
||||
@ -1291,8 +1329,8 @@ packages:
|
||||
glob: 7.1.7
|
||||
dev: true
|
||||
|
||||
/@next/swc-darwin-arm64@13.4.13:
|
||||
resolution: {integrity: sha512-ZptVhHjzUuivnXMNCJ6lER33HN7lC+rZ01z+PM10Ows21NHFYMvGhi5iXkGtBDk6VmtzsbqnAjnx4Oz5um0FjA==}
|
||||
/@next/swc-darwin-arm64@13.4.19:
|
||||
resolution: {integrity: sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
@ -1300,8 +1338,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-x64@13.4.13:
|
||||
resolution: {integrity: sha512-t9nTiWCLApw8W4G1kqJyYP7y6/7lyal3PftmRturIxAIBlZss9wrtVN8nci50StDHmIlIDxfguYIEGVr9DbFTg==}
|
||||
/@next/swc-darwin-x64@13.4.19:
|
||||
resolution: {integrity: sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
@ -1309,8 +1347,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-gnu@13.4.13:
|
||||
resolution: {integrity: sha512-xEHUqC8eqR5DHe8SOmMnDU1K3ggrJ28uIKltrQAwqFSSSmzjnN/XMocZkcVhuncuxYrpbri0iMQstRyRVdQVWg==}
|
||||
/@next/swc-linux-arm64-gnu@13.4.19:
|
||||
resolution: {integrity: sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@ -1318,8 +1356,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-musl@13.4.13:
|
||||
resolution: {integrity: sha512-sNf3MnLAm8rquSSAoeD9nVcdaDeRYOeey4stOWOyWIgbBDtP+C93amSgH/LPTDoUV7gNiU6f+ghepTjTjRgIUQ==}
|
||||
/@next/swc-linux-arm64-musl@13.4.19:
|
||||
resolution: {integrity: sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@ -1327,8 +1365,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-gnu@13.4.13:
|
||||
resolution: {integrity: sha512-WhcRaJJSHyx9OWmKjjz+OWHumiPZWRqmM/09Bt7Up4UqUJFFhGExeztR4trtv3rflvULatu9IH/nTV8fUUgaMA==}
|
||||
/@next/swc-linux-x64-gnu@13.4.19:
|
||||
resolution: {integrity: sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@ -1336,8 +1374,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-musl@13.4.13:
|
||||
resolution: {integrity: sha512-+Y4LLhOWWZQIDKVwr2R17lq2KSN0F1c30QVgGIWfnjjHpH8nrIWHEndhqYU+iFuW8It78CiJjQKTw4f51HD7jA==}
|
||||
/@next/swc-linux-x64-musl@13.4.19:
|
||||
resolution: {integrity: sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@ -1345,8 +1383,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-arm64-msvc@13.4.13:
|
||||
resolution: {integrity: sha512-rWurdOR20uxjfqd1X9vDAgv0Jb26KjyL8akF9CBeFqX8rVaBAnW/Wf6A2gYEwyYY4Bai3T7p1kro6DFrsvBAAw==}
|
||||
/@next/swc-win32-arm64-msvc@13.4.19:
|
||||
resolution: {integrity: sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
@ -1354,8 +1392,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-ia32-msvc@13.4.13:
|
||||
resolution: {integrity: sha512-E8bSPwRuY5ibJ3CzLQmJEt8qaWrPYuUTwnrwygPUEWoLzD5YRx9SD37oXRdU81TgGwDzCxpl7z5Nqlfk50xAog==}
|
||||
/@next/swc-win32-ia32-msvc@13.4.19:
|
||||
resolution: {integrity: sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
@ -1363,8 +1401,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-x64-msvc@13.4.13:
|
||||
resolution: {integrity: sha512-4KlyC6jWRubPnppgfYsNTPeWfGCxtWLh5vaOAW/kdzAk9widqho8Qb5S4K2vHmal1tsURi7Onk2MMCV1phvyqA==}
|
||||
/@next/swc-win32-x64-msvc@13.4.19:
|
||||
resolution: {integrity: sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@ -2238,15 +2276,15 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@sanity/groq-store@4.0.4:
|
||||
resolution: {integrity: sha512-Bk1ZsS6PGeCtmP8a4FJfvHws1WlnQUPdcr9MbO38Fbbtp55ZdLjTbxozxo//mK7jsbmNxf2HjpQ1mm5jDI49RQ==}
|
||||
/@sanity/groq-store@4.1.1:
|
||||
resolution: {integrity: sha512-SZg6i5Vb/fncUk5le42ijwkPeOm8WRkPoofM5d+BBqcAAuHctD1qZV0TMyZkw+HFNXbjzhW76rrytTgzsP+ZaQ==}
|
||||
engines: {node: '>=14.18'}
|
||||
dependencies:
|
||||
'@sanity/eventsource': 5.0.0
|
||||
'@sanity/types': 3.15.0
|
||||
fast-deep-equal: 3.1.3
|
||||
groq: 3.15.0
|
||||
groq-js: 1.1.12
|
||||
groq-js: 1.2.0
|
||||
mendoza: 3.0.3
|
||||
simple-get: 4.0.1
|
||||
split2: 4.2.0
|
||||
@ -2409,11 +2447,11 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@sanity/preview-kit@3.0.0(@sanity/client@6.4.4)(react@18.2.0):
|
||||
resolution: {integrity: sha512-LF83FQJ0kZgB8Dz8nolseiXh+AsX0UaNd3GhNLMrsmSjy6GCagNyQzCpadysQyuBZHftXgMN/fQ0/gfoMjNSDA==}
|
||||
/@sanity/preview-kit@3.1.6(@sanity/client@6.4.4)(react@18.2.0):
|
||||
resolution: {integrity: sha512-V8gZlIcyqqMr1WDAzrNXntrgYVeR56EKEZHbXOoHIr3qjgCRXPogVJ5w09DJ6cMhv2NKClOpAqmA9MWzt81wXw==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@sanity/client': ^6.4.6
|
||||
'@sanity/client': ^6.4.9
|
||||
react: ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
@ -2421,7 +2459,7 @@ packages:
|
||||
dependencies:
|
||||
'@sanity/client': 6.4.4
|
||||
'@sanity/eventsource': 5.0.0
|
||||
'@sanity/groq-store': 4.0.4
|
||||
'@sanity/groq-store': 4.1.1
|
||||
'@vercel/stega': 0.1.0
|
||||
lodash.get: 4.4.2
|
||||
lodash.isplainobject: 4.0.6
|
||||
@ -2516,7 +2554,7 @@ packages:
|
||||
uuid: 8.3.2
|
||||
dev: false
|
||||
|
||||
/@sanity/vision@3.0.0(@babel/runtime@7.22.10)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.3)(@sanity/client@6.4.4)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@5.3.11):
|
||||
/@sanity/vision@3.0.0(@babel/runtime@7.22.10)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.4)(@sanity/client@6.4.4)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@5.3.11):
|
||||
resolution: {integrity: sha512-Dr18Iugz2xHEavag4asOzYBIjwnj+5SEB7DlbyNow0mQ5fQWYh8eRES2OBDvrOLbBJ5rVuZMIzrcokQ+nzmrBw==}
|
||||
peerDependencies:
|
||||
'@sanity/client': ^3.4.1
|
||||
@ -2524,7 +2562,7 @@ packages:
|
||||
rxjs: ^6.5.3
|
||||
styled-components: ^5.2
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.8.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.3)
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/commands': 6.2.4
|
||||
'@codemirror/lang-javascript': 6.1.9
|
||||
'@codemirror/language': 6.8.0
|
||||
@ -2565,6 +2603,13 @@ packages:
|
||||
tslib: 2.6.1
|
||||
dev: false
|
||||
|
||||
/@sanity/webhook@3.0.1:
|
||||
resolution: {integrity: sha512-2eTDg/+TR8lSX2OH6wH7M8UUwZUsD/i8Raw9mFH9myt2mkPY3ns77cU6K1QL2ZhwIIDJT5tttTELURF7RjlzVg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dependencies:
|
||||
base64url: 3.0.1
|
||||
dev: false
|
||||
|
||||
/@shuding/opentype.js@1.4.0-beta.0:
|
||||
resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
@ -2855,7 +2900,7 @@ packages:
|
||||
'@codemirror/state': '>=6.0.0'
|
||||
'@codemirror/view': '>=6.0.0'
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.8.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.3)
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/commands': 6.2.4
|
||||
'@codemirror/language': 6.8.0
|
||||
'@codemirror/lint': 6.4.0
|
||||
@ -2881,7 +2926,7 @@ packages:
|
||||
'@codemirror/theme-one-dark': 6.1.2
|
||||
'@codemirror/view': 6.16.0
|
||||
'@uiw/codemirror-extensions-basic-setup': 4.21.9(@codemirror/autocomplete@6.9.0)(@codemirror/commands@6.2.4)(@codemirror/language@6.8.0)(@codemirror/lint@6.4.0)(@codemirror/search@6.5.1)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)
|
||||
codemirror: 6.0.1(@lezer/common@1.0.3)
|
||||
codemirror: 6.0.1(@lezer/common@1.0.4)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
@ -3488,7 +3533,7 @@ packages:
|
||||
normalize-path: 3.0.0
|
||||
readdirp: 3.6.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
fsevents: 2.3.3
|
||||
|
||||
/chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
@ -3562,12 +3607,12 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/codemirror@6.0.1(@lezer/common@1.0.3):
|
||||
/codemirror@6.0.1(@lezer/common@1.0.4):
|
||||
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.8.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.3)
|
||||
'@codemirror/autocomplete': 6.9.0(@codemirror/language@6.9.0)(@codemirror/state@6.2.1)(@codemirror/view@6.16.0)(@lezer/common@1.0.4)
|
||||
'@codemirror/commands': 6.2.4
|
||||
'@codemirror/language': 6.8.0
|
||||
'@codemirror/language': 6.9.0
|
||||
'@codemirror/lint': 6.4.0
|
||||
'@codemirror/search': 6.5.1
|
||||
'@codemirror/state': 6.2.1
|
||||
@ -4808,6 +4853,14 @@ packages:
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/ftp@0.3.10:
|
||||
@ -5080,8 +5133,8 @@ packages:
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
|
||||
/groq-js@1.1.12:
|
||||
resolution: {integrity: sha512-02KhsoLuTwr/MOf6bBzt+rQOj+QuLoZ5IDDkzXM2NWY73CF1d29KTRBffzCAjsjBvY7kn+oQcwPdQVb3vBkl9w==}
|
||||
/groq-js@1.2.0:
|
||||
resolution: {integrity: sha512-XW4PXKqf4LMsRGGz2MmBRcxDg8NJD0qTJxvd7YOdb6/IH1RQcqL/QK2o76Uxd0A3CiwMlJLUoPrL9KGUDWT39A==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
|
||||
@ -6087,7 +6140,7 @@ packages:
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/next-intl@2.19.1(next@13.4.13)(react@18.2.0):
|
||||
/next-intl@2.19.1(next@13.4.19)(react@18.2.0):
|
||||
resolution: {integrity: sha512-fk+IGWXxA+UOk+3rIhQqSPYxka+Hk9qKaIpbeF3nNlf8dp1td0oT6srVrPw/uZl5Qoj8El3qQ2mVd3RTLA25cg==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
@ -6096,34 +6149,32 @@ packages:
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher': 0.2.32
|
||||
negotiator: 0.6.3
|
||||
next: 13.4.13(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
use-intl: 2.19.1(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/next-sanity@5.3.0(@sanity/client@6.4.4)(@sanity/icons@2.4.1)(@sanity/types@3.15.0)(@sanity/ui@1.7.4)(@types/styled-components@5.1.26)(next@13.4.13)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11):
|
||||
resolution: {integrity: sha512-cBeO3QgIjR9UPjDedNfLT4m6vmeFlDn9HAVT/6q8CbMMf+bcpxQ94jpLGGkaPRzoeCy/XWKK4IXNQYDSs4ApIA==}
|
||||
/next-sanity@5.4.6(@sanity/client@6.4.4)(@sanity/icons@2.4.1)(@sanity/types@3.15.0)(@sanity/ui@1.7.4)(next@13.4.19)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11):
|
||||
resolution: {integrity: sha512-VgbLxYfgzLETNXKuvShhtaYKlz7DDb5QlFvvjf0eF82lIevI1c0jGHgPRhOTRuv0csvy9FVFCyMlxoc+BkAVmQ==}
|
||||
engines: {node: '>=16.14'}
|
||||
peerDependencies:
|
||||
'@sanity/client': ^6.4.6
|
||||
'@sanity/client': ^6.4.9
|
||||
'@sanity/icons': ^2.0.0
|
||||
'@sanity/types': ^3.0.0
|
||||
'@sanity/ui': ^1.0.0
|
||||
'@types/styled-components': ^5.1.0
|
||||
next: ^13.0.0
|
||||
react: ^18.0.0
|
||||
sanity: ^3.0.0
|
||||
styled-components: ^5.2.0
|
||||
styled-components: ^5.2.0 || ^6.0.0
|
||||
dependencies:
|
||||
'@sanity/client': 6.4.4
|
||||
'@sanity/icons': 2.4.1(react@18.2.0)
|
||||
'@sanity/preview-kit': 3.0.0(@sanity/client@6.4.4)(react@18.2.0)
|
||||
'@sanity/preview-kit': 3.1.6(@sanity/client@6.4.4)(react@18.2.0)
|
||||
'@sanity/types': 3.15.0
|
||||
'@sanity/ui': 1.7.4(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@5.3.11)
|
||||
'@sanity/webhook': 2.0.0
|
||||
'@types/styled-components': 5.1.26
|
||||
'@sanity/webhook': 3.0.1
|
||||
groq: 3.15.0
|
||||
next: 13.4.13(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
sanity: 3.15.0(@types/node@18.13.0)(@types/react@18.2.19)(react-dom@18.2.0)(react@18.2.0)(styled-components@5.3.11)
|
||||
styled-components: 5.3.11(@babel/core@7.22.10)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)
|
||||
@ -6131,8 +6182,8 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/next@13.4.13(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-A3YVbVDNeXLhWsZ8Nf6IkxmNlmTNz0yVg186NJ97tGZqPDdPzTrHotJ+A1cuJm2XfuWPrKOUZILl5iBQkIf8Jw==}
|
||||
/next@13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw==}
|
||||
engines: {node: '>=16.8.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@ -6146,7 +6197,7 @@ packages:
|
||||
sass:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@next/env': 13.4.13
|
||||
'@next/env': 13.4.19
|
||||
'@swc/helpers': 0.5.1
|
||||
busboy: 1.6.0
|
||||
caniuse-lite: 1.0.30001519
|
||||
@ -6157,15 +6208,15 @@ packages:
|
||||
watchpack: 2.4.0
|
||||
zod: 3.21.4
|
||||
optionalDependencies:
|
||||
'@next/swc-darwin-arm64': 13.4.13
|
||||
'@next/swc-darwin-x64': 13.4.13
|
||||
'@next/swc-linux-arm64-gnu': 13.4.13
|
||||
'@next/swc-linux-arm64-musl': 13.4.13
|
||||
'@next/swc-linux-x64-gnu': 13.4.13
|
||||
'@next/swc-linux-x64-musl': 13.4.13
|
||||
'@next/swc-win32-arm64-msvc': 13.4.13
|
||||
'@next/swc-win32-ia32-msvc': 13.4.13
|
||||
'@next/swc-win32-x64-msvc': 13.4.13
|
||||
'@next/swc-darwin-arm64': 13.4.19
|
||||
'@next/swc-darwin-x64': 13.4.19
|
||||
'@next/swc-linux-arm64-gnu': 13.4.19
|
||||
'@next/swc-linux-arm64-musl': 13.4.19
|
||||
'@next/swc-linux-x64-gnu': 13.4.19
|
||||
'@next/swc-linux-x64-musl': 13.4.19
|
||||
'@next/swc-win32-arm64-msvc': 13.4.19
|
||||
'@next/swc-win32-ia32-msvc': 13.4.19
|
||||
'@next/swc-win32-x64-msvc': 13.4.19
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
@ -7360,7 +7411,7 @@ packages:
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
fsevents: 2.3.3
|
||||
dev: false
|
||||
|
||||
/run-applescript@5.0.0:
|
||||
@ -7440,23 +7491,25 @@ packages:
|
||||
diff-match-patch: 1.0.5
|
||||
dev: false
|
||||
|
||||
/sanity-plugin-iframe-pane@2.3.0(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11):
|
||||
resolution: {integrity: sha512-bTq1Fnj1AQv5FXOE/88z41tSlJkfd7Ra/+19CvFOkOdopr7nnCWtztaG+phlqm8cndIs+CMnSxaBByLf/RGcPQ==}
|
||||
/sanity-plugin-iframe-pane@2.5.5(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11):
|
||||
resolution: {integrity: sha512-GoOjYXw7KKmPwA5+dy3ebR27cN/v6DGPtBxx2eaiBvJdVBHQ74JiCs97Kx9y0cAPFBtmTQ+bg0JkKPtxJLl9cw==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: ^18
|
||||
sanity: ^3.0.0
|
||||
sanity: ^3
|
||||
styled-components: ^5.2
|
||||
dependencies:
|
||||
'@sanity/icons': 2.4.1(react@18.2.0)
|
||||
'@sanity/incompatible-plugin': 1.0.4(react-dom@18.2.0)(react@18.2.0)
|
||||
'@sanity/ui': 1.7.4(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@5.3.11)
|
||||
framer-motion: 10.15.1(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
sanity: 3.15.0(@types/node@18.13.0)(@types/react@18.2.19)(react-dom@18.2.0)(react@18.2.0)(styled-components@5.3.11)
|
||||
styled-components: 5.3.11(@babel/core@7.22.10)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)
|
||||
usehooks-ts: 2.9.1(react-dom@18.2.0)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- react-dom
|
||||
- react-is
|
||||
- styled-components
|
||||
dev: false
|
||||
|
||||
/sanity-plugin-internationalized-array@1.10.1(@sanity/ui@1.7.4)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.15.0)(styled-components@5.3.11):
|
||||
@ -8085,6 +8138,10 @@ packages:
|
||||
resolution: {integrity: sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==}
|
||||
dev: false
|
||||
|
||||
/style-mod@4.1.0:
|
||||
resolution: {integrity: sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==}
|
||||
dev: false
|
||||
|
||||
/styled-components@5.3.11(@babel/core@7.22.10)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==}
|
||||
engines: {node: '>=10'}
|
||||
@ -8169,6 +8226,14 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/suspend-react@0.1.3(react@18.2.0):
|
||||
resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==}
|
||||
peerDependencies:
|
||||
react: '>=17.0'
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/symbol-tree@3.2.4:
|
||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||
dev: false
|
||||
@ -8678,7 +8743,7 @@ packages:
|
||||
postcss: 8.4.27
|
||||
rollup: 3.28.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
fsevents: 2.3.3
|
||||
dev: false
|
||||
|
||||
/w3c-keyname@2.2.8:
|
||||
|
@ -3,30 +3,88 @@ import { structure } from '@/lib/sanity/desk'
|
||||
import { schemaTypes } from '@/lib/sanity/schemas'
|
||||
import { documentInternationalization } from '@sanity/document-internationalization'
|
||||
import { visionTool } from '@sanity/vision'
|
||||
import { defineConfig, isDev } from 'sanity'
|
||||
import { defineConfig } from 'sanity'
|
||||
import { IframeOptions } from 'sanity-plugin-iframe-pane'
|
||||
import { previewUrl } from 'sanity-plugin-iframe-pane/preview-url'
|
||||
import { media } from 'sanity-plugin-media'
|
||||
import { deskTool } from 'sanity/desk'
|
||||
import { apiVersion, dataset, previewSecretId, projectId } from './lib/sanity/sanity.api'
|
||||
import category from './lib/sanity/schemas/documents/category'
|
||||
import page from './lib/sanity/schemas/documents/page'
|
||||
import product from './lib/sanity/schemas/documents/product'
|
||||
import home from './lib/sanity/schemas/singletons/home'
|
||||
import search from './lib/sanity/schemas/singletons/search'
|
||||
|
||||
const devOnlyPlugins = [visionTool()]
|
||||
const devOnlyPlugins = [visionTool({ defaultApiVersion: apiVersion})]
|
||||
|
||||
export const PREVIEWABLE_DOCUMENT_TYPES = [
|
||||
home.name,
|
||||
page.name,
|
||||
category.name,
|
||||
product.name,
|
||||
search.name
|
||||
] satisfies string[]
|
||||
|
||||
// Used to generate URLs for drafts and live previews
|
||||
export const PREVIEW_BASE_URL = '/api/preview'
|
||||
|
||||
// export const urlResolver = defineUrlResolver({
|
||||
// base: PREVIEW_BASE_URL,
|
||||
// })
|
||||
|
||||
// import {MissingSlug, type UrlResolver} from 'sanity-plugin-iframe-pane'
|
||||
|
||||
export const urlResolver = (document: any, urlSecret: any) => {
|
||||
const url = new URL(PREVIEW_BASE_URL, location.origin)
|
||||
url.searchParams.set('type', document._type)
|
||||
const lang = document?.language
|
||||
url.searchParams.set('locale', lang)
|
||||
const slug = (document?.slug as any)?.current
|
||||
if (slug) {
|
||||
url.searchParams.set('slug', slug)
|
||||
}
|
||||
|
||||
if (urlSecret) {
|
||||
url.searchParams.set('secret', urlSecret)
|
||||
}
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
export const iframeOptions = {
|
||||
url: urlResolver,
|
||||
urlSecretId: previewSecretId,
|
||||
} satisfies IframeOptions
|
||||
|
||||
// Define the actions that should be available for singleton documents
|
||||
const singletonActions = new Set(["publish", "discardChanges", "restore"])
|
||||
|
||||
// Define the singleton document types
|
||||
const singletonTypes = new Set(["settings", "home", "utilityMenu", "media.tag", ])
|
||||
const singletonTypes = new Set(["settings", "home", "search", "utilityMenu", "media.tag", ])
|
||||
|
||||
// console.log(process.env.SANITY_API_READ_TOKEN)
|
||||
|
||||
export default defineConfig({
|
||||
name: 'default',
|
||||
title: 'KM Storefront CMS',
|
||||
projectId: 'opfmivlh',
|
||||
projectId: projectId,
|
||||
basePath: '/studio',
|
||||
dataset: 'production',
|
||||
dataset: dataset,
|
||||
plugins: [
|
||||
deskTool({structure}),
|
||||
// deskTool({structure}),
|
||||
deskTool({
|
||||
structure: structure,
|
||||
}),
|
||||
// Configures the global "new document" button, and document actions, to suit the Settings document singleton
|
||||
// singletonPlugin([home.name, search.name]),
|
||||
|
||||
// Add the "Open preview" action
|
||||
previewUrl({
|
||||
base: PREVIEW_BASE_URL,
|
||||
urlSecretId: previewSecretId,
|
||||
matchTypes: PREVIEWABLE_DOCUMENT_TYPES,
|
||||
}),
|
||||
media(),
|
||||
...(isDev ? devOnlyPlugins : []),
|
||||
// ...(isDev ? devOnlyPlugins : []),
|
||||
documentInternationalization({
|
||||
// Required, either:
|
||||
// An array of supported languages
|
||||
@ -48,10 +106,6 @@ export default defineConfig({
|
||||
'utilityMenu',
|
||||
'search'
|
||||
],
|
||||
// Optional
|
||||
// languageField: `language`, // defauts to "language"
|
||||
// Optional, requires access to the Publishing API
|
||||
// bulkPublish: true // defaults to false
|
||||
}),
|
||||
],
|
||||
schema: {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
const { fontFamily } = require('tailwindcss/defaultTheme')
|
||||
const { fontFamily } = require('tailwindcss/defaultTheme');
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
|
||||
module.exports = {
|
||||
@ -21,7 +21,7 @@ module.exports = {
|
||||
'3xl': '1.75rem',
|
||||
'4xl': '2rem',
|
||||
'5xl': '3rem',
|
||||
'6xl': '4rem',
|
||||
'6xl': '4rem'
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
@ -42,62 +42,34 @@ module.exports = {
|
||||
red: '#ec5d40',
|
||||
yellow: '#ffcb47',
|
||||
// UI.SHADCN.COM
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))'
|
||||
},
|
||||
textColor: {
|
||||
base: '#333333',
|
||||
'low-contrast': '#585858',
|
||||
'high-contrast': '#333333',
|
||||
'high-contrast': '#333333'
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['var(--font-inter)', ...fontFamily.sans],
|
||||
display: ['var(--font-inter-tight)', ...fontFamily.sans],
|
||||
display: ['var(--font-inter-tight)', ...fontFamily.sans]
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
'accordion-down': {
|
||||
from: { height: 0 },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
},
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: 0 },
|
||||
to: { height: 'var(--radix-accordion-content-height)' }
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: 0 }
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out'
|
||||
},
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
@ -107,13 +79,13 @@ module.exports = {
|
||||
textDecoration: 'underline',
|
||||
color: '#3182ce',
|
||||
'&:hover': {
|
||||
color: '#2c5282',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
color: '#2c5282'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require('tailwindcss-animate'),
|
||||
@ -135,5 +107,5 @@ module.exports = {
|
||||
],
|
||||
future: {
|
||||
hoverOnlyWhenSupported: true
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user