Rewrite URLs for app router folders

This commit is contained in:
Henrik Larsson 2023-08-11 23:37:34 +02:00
parent 6a5aa06841
commit f14d0cb865
12 changed files with 95 additions and 71 deletions

View File

@ -0,0 +1,24 @@
'use client';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
export default function DesktopMenu({ items, locale }: { items: []; locale: string }) {
const t = useTranslations('routes');
return (
<ul className="flex gap-6">
{items.map((item: { title: string; slug: string }, i: number) => {
return (
<li key={i}>
<Link
className="font-medium underline-offset-2 hover:underline"
href={`/${locale}/${t('category')}/${item.slug}`}
>
{item.title}
</Link>
</li>
);
})}
</ul>
);
}

View File

@ -3,8 +3,10 @@ import { clientFetch } from '@/lib/sanity/sanity.client';
import Cart from 'components/cart'; import Cart from 'components/cart';
import OpenCart from 'components/cart/open-cart'; import OpenCart from 'components/cart/open-cart';
import Logo from 'components/ui/logo/logo'; import Logo from 'components/ui/logo/logo';
import Link from 'next/link'; import Link from 'next/link';
import { Suspense } from 'react'; import { Suspense } from 'react';
import DesktopMenu from './desktop-menu/desktop-menu';
import HeaderRoot from './header-root'; import HeaderRoot from './header-root';
import MobileMenuModal from './mobile-menu/modal'; import MobileMenuModal from './mobile-menu/modal';
import OpenMobileMenu from './mobile-menu/open-mobile-menu'; import OpenMobileMenu from './mobile-menu/open-mobile-menu';
@ -43,17 +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"> <div className="absolute left-1/2 top-1/2 hidden -translate-x-1/2 -translate-y-1/2 transform md:flex">
<Suspense> <Suspense>
<ul className="flex gap-6"> <DesktopMenu items={mainMenu} locale={locale} />
{mainMenu.map((item: { title: string; slug: string }, i: number) => {
return (
<li key={i}>
<Link className="font-medium" href={`/${locale}/category/${item.slug}`}>
{item.title}
</Link>
</li>
);
})}
</ul>
</Suspense> </Suspense>
</div> </div>
<div className="flex translate-x-2 transform justify-end space-x-1"> <div className="flex translate-x-2 transform justify-end space-x-1">

View File

@ -1,8 +1,6 @@
import { Carousel, CarouselItem } from '@/components/modules/carousel/carousel';
import Card from '@/components/ui/card/card'; import Card from '@/components/ui/card/card';
import { cn } from '@/lib/utils';
import Text from 'components/ui/text'; import Text from 'components/ui/text';
interface BlurbSectionProps { interface BlurbSectionProps {
blurbs: any; blurbs: any;
title: string; title: string;
@ -24,9 +22,7 @@ const BlurbSection = ({
: desktopLayout === '3-column' : desktopLayout === '3-column'
? 'lg:grid-cols-3' ? 'lg:grid-cols-3'
: 'lg:grid-cols-4'; : 'lg:grid-cols-4';
console.log(imageFormat);
const sliderLayout = desktopLayout === '2-column' ? 2 : desktopLayout === '3-column' ? 3 : 4;
return ( return (
<div> <div>
{title ? ( {title ? (
@ -42,52 +38,35 @@ const BlurbSection = ({
</Text> </Text>
)} )}
<div <div
className={`grid px-4 ${gridLayout} gap-x-4 gap-y-8 ${ className={cn(
mobileLayout === 'stacked' ? 'lg:hidden' : 'hidden' 'w-full gap-4 px-4 lg:px-8 2xl:px-16',
} lg:px-8 2xl:!px-16`} {
['grid grid-cols-1']: mobileLayout !== 'horizontal',
['flex snap-x snap-proximity overflow-x-auto lg:grid lg:overflow-visible']:
mobileLayout === 'horizontal'
},
`${gridLayout}`
)}
> >
{blurbs.map((blurb: object | any, index: number) => { {blurbs.map((blurb: object | any, index: number) => {
return ( return (
<div key={index}> <div
key={index}
className={`${
mobileLayout === 'horizontal' && 'w-5/12 shrink-0 snap-center lg:w-full'
}`}
>
<Card <Card
title={blurb?.title} title={blurb?.title}
link={blurb?.link} link={blurb?.link}
image={blurb?.image} image={blurb?.image}
text={blurb?.text} text={blurb?.text}
imageFormat={blurb?.imageFormat} imageFormat={imageFormat}
/> />
</div> </div>
); );
})} })}
</div> </div>
<div className={`${mobileLayout === 'stacked' ? 'hidden lg:block' : 'block'}`}>
{blurbs && (
<Carousel
gliderClasses={'px-4 lg:px-8 2xl:px-16'}
hasDots={true}
slidesToShow={2.2}
responsive={{
breakpoint: 1024,
settings: {
slidesToShow: sliderLayout <= 4 ? sliderLayout + 0.5 : sliderLayout
}
}}
>
{blurbs.map((blurb: any, index: number) => (
<CarouselItem key={`${index}`}>
<Card
title={blurb?.title}
link={blurb?.link}
image={blurb?.image}
text={blurb.text}
imageFormat={imageFormat}
/>
</CarouselItem>
))}
</Carousel>
)}
</div>
</div> </div>
); );
}; };

View File

@ -1,32 +1,30 @@
'use client' 'use client';
import SanityImage from 'components/ui/sanity-image'
import { cn } from 'lib/utils'
import Link from 'next/link'
import { FC } from 'react'
import SanityImage from 'components/ui/sanity-image';
import { cn } from 'lib/utils';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
import { FC } from 'react';
interface Props { interface Props {
className?: string className?: string;
category: any category: any;
} }
const placeholderImg = '/product-img-placeholder.svg'
const CategoryCard: FC<Props> = ({ category, className }) => { const CategoryCard: FC<Props> = ({ category, className }) => {
const rootClassName = cn( const rootClassName = cn(
'w-1/2 min-w-0 grow-0 shrink-0 group relative box-border overflow-hidden transition-transform ease-linear cursor-pointer basis-[50%]', 'w-1/2 min-w-0 grow-0 shrink-0 group relative box-border overflow-hidden transition-transform ease-linear cursor-pointer basis-[50%]',
className className
) );
const t = useTranslations('routes');
return ( return (
<Link <Link
href={`${category.slug}`} href={`/${t('category')}/${category.slug}`}
className={rootClassName} className={rootClassName}
aria-label={category.name} aria-label={category.name}
> >
<div className={'flex flex-col flex-1 justify-center w-full h-full'}> <div className={'flex h-full w-full flex-1 flex-col justify-center'}>
<div className="w-full h-full aspect-[3/4] relative"> <div className="relative aspect-[3/4] h-full w-full">
<SanityImage <SanityImage
image={category.image} image={category.image}
alt={category.name || 'Category Image'} alt={category.name || 'Category Image'}
@ -34,13 +32,13 @@ const CategoryCard: FC<Props> = ({ category, className }) => {
height={400} height={400}
sizes="(max-width: 1024px) 50vw, 25vw" sizes="(max-width: 1024px) 50vw, 25vw"
/> />
<div className="absolute font-medium bg-high-contrast text-white py-3 px-6 md:py-5 md:px-10 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"> <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} {category.title}
</div> </div>
</div> </div>
</div> </div>
</Link> </Link>
) );
} };
export default CategoryCard export default CategoryCard;

View File

@ -5,6 +5,7 @@ import type { Product } from '@/lib/storm/product';
import Price from 'components/price'; import Price from 'components/price';
import Text from 'components/ui/text'; import Text from 'components/ui/text';
import { cn } from 'lib/utils'; import { cn } from 'lib/utils';
import { useLocale, useTranslations } from 'next-intl';
import Link from 'next/link'; import Link from 'next/link';
import { FC } from 'react'; import { FC } from 'react';
interface Props { interface Props {
@ -15,10 +16,12 @@ interface Props {
const ProductCard: FC<Props> = ({ product, className, variant = 'default' }) => { const ProductCard: FC<Props> = ({ product, className, variant = 'default' }) => {
const rootClassName = cn('w-full group relative overflow-hidden', className); const rootClassName = cn('w-full group relative overflow-hidden', className);
const t = useTranslations('routes');
const locale = useLocale();
return ( return (
<Link <Link
href={`/product/${product.slug}`} href={`/${locale}/${t('product')}/${product.slug}`}
className={rootClassName} className={rootClassName}
aria-label={product.name} aria-label={product.name}
locale={product.locale} locale={product.locale}

View File

@ -1,4 +1,9 @@
{ {
"routes": {
"product": "product",
"category": "category",
"search": "search"
},
"ui": { "ui": {
"button": { "button": {
"close": "Close", "close": "Close",

View File

@ -1,4 +1,9 @@
{ {
"routes": {
"product": "produkt",
"category": "kategori",
"search": "sok"
},
"ui": { "ui": {
"button": { "button": {
"close": "Stäng", "close": "Stäng",

View File

@ -6,7 +6,6 @@ export default createMiddleware({
// 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',
localeDetection: false
}); });
export const config = { export const config = {

View File

@ -5,6 +5,25 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
module.exports = withBundleAnalyzer( module.exports = withBundleAnalyzer(
{ {
async rewrites() {
return [
{
source: '/en/product/:slug',
destination: '/en/produkt/:slug',
locale: false
},
{
source: '/en/category/:slug',
destination: '/en/kategori/:slug',
locale: false
},
{
source: '/en/search',
destination: '/en/sok',
locale: false
},
]
},
eslint: { eslint: {
// Disabling on production builds because we're running checks on PRs via GitHub Actions. // Disabling on production builds because we're running checks on PRs via GitHub Actions.
ignoreDuringBuilds: true ignoreDuringBuilds: true