mirror of
https://github.com/vercel/commerce.git
synced 2025-05-15 14:06:59 +00:00
Iterations and TS error fixes
This commit is contained in:
parent
c68f95e454
commit
4bf59a61f6
@ -7,7 +7,6 @@ interface CategoryPageProps {
|
|||||||
// has access to state and effects just like Page components
|
// has access to state and effects just like Page components
|
||||||
// in the `pages` directory.
|
// in the `pages` directory.
|
||||||
export default function ProductPage({data }: CategoryPageProps) {
|
export default function ProductPage({data }: CategoryPageProps) {
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>Category page</>
|
<>Category page</>
|
||||||
|
@ -14,8 +14,6 @@ export async function generateStaticParams() {
|
|||||||
next: { revalidate: 10 },
|
next: { revalidate: 10 },
|
||||||
})
|
})
|
||||||
|
|
||||||
// console.log(paths)
|
|
||||||
|
|
||||||
return paths.map((path: {
|
return paths.map((path: {
|
||||||
slug: string,
|
slug: string,
|
||||||
locale: string
|
locale: string
|
||||||
@ -52,7 +50,7 @@ export default async function Page({
|
|||||||
}) {
|
}) {
|
||||||
const { slug, locale } = params;
|
const { slug, locale } = params;
|
||||||
|
|
||||||
const { query, queryParams, docType } = getQueryFromSlug(slug, locale)
|
const { query = '', queryParams, docType } = getQueryFromSlug(slug, locale)
|
||||||
|
|
||||||
const pageData = await client.fetch(query, queryParams)
|
const pageData = await client.fetch(query, queryParams)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import ProductView from "components/product/product-view";
|
import ProductView from "components/product/product-view";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
interface ProductPageProps {
|
interface ProductPageProps {
|
||||||
data: object | any
|
data: object | any
|
||||||
@ -8,6 +9,10 @@ interface ProductPageProps {
|
|||||||
// has access to state and effects just like Page components
|
// has access to state and effects just like Page components
|
||||||
// in the `pages` directory.
|
// in the `pages` directory.
|
||||||
export default function ProductPage({data }: ProductPageProps) {
|
export default function ProductPage({data }: ProductPageProps) {
|
||||||
|
if (!data) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
|
|
||||||
const { product } = data;
|
const { product } = data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -39,6 +39,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* COMPONENTS */
|
/* COMPONENTS */
|
||||||
|
.glider {
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glider::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.glider-dots {
|
.glider-dots {
|
||||||
@apply flex !space-x-[2px] !mt-8;
|
@apply flex !space-x-[2px] !mt-8;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,9 @@ export default async function LocaleLayout({children, params: {locale}}: LocaleL
|
|||||||
<body className="flex flex-col min-h-screen">
|
<body className="flex flex-col min-h-screen">
|
||||||
<NextIntlClientProvider locale={locale} messages={messages}>
|
<NextIntlClientProvider locale={locale} messages={messages}>
|
||||||
<Header />
|
<Header />
|
||||||
<main className="flex-1">{children}</main>
|
<main className="flex-1">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
</body>
|
</body>
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
import type { Metadata } from 'next';
|
|
||||||
import { notFound } from 'next/navigation';
|
|
||||||
import { Suspense } from 'react';
|
|
||||||
|
|
||||||
import Grid from 'components/grid';
|
|
||||||
import Footer from 'components/layout/footer';
|
|
||||||
import ProductGridItems from 'components/layout/product-grid-items';
|
|
||||||
import { AddToCart } from 'components/product/add-to-cart';
|
|
||||||
import { Gallery } from 'components/product/gallery';
|
|
||||||
import { VariantSelector } from 'components/product/variant-selector';
|
|
||||||
import Prose from 'components/prose';
|
|
||||||
import { HIDDEN_PRODUCT_TAG } from 'lib/constants';
|
|
||||||
import { getProduct, getProductRecommendations } from 'lib/shopify';
|
|
||||||
import { Image } from 'lib/shopify/types';
|
|
||||||
|
|
||||||
export const runtime = 'edge';
|
|
||||||
|
|
||||||
export async function generateMetadata({
|
|
||||||
params
|
|
||||||
}: {
|
|
||||||
params: { handle: string };
|
|
||||||
}): Promise<Metadata> {
|
|
||||||
const product = await getProduct(params.handle);
|
|
||||||
|
|
||||||
if (!product) return notFound();
|
|
||||||
|
|
||||||
const { url, width, height, altText: alt } = product.featuredImage || {};
|
|
||||||
const hide = !product.tags.includes(HIDDEN_PRODUCT_TAG);
|
|
||||||
|
|
||||||
return {
|
|
||||||
title: product.seo.title || product.title,
|
|
||||||
description: product.seo.description || product.description,
|
|
||||||
robots: {
|
|
||||||
index: hide,
|
|
||||||
follow: hide,
|
|
||||||
googleBot: {
|
|
||||||
index: hide,
|
|
||||||
follow: hide
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openGraph: url
|
|
||||||
? {
|
|
||||||
images: [
|
|
||||||
{
|
|
||||||
url,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
alt
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function ProductPage({ params }: { params: { handle: string } }) {
|
|
||||||
const product = await getProduct(params.handle);
|
|
||||||
|
|
||||||
if (!product) return notFound();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="lg:grid lg:grid-cols-6">
|
|
||||||
<div className="lg:col-span-4">
|
|
||||||
<Gallery
|
|
||||||
title={product.title}
|
|
||||||
amount={product.priceRange.maxVariantPrice.amount}
|
|
||||||
currencyCode={product.priceRange.maxVariantPrice.currencyCode}
|
|
||||||
images={product.images.map((image: Image) => ({
|
|
||||||
src: image.url,
|
|
||||||
altText: image.altText
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-6 lg:col-span-2">
|
|
||||||
{/* @ts-expect-error Server Component */}
|
|
||||||
<VariantSelector options={product.options} variants={product.variants} />
|
|
||||||
|
|
||||||
{product.descriptionHtml ? (
|
|
||||||
<Prose className="mb-6 text-sm leading-tight" html={product.descriptionHtml} />
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<AddToCart variants={product.variants} availableForSale={product.availableForSale} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Suspense>
|
|
||||||
{/* @ts-expect-error Server Component */}
|
|
||||||
<RelatedProducts id={product.id} />
|
|
||||||
<Suspense>
|
|
||||||
{/* @ts-expect-error Server Component */}
|
|
||||||
<Footer />
|
|
||||||
</Suspense>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function RelatedProducts({ id }: { id: string }) {
|
|
||||||
const relatedProducts = await getProductRecommendations(id);
|
|
||||||
|
|
||||||
if (!relatedProducts.length) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="px-4 py-8">
|
|
||||||
<div className="mb-4 text-3xl font-bold">Related Products</div>
|
|
||||||
<Grid className="grid-cols-2 lg:grid-cols-5">
|
|
||||||
<ProductGridItems products={relatedProducts} />
|
|
||||||
</Grid>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
import { getCollections, getPages, getProducts } from 'lib/shopify';
|
|
||||||
import { MetadataRoute } from 'next';
|
import { MetadataRoute } from 'next';
|
||||||
|
|
||||||
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
|
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
|
||||||
@ -11,23 +10,5 @@ export default async function sitemap(): Promise<Promise<Promise<MetadataRoute.S
|
|||||||
lastModified: new Date().toISOString()
|
lastModified: new Date().toISOString()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const collections = await getCollections();
|
return [...routesMap];
|
||||||
const collectionsMap = collections.map((collection) => ({
|
|
||||||
url: `${baseUrl}${collection.path}`,
|
|
||||||
lastModified: collection.updatedAt
|
|
||||||
}));
|
|
||||||
|
|
||||||
const products = await getProducts({});
|
|
||||||
const productsMap = products.map((product) => ({
|
|
||||||
url: `${baseUrl}/product/${product.handle}`,
|
|
||||||
lastModified: product.updatedAt
|
|
||||||
}));
|
|
||||||
|
|
||||||
const pages = await getPages();
|
|
||||||
const pagesMap = pages.map((page) => ({
|
|
||||||
url: `${baseUrl}/${page.handle}`,
|
|
||||||
lastModified: page.updatedAt
|
|
||||||
}));
|
|
||||||
|
|
||||||
return [...routesMap, ...collectionsMap, ...productsMap, ...pagesMap];
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import CloseIcon from 'components/icons/close';
|
import CloseIcon from 'components/icons/close';
|
||||||
import LoadingDots from 'components/loading-dots';
|
import LoadingDots from 'components/ui/loading-dots';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { startTransition, useState } from 'react';
|
import { startTransition, useState } from 'react';
|
||||||
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
import LogoIcon from 'components/icons/logo';
|
|
||||||
// import { getMenu } from 'lib/shopify';
|
|
||||||
// import { Menu } from 'lib/shopify/types';
|
|
||||||
// import MobileMenu from './mobile-menu';
|
|
||||||
// import Search from './search';
|
|
||||||
|
|
||||||
export default async function Navbar() {
|
|
||||||
// const menu = await getMenu('next-js-frontend-header-menu');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav className="relative flex items-center justify-between bg-white p-4 dark:bg-black lg:px-6">
|
|
||||||
<div className="block w-1/3 md:hidden">
|
|
||||||
{/* <MobileMenu menu={menu} /> */}
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-self-center md:w-1/3 md:justify-self-start">
|
|
||||||
<div className="md:mr-4">
|
|
||||||
<Link href="/" aria-label="Go back home">
|
|
||||||
<LogoIcon className="h-8 transition-transform hover:scale-110" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
{/* {menu.length ? (
|
|
||||||
<ul className="hidden md:flex">
|
|
||||||
{menu.map((item: Menu) => (
|
|
||||||
<li key={item.title}>
|
|
||||||
<Link
|
|
||||||
href={item.path}
|
|
||||||
className="rounded-lg px-2 py-1 text-gray-800 hover:text-gray-500 dark:text-gray-200 dark:hover:text-gray-400"
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
) : null} */}
|
|
||||||
</div>
|
|
||||||
<div className="hidden w-1/3 md:block">
|
|
||||||
{/* <Search /> */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex w-1/3 justify-end">
|
|
||||||
{/* <Suspense fallback={<CartIcon className="h-6" />}> */}
|
|
||||||
{/* @ts-expect-error Server Component */}
|
|
||||||
{/* <Cart /> */}
|
|
||||||
{/* </Suspense> */}
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { Dialog } from '@headlessui/react';
|
|
||||||
import { motion } from 'framer-motion';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { usePathname, useSearchParams } from 'next/navigation';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import CloseIcon from 'components/icons/close';
|
|
||||||
import MenuIcon from 'components/icons/menu';
|
|
||||||
import { Menu } from 'lib/shopify/types';
|
|
||||||
import Search from './search';
|
|
||||||
|
|
||||||
export default function MobileMenu({ menu }: { menu: Menu[] }) {
|
|
||||||
const pathname = usePathname();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [mobileMenuIsOpen, setMobileMenuIsOpen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
if (window.innerWidth > 768) {
|
|
||||||
setMobileMenuIsOpen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
window.addEventListener('resize', handleResize);
|
|
||||||
return () => window.removeEventListener('resize', handleResize);
|
|
||||||
}, [mobileMenuIsOpen]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMobileMenuIsOpen(false);
|
|
||||||
}, [pathname, searchParams]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setMobileMenuIsOpen(!mobileMenuIsOpen);
|
|
||||||
}}
|
|
||||||
aria-label="Open mobile menu"
|
|
||||||
className="md:hidden"
|
|
||||||
data-testid="open-mobile-menu"
|
|
||||||
>
|
|
||||||
<MenuIcon className="h-6" />
|
|
||||||
</button>
|
|
||||||
<Dialog
|
|
||||||
open={mobileMenuIsOpen}
|
|
||||||
onClose={() => {
|
|
||||||
setMobileMenuIsOpen(false);
|
|
||||||
}}
|
|
||||||
className="relative z-50"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 flex justify-end" data-testid="mobile-menu">
|
|
||||||
<Dialog.Panel
|
|
||||||
as={motion.div}
|
|
||||||
variants={{
|
|
||||||
open: { opacity: 1 }
|
|
||||||
}}
|
|
||||||
className="flex w-full flex-col bg-white pb-6 dark:bg-black"
|
|
||||||
>
|
|
||||||
<div className="p-4">
|
|
||||||
<button
|
|
||||||
className="mb-4"
|
|
||||||
onClick={() => {
|
|
||||||
setMobileMenuIsOpen(false);
|
|
||||||
}}
|
|
||||||
aria-label="Close mobile menu"
|
|
||||||
data-testid="close-mobile-menu"
|
|
||||||
>
|
|
||||||
<CloseIcon className="h-6" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div className="mb-4 w-full">
|
|
||||||
<Search />
|
|
||||||
</div>
|
|
||||||
{menu.length ? (
|
|
||||||
<ul className="flex flex-col">
|
|
||||||
{menu.map((item: Menu) => (
|
|
||||||
<li key={item.title}>
|
|
||||||
<Link
|
|
||||||
href={item.path}
|
|
||||||
className="rounded-lg py-1 text-xl text-black transition-colors hover:text-gray-500 dark:text-white"
|
|
||||||
onClick={() => {
|
|
||||||
setMobileMenuIsOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</Dialog.Panel>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
|
||||||
|
|
||||||
import SearchIcon from 'components/icons/search';
|
|
||||||
|
|
||||||
export default function Search() {
|
|
||||||
const router = useRouter();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
|
|
||||||
function onSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const val = e.target as HTMLFormElement;
|
|
||||||
const search = val.search as HTMLInputElement;
|
|
||||||
|
|
||||||
if (search.value) {
|
|
||||||
router.push(`/search?q=${search.value}`);
|
|
||||||
} else {
|
|
||||||
router.push(`/search`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<form
|
|
||||||
onSubmit={onSubmit}
|
|
||||||
className="relative m-0 flex w-full items-center border border-gray-200 bg-transparent p-0 dark:border-gray-500"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="search"
|
|
||||||
placeholder="Search for products..."
|
|
||||||
autoComplete="off"
|
|
||||||
defaultValue={searchParams?.get('q') || ''}
|
|
||||||
className="w-full px-4 py-2 text-black dark:bg-black dark:text-gray-100"
|
|
||||||
/>
|
|
||||||
<div className="absolute right-0 top-0 mr-3 flex h-full items-center">
|
|
||||||
<SearchIcon className="h-5" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import clsx from 'clsx';
|
|
||||||
import { Suspense } from 'react';
|
|
||||||
|
|
||||||
import { getCollections } from 'lib/shopify';
|
|
||||||
import FilterList from './filter';
|
|
||||||
|
|
||||||
async function CollectionList() {
|
|
||||||
const collections = await getCollections();
|
|
||||||
return <FilterList list={collections} title="Collections" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const skeleton = 'mb-3 h-4 w-5/6 animate-pulse rounded';
|
|
||||||
const activeAndTitles = 'bg-gray-800 dark:bg-gray-300';
|
|
||||||
const items = 'bg-gray-400 dark:bg-gray-700';
|
|
||||||
|
|
||||||
export default function Collections() {
|
|
||||||
return (
|
|
||||||
<Suspense
|
|
||||||
fallback={
|
|
||||||
<div className="col-span-2 hidden h-[400px] w-full flex-none py-4 pl-10 lg:block">
|
|
||||||
<div className={clsx(skeleton, activeAndTitles)} />
|
|
||||||
<div className={clsx(skeleton, activeAndTitles)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
<div className={clsx(skeleton, items)} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{/* @ts-expect-error Server Component */}
|
|
||||||
<CollectionList />
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { usePathname, useSearchParams } from 'next/navigation';
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import Caret from 'components/icons/caret-right';
|
|
||||||
import type { ListItem } from '.';
|
|
||||||
import { FilterItem } from './item';
|
|
||||||
|
|
||||||
export default function FilterItemDropdown({ list }: { list: ListItem[] }) {
|
|
||||||
const pathname = usePathname();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [active, setActive] = useState('');
|
|
||||||
const [openSelect, setOpenSelect] = useState(false);
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
|
||||||
if (ref.current && !ref.current.contains(event.target as Node)) {
|
|
||||||
setOpenSelect(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('click', handleClickOutside);
|
|
||||||
return () => window.removeEventListener('click', handleClickOutside);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
list.forEach((listItem: ListItem) => {
|
|
||||||
if (
|
|
||||||
('path' in listItem && pathname === listItem.path) ||
|
|
||||||
('slug' in listItem && searchParams.get('sort') === listItem.slug)
|
|
||||||
) {
|
|
||||||
setActive(listItem.title);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [pathname, list, searchParams]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="relative" ref={ref}>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
setOpenSelect(!openSelect);
|
|
||||||
}}
|
|
||||||
className="flex w-full items-center justify-between rounded border border-black/30 px-4 py-2 text-sm dark:border-white/30"
|
|
||||||
>
|
|
||||||
<div>{active}</div>
|
|
||||||
<Caret className="h-4 rotate-90" />
|
|
||||||
</div>
|
|
||||||
{openSelect && (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
setOpenSelect(false);
|
|
||||||
}}
|
|
||||||
className="absolute z-40 w-full rounded-b-md bg-white p-4 shadow-md dark:bg-black"
|
|
||||||
>
|
|
||||||
{list.map((item: ListItem, i) => (
|
|
||||||
<FilterItem key={i} item={item} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
import { SortFilterItem } from 'lib/constants';
|
|
||||||
import FilterItemDropdown from './dropdown';
|
|
||||||
import { FilterItem } from './item';
|
|
||||||
|
|
||||||
export type ListItem = SortFilterItem | PathFilterItem;
|
|
||||||
export type PathFilterItem = { title: string; path: string };
|
|
||||||
|
|
||||||
function FilterItemList({ list }: { list: ListItem[] }) {
|
|
||||||
return (
|
|
||||||
<div className="hidden md:block">
|
|
||||||
{list.map((item: ListItem, i) => (
|
|
||||||
<FilterItem key={i} item={item} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function FilterList({ list, title }: { list: ListItem[]; title?: string }) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<nav className="col-span-2 w-full flex-none px-6 py-2 md:py-4 md:pl-10">
|
|
||||||
{title ? (
|
|
||||||
<h3 className="hidden font-semibold text-black dark:text-white md:block">{title}</h3>
|
|
||||||
) : null}
|
|
||||||
<ul className="hidden md:block">
|
|
||||||
<FilterItemList list={list} />
|
|
||||||
</ul>
|
|
||||||
<ul className="md:hidden">
|
|
||||||
<FilterItemDropdown list={list} />
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { SortFilterItem } from 'lib/constants';
|
|
||||||
import { createUrl } from 'lib/utils';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { usePathname, useSearchParams } from 'next/navigation';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import type { ListItem, PathFilterItem } from '.';
|
|
||||||
|
|
||||||
function PathFilterItem({ item }: { item: PathFilterItem }) {
|
|
||||||
const pathname = usePathname();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [active, setActive] = useState(pathname === item.path);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setActive(pathname === item.path);
|
|
||||||
}, [pathname, item.path]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className="mt-2 flex text-sm text-gray-400" key={item.title}>
|
|
||||||
<Link
|
|
||||||
href={createUrl(item.path, searchParams)}
|
|
||||||
className={clsx('w-full hover:text-gray-800 dark:hover:text-gray-100', {
|
|
||||||
'text-gray-600 dark:text-gray-400': !active,
|
|
||||||
'font-semibold text-black dark:text-white': active
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SortFilterItem({ item }: { item: SortFilterItem }) {
|
|
||||||
const pathname = usePathname();
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [active, setActive] = useState(searchParams.get('sort') === item.slug);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setActive(searchParams.get('sort') === item.slug);
|
|
||||||
}, [searchParams, item.slug]);
|
|
||||||
|
|
||||||
const href =
|
|
||||||
item.slug && item.slug.length
|
|
||||||
? createUrl(pathname, new URLSearchParams({ sort: item.slug }))
|
|
||||||
: pathname;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className="mt-2 flex text-sm text-gray-400" key={item.title}>
|
|
||||||
<Link
|
|
||||||
prefetch={false}
|
|
||||||
href={href}
|
|
||||||
className={clsx('w-full hover:text-gray-800 dark:hover:text-gray-100', {
|
|
||||||
'text-gray-600 dark:text-gray-400': !active,
|
|
||||||
'font-semibold text-black dark:text-white': active
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function FilterItem({ item }: { item: ListItem }) {
|
|
||||||
return 'path' in item ? <PathFilterItem item={item} /> : <SortFilterItem item={item} />;
|
|
||||||
}
|
|
@ -1,14 +1,6 @@
|
|||||||
import {
|
|
||||||
CarouselItemProps as ItemProps,
|
|
||||||
CarouselProps as Props,
|
|
||||||
} from 'components/modules/carousel/carousel'
|
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
const Carousel = dynamic<Props>(() =>
|
|
||||||
import('components/modules/carousel/carousel').then((mod) => mod.Carousel)
|
import { Carousel, CarouselItem } from 'components/modules/carousel/carousel'
|
||||||
)
|
|
||||||
const CarouselItem = dynamic<ItemProps>(() =>
|
|
||||||
import('components/modules/carousel/carousel').then((mod) => mod.CarouselItem)
|
|
||||||
)
|
|
||||||
const Card = dynamic(() => import('components/ui/card'))
|
const Card = dynamic(() => import('components/ui/card'))
|
||||||
|
|
||||||
import Text from 'components/ui/text'
|
import Text from 'components/ui/text'
|
||||||
@ -83,7 +75,6 @@ const BlurbSection = ({
|
|||||||
{blurbs && (
|
{blurbs && (
|
||||||
<Carousel
|
<Carousel
|
||||||
gliderClasses={'px-4 lg:px-8 2xl:px-16'}
|
gliderClasses={'px-4 lg:px-8 2xl:px-16'}
|
||||||
gliderItemWrapperClasses={''}
|
|
||||||
hasDots={true}
|
hasDots={true}
|
||||||
slidesToShow={2.2}
|
slidesToShow={2.2}
|
||||||
responsive={{
|
responsive={{
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
import {
|
|
||||||
CarouselItemProps as ItemProps,
|
|
||||||
CarouselProps as Props,
|
|
||||||
} from 'components/modules/carousel/carousel'
|
|
||||||
import Text from 'components/ui/text'
|
import Text from 'components/ui/text'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
const Carousel = dynamic<Props>(() =>
|
|
||||||
import('components/modules/carousel/carousel').then((mod) => mod.Carousel)
|
import { Carousel, CarouselItem } from 'components/modules/carousel/carousel'
|
||||||
)
|
|
||||||
const CarouselItem = dynamic<ItemProps>(() =>
|
|
||||||
import('components/modules/carousel/carousel').then((mod) => mod.CarouselItem)
|
|
||||||
)
|
|
||||||
const ProductCard = dynamic(() => import('components/ui/product-card'))
|
const ProductCard = dynamic(() => import('components/ui/product-card'))
|
||||||
const CategoryCard = dynamic(() => import('components/ui/category-card'))
|
const CategoryCard = dynamic(() => import('components/ui/category-card'))
|
||||||
|
|
||||||
|
@ -1,21 +1,12 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import {
|
import { Carousel, CarouselItem } from 'components/modules/carousel/carousel'
|
||||||
CarouselItemProps as ItemProps,
|
|
||||||
CarouselProps as Props,
|
|
||||||
} from 'components/modules/carousel/carousel'
|
|
||||||
import SanityImage from 'components/ui/sanity-image'
|
import SanityImage from 'components/ui/sanity-image'
|
||||||
import { Product } from "lib/storm/types/product"
|
import { Product } from "lib/storm/types/product"
|
||||||
import { cn } from 'lib/utils'
|
import { cn } from 'lib/utils'
|
||||||
import { useTranslations } from 'next-intl'
|
import { useTranslations } from 'next-intl'
|
||||||
import dynamic from "next/dynamic"
|
import dynamic from "next/dynamic"
|
||||||
const ProductCard = dynamic(() => import('components/ui/product-card'))
|
const ProductCard = dynamic(() => import('components/ui/product-card'))
|
||||||
const Carousel = dynamic<Props>(() =>
|
|
||||||
import('components/modules/carousel/carousel').then((mod) => mod.Carousel)
|
|
||||||
)
|
|
||||||
const CarouselItem = dynamic<ItemProps>(() =>
|
|
||||||
import('components/modules/carousel/carousel').then((mod) => mod.CarouselItem)
|
|
||||||
)
|
|
||||||
const Text = dynamic(() => import('components/ui/text'))
|
const Text = dynamic(() => import('components/ui/text'))
|
||||||
interface ProductViewProps {
|
interface ProductViewProps {
|
||||||
product: Product
|
product: Product
|
||||||
@ -78,7 +69,9 @@ export default function ProductView({product, relatedProducts }: ProductViewProp
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col col-span-1 mx-auto px-4 py-6 w-full h-auto lg:col-span-4 lg:py-0 lg:px-8 lg:pr-0 2xl:px-16 2xl:pr-0 lg:sticky lg:top-8 2xl:top-16">
|
<div className="flex flex-col col-span-1 mx-auto px-4 py-6 w-full h-auto lg:col-span-4 lg:py-0 lg:px-8 lg:pr-0 2xl:px-16 2xl:pr-0 lg:sticky lg:top-8 2xl:top-16">
|
||||||
|
<Text variant={'productHeading'}>
|
||||||
{product.name}
|
{product.name}
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export { default } from './I18nWidget'
|
export { default } from './locale-switcher';
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ type Variant =
|
|||||||
| 'heading'
|
| 'heading'
|
||||||
| 'body'
|
| 'body'
|
||||||
| 'pageHeading'
|
| 'pageHeading'
|
||||||
|
| 'productHeading'
|
||||||
| 'sectionHeading'
|
| 'sectionHeading'
|
||||||
| 'label'
|
| 'label'
|
||||||
| 'paragraph'
|
| 'paragraph'
|
||||||
@ -39,6 +40,7 @@ const Text: FunctionComponent<TextProps> = ({
|
|||||||
body: 'div',
|
body: 'div',
|
||||||
heading: 'h1',
|
heading: 'h1',
|
||||||
pageHeading: 'h1',
|
pageHeading: 'h1',
|
||||||
|
productHeading: 'h1',
|
||||||
sectionHeading: 'h2',
|
sectionHeading: 'h2',
|
||||||
listChildHeading: 'h3',
|
listChildHeading: 'h3',
|
||||||
label: 'div',
|
label: 'div',
|
||||||
@ -67,6 +69,8 @@ const Text: FunctionComponent<TextProps> = ({
|
|||||||
variant === 'heading',
|
variant === 'heading',
|
||||||
['max-w-prose text-3xl font-display font-bold leading-none md:text-4xl md:leading-none lg:leading-none lg:text-5xl']:
|
['max-w-prose text-3xl font-display font-bold leading-none md:text-4xl md:leading-none lg:leading-none lg:text-5xl']:
|
||||||
variant === 'pageHeading',
|
variant === 'pageHeading',
|
||||||
|
['max-w-prose text-2xl font-display leading-none md:text-3xl md:leading-none lg:leading-none lg:text-4xl']:
|
||||||
|
variant === 'productHeading',
|
||||||
['max-w-prose text-2xl font-display font-bold leading-none md:text-3xl md:leading-none lg:leading-none lg:text-4xl']:
|
['max-w-prose text-2xl font-display font-bold leading-none md:text-3xl md:leading-none lg:leading-none lg:text-4xl']:
|
||||||
variant === 'sectionHeading',
|
variant === 'sectionHeading',
|
||||||
['text-sm font-semibold leading-tight lg:text-base']:
|
['text-sm font-semibold leading-tight lg:text-base']:
|
||||||
|
@ -7,11 +7,11 @@ import {
|
|||||||
} from '../lib/sanity/queries'
|
} from '../lib/sanity/queries'
|
||||||
|
|
||||||
const getQueryFromSlug = (slugArray: string[], locale: string) => {
|
const getQueryFromSlug = (slugArray: string[], locale: string) => {
|
||||||
const docQuery = {
|
const docQuery: { [index: string]: string } = {
|
||||||
homePage: groq`${homePageQuery}`,
|
'homePage': groq`${homePageQuery}`,
|
||||||
product: groq`${productQuery}`,
|
'product': groq`${productQuery}`,
|
||||||
category: groq`${categoryQuery}`,
|
'category': groq`${categoryQuery}`,
|
||||||
page: groq`${pageQuery}`,
|
'page': groq`${pageQuery}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
let docType = ''
|
let docType = ''
|
||||||
|
@ -5,7 +5,10 @@ export default createMiddleware({
|
|||||||
locales: ['sv', 'en', 'nn'],
|
locales: ['sv', 'en', 'nn'],
|
||||||
|
|
||||||
// If this locale is matched, pathnames work without a prefix (e.g. `/about`)
|
// If this locale is matched, pathnames work without a prefix (e.g. `/about`)
|
||||||
defaultLocale: 'sv'
|
defaultLocale: 'sv',
|
||||||
|
|
||||||
|
// Don't automatically detect locale, sv is default.
|
||||||
|
localeDetection: false
|
||||||
});
|
});
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
|
@ -10,7 +10,6 @@ module.exports = withBundleAnalyzer(
|
|||||||
ignoreDuringBuilds: true
|
ignoreDuringBuilds: true
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
appDir: true,
|
|
||||||
scrollRestoration: true,
|
scrollRestoration: true,
|
||||||
},
|
},
|
||||||
images: {
|
images: {
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"framer-motion": "^8.4.0",
|
"framer-motion": "^8.4.0",
|
||||||
"is-empty-iterable": "^3.0.0",
|
"is-empty-iterable": "^3.0.0",
|
||||||
"lucide-react": "^0.194.0",
|
"lucide-react": "^0.194.0",
|
||||||
"next": "13.3.4",
|
"next": "13.4.0",
|
||||||
"next-intl": "^2.13.1",
|
"next-intl": "^2.13.1",
|
||||||
"next-sanity": "^4.2.0",
|
"next-sanity": "^4.2.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
@ -62,7 +62,7 @@
|
|||||||
"@vercel/git-hooks": "^1.0.0",
|
"@vercel/git-hooks": "^1.0.0",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
"eslint": "^8.35.0",
|
"eslint": "^8.35.0",
|
||||||
"eslint-config-next": "^13.3.4",
|
"eslint-config-next": "^13.4.0",
|
||||||
"eslint-config-prettier": "^8.6.0",
|
"eslint-config-prettier": "^8.6.0",
|
||||||
"eslint-plugin-unicorn": "^45.0.2",
|
"eslint-plugin-unicorn": "^45.0.2",
|
||||||
"lint-staged": "^13.1.1",
|
"lint-staged": "^13.1.1",
|
||||||
|
99
pnpm-lock.yaml
generated
99
pnpm-lock.yaml
generated
@ -24,14 +24,14 @@ specifiers:
|
|||||||
class-variance-authority: ^0.6.0
|
class-variance-authority: ^0.6.0
|
||||||
clsx: ^1.2.1
|
clsx: ^1.2.1
|
||||||
eslint: ^8.35.0
|
eslint: ^8.35.0
|
||||||
eslint-config-next: ^13.3.4
|
eslint-config-next: ^13.4.0
|
||||||
eslint-config-prettier: ^8.6.0
|
eslint-config-prettier: ^8.6.0
|
||||||
eslint-plugin-unicorn: ^45.0.2
|
eslint-plugin-unicorn: ^45.0.2
|
||||||
framer-motion: ^8.4.0
|
framer-motion: ^8.4.0
|
||||||
is-empty-iterable: ^3.0.0
|
is-empty-iterable: ^3.0.0
|
||||||
lint-staged: ^13.1.1
|
lint-staged: ^13.1.1
|
||||||
lucide-react: ^0.194.0
|
lucide-react: ^0.194.0
|
||||||
next: 13.3.4
|
next: 13.4.0
|
||||||
next-intl: ^2.13.1
|
next-intl: ^2.13.1
|
||||||
next-sanity: ^4.2.0
|
next-sanity: ^4.2.0
|
||||||
postcss: ^8.4.21
|
postcss: ^8.4.21
|
||||||
@ -66,9 +66,9 @@ dependencies:
|
|||||||
framer-motion: 8.5.5_biqbaboplfbrettd7655fr4n2y
|
framer-motion: 8.5.5_biqbaboplfbrettd7655fr4n2y
|
||||||
is-empty-iterable: 3.0.0
|
is-empty-iterable: 3.0.0
|
||||||
lucide-react: 0.194.0_react@18.2.0
|
lucide-react: 0.194.0_react@18.2.0
|
||||||
next: 13.3.4_5lnmxaau2bs7vcvowl2iwadrxa
|
next: 13.4.0_5lnmxaau2bs7vcvowl2iwadrxa
|
||||||
next-intl: 2.13.1_next@13.3.4+react@18.2.0
|
next-intl: 2.13.1_next@13.4.0+react@18.2.0
|
||||||
next-sanity: 4.2.0_ng6tx5vtrrzblbayibx5wevyra
|
next-sanity: 4.2.0_aehsfoaj4shzjn3qi6ffpl7sie
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-cookie: 4.1.1_react@18.2.0
|
react-cookie: 4.1.1_react@18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
@ -88,7 +88,7 @@ devDependencies:
|
|||||||
'@vercel/git-hooks': 1.0.0
|
'@vercel/git-hooks': 1.0.0
|
||||||
autoprefixer: 10.4.14_postcss@8.4.22
|
autoprefixer: 10.4.14_postcss@8.4.22
|
||||||
eslint: 8.38.0
|
eslint: 8.38.0
|
||||||
eslint-config-next: 13.3.4_ze6bmax3gcsfve3yrzu6npguhe
|
eslint-config-next: 13.4.0_ze6bmax3gcsfve3yrzu6npguhe
|
||||||
eslint-config-prettier: 8.8.0_eslint@8.38.0
|
eslint-config-prettier: 8.8.0_eslint@8.38.0
|
||||||
eslint-plugin-unicorn: 45.0.2_eslint@8.38.0
|
eslint-plugin-unicorn: 45.0.2_eslint@8.38.0
|
||||||
lint-staged: 13.2.1
|
lint-staged: 13.2.1
|
||||||
@ -1091,18 +1091,18 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@next/env/13.3.4:
|
/@next/env/13.4.0:
|
||||||
resolution: {integrity: sha512-oTK/wRV2qga86m/4VdrR1+/56UA6U1Qv3sIgowB+bZjahniZLEG5BmmQjfoGv7ZuLXBZ8Eec6hkL9BqJcrEL2g==}
|
resolution: {integrity: sha512-LKofmUuxwGXk2OZJSSJ2SlJE62s6z+56aRsze7chc5TPoVouLR9liTiSWxzYuVzuxk0ui2wtIjyR2tcgS1dIyw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@next/eslint-plugin-next/13.3.4:
|
/@next/eslint-plugin-next/13.4.0:
|
||||||
resolution: {integrity: sha512-mvS+HafOPy31oJbAi920WJXMdjbyb4v5FAMr9PeGZfRIdEcsLkA3mU/ZvmwzovJgP3nAWw2e2yM8iIFW8VpvIA==}
|
resolution: {integrity: sha512-ZqQi1slguDavpuNUcl9va8+WtHHpgymIW2g+4Gs9FdI+5rjAvrUqqjfCec2hi3Cjbbp7zULFQuAiPwASKHbrxw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
glob: 7.1.7
|
glob: 7.1.7
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@next/swc-darwin-arm64/13.3.4:
|
/@next/swc-darwin-arm64/13.4.0:
|
||||||
resolution: {integrity: sha512-vux7RWfzxy1lD21CMwZsy9Ej+0+LZdIIj1gEhVmzOQqQZ5N56h8JamrjIVCfDL+Lpj8KwOmFZbPHE8qaYnL2pg==}
|
resolution: {integrity: sha512-C39AGL3ANXA+P3cFclQjFZaJ4RHPmuBhskmyy0N3VyCntDmRrNkS4aXeNY4Xwure9IL1nuw02D8bM55I+FsbuQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
@ -1110,8 +1110,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-darwin-x64/13.3.4:
|
/@next/swc-darwin-x64/13.4.0:
|
||||||
resolution: {integrity: sha512-1tb+6JT98+t7UIhVQpKL7zegKnCs9RKU6cKNyj+DYKuC/NVl49/JaIlmwCwK8Ibl+RXxJrK7uSXSIO71feXsgw==}
|
resolution: {integrity: sha512-nj6nx6o7rnBXjo1woZFWLk7OUs7y0SQ0k65SX62kc88GqXtYi3BCqbBznjOX8qtrO//NmtAde/Jd5qkjSgINUQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
@ -1119,8 +1119,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-arm64-gnu/13.3.4:
|
/@next/swc-linux-arm64-gnu/13.4.0:
|
||||||
resolution: {integrity: sha512-UqcKkYTKslf5YAJNtZ5XV1D5MQJIkVtDHL8OehDZERHzqOe7jvy41HFto33IDPPU8gJiP5eJb3V9U26uifqHjw==}
|
resolution: {integrity: sha512-FBYL7kpzI2KG3lv8gO4xVYmWcFohptjzD9RCLdXsAz+Kqz5VCJILF21DoRcz4Nwj/jMe0SO7l5kBVW4POl4EaQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
@ -1128,8 +1128,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-arm64-musl/13.3.4:
|
/@next/swc-linux-arm64-musl/13.4.0:
|
||||||
resolution: {integrity: sha512-HE/FmE8VvstAfehyo/XsrhGgz97cEr7uf9IfkgJ/unqSXE0CDshDn/4as6rRid74eDR8/exi7c2tdo49Tuqxrw==}
|
resolution: {integrity: sha512-S3htBbcovnLMgVn0z1ThrP1iAeEM43fw8B7S3KyHTAGe0I21ww4rvUkLdgPCqLNvMpv899lmG7NU5rs6rTkGvg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
@ -1137,8 +1137,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-x64-gnu/13.3.4:
|
/@next/swc-linux-x64-gnu/13.4.0:
|
||||||
resolution: {integrity: sha512-xU+ugaupGA4SL5aK1ZYEqVHrW3TPOhxVcpaJLfpANm2443J4GfxCmOacu9XcSgy5c51Mq7C9uZ1LODKHfZosRQ==}
|
resolution: {integrity: sha512-H8GhCgQwFl6iWJ6azQ2tG/GY8BUg1nhPtg4Tp2kIPljdyQypTGJe8oRnPDx0N48WWvB2fNeA7LNEwzVuSidH2w==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
@ -1146,8 +1146,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-x64-musl/13.3.4:
|
/@next/swc-linux-x64-musl/13.4.0:
|
||||||
resolution: {integrity: sha512-cZvmf5KcYeTfIK6bCypfmxGUjme53Ep7hx94JJtGrYgCA1VwEuYdh+KouubJaQCH3aqnNE7+zGnVEupEKfoaaA==}
|
resolution: {integrity: sha512-mztVybRPY39NfPOA3QrRQKzYuw7A/D8ElR6ruvM1cBsXMEfF5xTzdZqfTtrE/gNTPUFug9FJPpiRpkZ4mDUl8w==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
@ -1155,8 +1155,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-win32-arm64-msvc/13.3.4:
|
/@next/swc-win32-arm64-msvc/13.4.0:
|
||||||
resolution: {integrity: sha512-7dL+CAUAjmgnVbjXPIpdj7/AQKFqEUL3bKtaOIE1JzJ5UMHHAXCPwzQtibrsvQpf9MwcAmiv8aburD3xH1xf8w==}
|
resolution: {integrity: sha512-mdVh/n0QqT2uXqn8kaTywUoLxY1OYqTpiKbt5b51pDwOStqgbIbqBqG0A7XDaiqWa7RKwllOYxPlPm16EDfWUA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@ -1164,8 +1164,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-win32-ia32-msvc/13.3.4:
|
/@next/swc-win32-ia32-msvc/13.4.0:
|
||||||
resolution: {integrity: sha512-qplTyzEl1vPkS+/DRK3pKSL0HeXrPHkYsV7U6gboHYpfqoHY+bcLUj3gwVUa9PEHRIoq4vXvPzx/WtzE6q52ng==}
|
resolution: {integrity: sha512-GNRqT2mqxxH0x9VthFqziBj8X8HsoBUougmLe3kOouRq/jF73LpKXG0Qs2MYkylqvv/Wg31EYjFNcJnBi1Nimg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@ -1173,8 +1173,8 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-win32-x64-msvc/13.3.4:
|
/@next/swc-win32-x64-msvc/13.4.0:
|
||||||
resolution: {integrity: sha512-usdvZT7JHrTuXC+4OKN5mCzUkviFkCyJJTkEz8jhBpucg+T7s83e7owm3oNFzmj5iKfvxU2St6VkcnSgpFvEYA==}
|
resolution: {integrity: sha512-0AkvhUBUqeb4WKN75IW1KjPkN3HazQFA0OpMuTK+6ptJUXMaMwDDcF3sIPCI741BJ2fpODB7BPM4C63hXWEypg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@ -3419,8 +3419,8 @@ packages:
|
|||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/eslint-config-next/13.3.4_ze6bmax3gcsfve3yrzu6npguhe:
|
/eslint-config-next/13.4.0_ze6bmax3gcsfve3yrzu6npguhe:
|
||||||
resolution: {integrity: sha512-TknEcP+EdTqLvJ2zMY1KnWqcx8ZHl1C2Tjjbq3qmtWcHRU5oxe1PAsz3vrKG3NOzonSaPcB2SpCSfYqcgj6nfA==}
|
resolution: {integrity: sha512-FkO3QRyUEKAHM4ie0xAcxo7fQ8gWevuLqgf6/g1Y6zWybqSa4FNeJr4hqqTbP25xIRgUUIPILBlx9RSH4C6+gQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^7.23.0 || ^8.0.0
|
eslint: ^7.23.0 || ^8.0.0
|
||||||
typescript: '>=3.3.1'
|
typescript: '>=3.3.1'
|
||||||
@ -3428,7 +3428,7 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/eslint-plugin-next': 13.3.4
|
'@next/eslint-plugin-next': 13.4.0
|
||||||
'@rushstack/eslint-patch': 1.2.0
|
'@rushstack/eslint-patch': 1.2.0
|
||||||
'@typescript-eslint/parser': 5.59.2_ze6bmax3gcsfve3yrzu6npguhe
|
'@typescript-eslint/parser': 5.59.2_ze6bmax3gcsfve3yrzu6npguhe
|
||||||
eslint: 8.38.0
|
eslint: 8.38.0
|
||||||
@ -5201,7 +5201,7 @@ packages:
|
|||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/next-intl/2.13.1_next@13.3.4+react@18.2.0:
|
/next-intl/2.13.1_next@13.4.0+react@18.2.0:
|
||||||
resolution: {integrity: sha512-3XUZ7c123QHgQGcz5UUkTtakJdLETBlcHcdHop43iVToOpsezxvMZW6jxWwuHTRvkElfNPy1fhHwzBo/mhVVvQ==}
|
resolution: {integrity: sha512-3XUZ7c123QHgQGcz5UUkTtakJdLETBlcHcdHop43iVToOpsezxvMZW6jxWwuHTRvkElfNPy1fhHwzBo/mhVVvQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5210,12 +5210,12 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/intl-localematcher': 0.2.32
|
'@formatjs/intl-localematcher': 0.2.32
|
||||||
negotiator: 0.6.3
|
negotiator: 0.6.3
|
||||||
next: 13.3.4_5lnmxaau2bs7vcvowl2iwadrxa
|
next: 13.4.0_5lnmxaau2bs7vcvowl2iwadrxa
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
use-intl: 2.13.1_react@18.2.0
|
use-intl: 2.13.1_react@18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/next-sanity/4.2.0_ng6tx5vtrrzblbayibx5wevyra:
|
/next-sanity/4.2.0_aehsfoaj4shzjn3qi6ffpl7sie:
|
||||||
resolution: {integrity: sha512-4GNEgXXDWPlvXqdJaAfKBR8BNvwQqUCynJ9GCgL6tVGcfZvcAImyZkzLTXj75PTZDPDcc7OfKHXg+XbmbUp7hA==}
|
resolution: {integrity: sha512-4GNEgXXDWPlvXqdJaAfKBR8BNvwQqUCynJ9GCgL6tVGcfZvcAImyZkzLTXj75PTZDPDcc7OfKHXg+XbmbUp7hA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5236,7 +5236,7 @@ packages:
|
|||||||
'@sanity/webhook': 2.0.0
|
'@sanity/webhook': 2.0.0
|
||||||
'@types/styled-components': 5.1.26
|
'@types/styled-components': 5.1.26
|
||||||
groq: 3.9.1
|
groq: 3.9.1
|
||||||
next: 13.3.4_5lnmxaau2bs7vcvowl2iwadrxa
|
next: 13.4.0_5lnmxaau2bs7vcvowl2iwadrxa
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
sanity: 3.9.1_inskn5v7aqlrr54h6fubgcms5y
|
sanity: 3.9.1_inskn5v7aqlrr54h6fubgcms5y
|
||||||
styled-components: 5.3.10_7i5myeigehqah43i5u7wbekgba
|
styled-components: 5.3.10_7i5myeigehqah43i5u7wbekgba
|
||||||
@ -5244,8 +5244,8 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/next/13.3.4_5lnmxaau2bs7vcvowl2iwadrxa:
|
/next/13.4.0_5lnmxaau2bs7vcvowl2iwadrxa:
|
||||||
resolution: {integrity: sha512-sod7HeokBSvH5QV0KB+pXeLfcXUlLrGnVUXxHpmhilQ+nQYT3Im2O8DswD5e4uqbR8Pvdu9pcWgb1CbXZQZlmQ==}
|
resolution: {integrity: sha512-y3E+2ZjiVrphkz7zcJvd2rEG6miOekI8krPfWV4AZZ9TaF0LDuFdP/f+RQ5M9wRvsz6GWw8k8+7jsO860GxSqg==}
|
||||||
engines: {node: '>=16.8.0'}
|
engines: {node: '>=16.8.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5265,7 +5265,7 @@ packages:
|
|||||||
sass:
|
sass:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/env': 13.3.4
|
'@next/env': 13.4.0
|
||||||
'@swc/helpers': 0.5.1
|
'@swc/helpers': 0.5.1
|
||||||
busboy: 1.6.0
|
busboy: 1.6.0
|
||||||
caniuse-lite: 1.0.30001482
|
caniuse-lite: 1.0.30001482
|
||||||
@ -5273,16 +5273,17 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
styled-jsx: 5.1.1_yxvpwo57iqrkjg2xxfiwjdgilu
|
styled-jsx: 5.1.1_yxvpwo57iqrkjg2xxfiwjdgilu
|
||||||
|
zod: 3.21.4
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@next/swc-darwin-arm64': 13.3.4
|
'@next/swc-darwin-arm64': 13.4.0
|
||||||
'@next/swc-darwin-x64': 13.3.4
|
'@next/swc-darwin-x64': 13.4.0
|
||||||
'@next/swc-linux-arm64-gnu': 13.3.4
|
'@next/swc-linux-arm64-gnu': 13.4.0
|
||||||
'@next/swc-linux-arm64-musl': 13.3.4
|
'@next/swc-linux-arm64-musl': 13.4.0
|
||||||
'@next/swc-linux-x64-gnu': 13.3.4
|
'@next/swc-linux-x64-gnu': 13.4.0
|
||||||
'@next/swc-linux-x64-musl': 13.3.4
|
'@next/swc-linux-x64-musl': 13.4.0
|
||||||
'@next/swc-win32-arm64-msvc': 13.3.4
|
'@next/swc-win32-arm64-msvc': 13.4.0
|
||||||
'@next/swc-win32-ia32-msvc': 13.3.4
|
'@next/swc-win32-ia32-msvc': 13.4.0
|
||||||
'@next/swc-win32-x64-msvc': 13.3.4
|
'@next/swc-win32-x64-msvc': 13.4.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
@ -7538,3 +7539,7 @@ packages:
|
|||||||
compress-commons: 4.1.1
|
compress-commons: 4.1.1
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/zod/3.21.4:
|
||||||
|
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||||
|
dev: false
|
||||||
|
@ -11,6 +11,18 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
safelist: ['outline-none'],
|
safelist: ['outline-none'],
|
||||||
theme: {
|
theme: {
|
||||||
|
fontSize: {
|
||||||
|
xs: '0.75rem',
|
||||||
|
sm: '0.875rem',
|
||||||
|
base: '1rem',
|
||||||
|
lg: '1.125rem',
|
||||||
|
xl: '1.25rem',
|
||||||
|
'2xl': '1.5rem',
|
||||||
|
'3xl': '1.75rem',
|
||||||
|
'4xl': '2rem',
|
||||||
|
'5xl': '3rem',
|
||||||
|
'6xl': '4rem',
|
||||||
|
},
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
app: '#ffffff',
|
app: '#ffffff',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user