mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 07:56:59 +00:00
wip: Working on footer
This commit is contained in:
parent
ce7f51a600
commit
95d237c4ac
@ -12,7 +12,7 @@ export const revalidate = 43200; // 12 hours in seconds
|
||||
export async function generateMetadata({
|
||||
params
|
||||
}: {
|
||||
params: { page: string; locale: SupportedLocale };
|
||||
params: { page: string; locale?: SupportedLocale };
|
||||
}): Promise<Metadata> {
|
||||
const page = await getPage({ handle: params.page, language: params?.locale?.toUpperCase() });
|
||||
|
||||
@ -32,7 +32,7 @@ export async function generateMetadata({
|
||||
export default async function Page({
|
||||
params
|
||||
}: {
|
||||
params: { page: string; locale: SupportedLocale };
|
||||
params: { page: string; locale?: SupportedLocale };
|
||||
}) {
|
||||
const page = await getPage({ handle: params.page, language: params?.locale?.toUpperCase() });
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Navbar from 'components/layout/navbar';
|
||||
import { Locale } from 'i18n-config';
|
||||
import { Noto_Sans_JP } from 'next/font/google';
|
||||
import { Noto_Serif_JP } from 'next/font/google';
|
||||
import localFont from 'next/font/local';
|
||||
import { ReactNode, Suspense } from 'react';
|
||||
|
||||
import { SupportedLocale } from 'components/layout/navbar/language-control';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { notFound } from 'next/navigation';
|
||||
import './globals.css';
|
||||
@ -56,19 +56,13 @@ const alpina = localFont({
|
||||
variable: '--font-alpina'
|
||||
});
|
||||
|
||||
const noto = Noto_Sans_JP({
|
||||
const noto = Noto_Serif_JP({
|
||||
subsets: ['latin'],
|
||||
display: 'swap',
|
||||
weight: ['300', '600'],
|
||||
variable: '--font-noto'
|
||||
});
|
||||
|
||||
const mincho = localFont({
|
||||
src: '../fonts/A-OTF-A1MinchoStd-Bold.otf',
|
||||
display: 'swap',
|
||||
variable: '--font-mincho'
|
||||
});
|
||||
|
||||
export function generateStaticParams() {
|
||||
return [{ locale: 'en' }, { locale: 'ja' }];
|
||||
}
|
||||
@ -78,7 +72,7 @@ export default async function RootLayout({
|
||||
params
|
||||
}: {
|
||||
children: ReactNode;
|
||||
params: { locale: Locale };
|
||||
params: { locale?: SupportedLocale };
|
||||
}) {
|
||||
let messages;
|
||||
try {
|
||||
|
@ -25,7 +25,7 @@ export const metadata = {
|
||||
export default async function HomePage({
|
||||
params: { locale }
|
||||
}: {
|
||||
params: { locale: SupportedLocale };
|
||||
params: { locale?: SupportedLocale };
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
import LogoNamemark from 'components/icons/namemark';
|
||||
import { SupportedLocale } from 'components/layout/navbar/language-control';
|
||||
import Prose from 'components/prose';
|
||||
import { getPage } from 'lib/shopify';
|
||||
@ -13,9 +14,9 @@ export const revalidate = 43200; // 12 hours in seconds
|
||||
export async function generateMetadata({
|
||||
params
|
||||
}: {
|
||||
params: { page: string; locale: SupportedLocale };
|
||||
params: { locale?: SupportedLocale };
|
||||
}): Promise<Metadata> {
|
||||
const page = await getPage({ handle: params.page, language: params?.locale?.toUpperCase() });
|
||||
const page = await getPage({ handle: 'shop-list', language: params?.locale?.toUpperCase() });
|
||||
|
||||
if (!page) return notFound();
|
||||
|
||||
@ -30,17 +31,16 @@ export async function generateMetadata({
|
||||
};
|
||||
}
|
||||
|
||||
export default async function Page({
|
||||
params
|
||||
}: {
|
||||
params: { page: string; locale: SupportedLocale };
|
||||
}) {
|
||||
const page = await getPage({ handle: params.page, language: params?.locale?.toUpperCase() });
|
||||
export default async function Page({ params }: { params: { locale?: SupportedLocale } }) {
|
||||
const page = await getPage({ handle: 'shop-list', language: params?.locale?.toUpperCase() });
|
||||
|
||||
if (!page) return notFound();
|
||||
|
||||
return (
|
||||
<div className="font-multilingual min-h-screen px-4 text-white">
|
||||
<div className="pb-12">
|
||||
<LogoNamemark className="w-[260px] fill-current md:w-[320px]" />
|
||||
</div>
|
||||
<ShopsTitle />
|
||||
<h2 className="mb-8 text-3xl font-medium">{page.title}</h2>
|
||||
<Prose className="mb-8" html={page.body as string} />
|
@ -35,7 +35,7 @@ function ThreeItemGridItem({ item, priority }: { item: Product; priority?: boole
|
||||
);
|
||||
}
|
||||
|
||||
export async function ThreeItemGrid({ lang }: { lang: SupportedLocale }) {
|
||||
export async function ThreeItemGrid({ lang }: { lang?: SupportedLocale }) {
|
||||
// Collections that start with `hidden-*` are hidden from the search page.
|
||||
const homepageItems = await getCollectionProducts({
|
||||
collection: 'hidden-homepage-featured-items',
|
||||
|
@ -1,46 +1,88 @@
|
||||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { Menu } from 'lib/shopify/types';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const FooterMenuItem = ({ item }: { item: Menu }) => {
|
||||
const pathname = usePathname();
|
||||
const [active, setActive] = useState(pathname === item.path);
|
||||
|
||||
useEffect(() => {
|
||||
setActive(pathname === item.path);
|
||||
}, [pathname, item.path]);
|
||||
export default function FooterMenu() {
|
||||
const t = useTranslations('Index');
|
||||
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
href={item.path}
|
||||
className={clsx(
|
||||
'block p-2 text-lg underline-offset-4 hover:text-black hover:underline dark:hover:text-neutral-300 md:inline-block md:text-sm',
|
||||
{
|
||||
'text-black dark:text-neutral-300': active
|
||||
}
|
||||
)}
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
<div className="hidden md:grid md:w-full md:grid-cols-2">
|
||||
<div className="col-span-1">
|
||||
<div className="mb-4 font-serif text-base underline">{t('menu.title')}</div>
|
||||
<nav className="font-multilingual flex flex-col space-y-2 text-left text-base font-normal">
|
||||
<div>
|
||||
<Link href="/products" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.products')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
export default function FooterMenu({ menu }: { menu: Menu[] }) {
|
||||
if (!menu.length) return null;
|
||||
<div>
|
||||
<Link href="/shop-list" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.shops')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<nav>
|
||||
<ul>
|
||||
{menu.map((item: Menu) => {
|
||||
return <FooterMenuItem key={item.title} item={item} />;
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
<div>
|
||||
<Link href="/about" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.about')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/bar" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.bar')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/concept" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.concept')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/stories" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.stories')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/company" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('menu.company')}
|
||||
</Link>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div className="col-span-1">
|
||||
<div className="mb-4 font-serif text-base underline">{t('shopping-guide.title')}</div>
|
||||
<nav className="font-multilingual flex flex-col space-y-2 text-left text-base font-normal">
|
||||
<div>
|
||||
<Link href="/terms" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('shopping-guide.terms')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/legal" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('shopping-guide.legal')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/privacy" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('shopping-guide.privacy')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/contact" className="transition-opacity duration-150 hover:opacity-50">
|
||||
{t('shopping-guide.contact')}
|
||||
</Link>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { getMenu } from 'lib/shopify';
|
||||
import clsx from 'clsx';
|
||||
import FooterMenu from './footer-menu';
|
||||
import NewsletterFooter from './newsletter-footer';
|
||||
|
||||
const { COMPANY_NAME, SITE_NAME } = process.env;
|
||||
@ -6,16 +7,24 @@ const { COMPANY_NAME, SITE_NAME } = process.env;
|
||||
export default async function Footer() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const copyrightDate = 2023 + (currentYear > 2023 ? `-${currentYear}` : '');
|
||||
const skeleton = 'w-full h-6 animate-pulse rounded bg-neutral-200 dark:bg-neutral-700';
|
||||
const menu = await getMenu('next-js-frontend-footer-menu');
|
||||
const copyrightName = COMPANY_NAME || SITE_NAME || '';
|
||||
|
||||
return (
|
||||
<footer className="text-sm">
|
||||
<div className="mx-auto flex w-full max-w-screen-2xl flex-col gap-6 border-t border-white/20 px-6 py-12 text-sm md:flex-row md:gap-12">
|
||||
<div className="flex flex-row justify-between">
|
||||
<footer className="px-6 text-sm">
|
||||
<div
|
||||
className={clsx(
|
||||
'mx-auto flex w-full max-w-screen-2xl justify-between',
|
||||
'flex-col gap-6 py-12',
|
||||
'border-t border-subtle',
|
||||
'text-sm md:flex-row md:gap-12'
|
||||
)}
|
||||
>
|
||||
<div className="w-full md:w-1/2">
|
||||
<NewsletterFooter />
|
||||
</div>
|
||||
<div className="hidden md:block md:w-1/3">
|
||||
<FooterMenu />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="mx-auto flex w-full max-w-7xl flex-col items-center gap-1 pb-12 md:flex-row">
|
||||
|
@ -68,7 +68,7 @@ export function MenuModal() {
|
||||
|
||||
<div className="fixed inset-0 grid grid-cols-1 place-content-center bg-dark/80">
|
||||
<div className="flex flex-row justify-end">
|
||||
<div className="flex flex-col space-y-4 px-6 text-right">
|
||||
<nav className="flex flex-col space-y-4 px-6 text-right">
|
||||
<div>
|
||||
<Link
|
||||
href="/products"
|
||||
@ -80,7 +80,7 @@ export function MenuModal() {
|
||||
|
||||
<div>
|
||||
<Link
|
||||
href="/shops"
|
||||
href="/shop-list"
|
||||
className="font-serif text-4xl font-normal transition-opacity duration-150 hover:opacity-50"
|
||||
>
|
||||
{t('menu.shops')}
|
||||
@ -140,7 +140,7 @@ export function MenuModal() {
|
||||
{t('menu.contact')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
|
@ -4,7 +4,7 @@ import clsx from 'clsx';
|
||||
import Link from 'next-intl/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
export type SupportedLocale = 'en' | 'ja' | undefined;
|
||||
export type SupportedLocale = 'en' | 'ja';
|
||||
|
||||
function removeItem<T>(arr: Array<T>, value: T): Array<T> {
|
||||
const index = arr.indexOf(value);
|
||||
|
@ -6,13 +6,13 @@ export default function NewsletterSignup() {
|
||||
const t = useTranslations('Index');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-row items-baseline justify-between space-x-6">
|
||||
<div className="max-w-xl">
|
||||
<div className="flex flex-row items-baseline justify-between space-x-6 pb-2">
|
||||
<h3 className="grow font-serif text-2xl tracking-wider">{t('newsletter.title')}</h3>
|
||||
<div className="font-multilingual">{t('footer.newsletter.promo')}</div>
|
||||
</div>
|
||||
<form
|
||||
className="max-w-xl space-x-px md:flex"
|
||||
className="space-x-px md:flex"
|
||||
action={`${process?.env?.NEXT_PUBLIC_MAILCHIMP_HOST}/subscribe/post?u=${process?.env?.NEXT_PUBLIC_MAILCHIMP_USER_ID}&id=${process?.env?.NEXT_PUBLIC_MAILCHIMP_LIST_ID}`}
|
||||
method="post"
|
||||
name="mc-embedded-subscribe-form"
|
||||
|
@ -15,7 +15,7 @@ export default function Shoplist() {
|
||||
</div>
|
||||
<div className="grid w-full grid-cols-2 gap-px">
|
||||
<Link
|
||||
href="shops/hokkaido"
|
||||
href="shop-list/#hokkaido"
|
||||
className="group col-span-1 flex flex-row items-center justify-between p-6 outline outline-1 outline-subtle"
|
||||
>
|
||||
<div>{t('shops.hokkaido')}</div>
|
||||
@ -27,7 +27,7 @@ export default function Shoplist() {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="shops/kanto"
|
||||
href="shop-list/#kanto"
|
||||
className="group col-span-1 flex flex-row items-center justify-between p-6 outline outline-1 outline-subtle"
|
||||
>
|
||||
<div>{t('shops.kanto')}</div>
|
||||
@ -39,7 +39,7 @@ export default function Shoplist() {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="shops/chubu"
|
||||
href="shop-list/#chubu"
|
||||
className="group col-span-1 flex flex-row items-center justify-between p-6 outline outline-1 outline-subtle"
|
||||
>
|
||||
<div>{t('shops.chubu')}</div>
|
||||
@ -51,7 +51,7 @@ export default function Shoplist() {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="shops/kinki"
|
||||
href="shop-list/#kinki"
|
||||
className="group col-span-1 flex flex-row items-center justify-between p-6 outline outline-1 outline-subtle"
|
||||
>
|
||||
<div>{t('shops.kinki')}</div>
|
||||
@ -63,7 +63,7 @@ export default function Shoplist() {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="shops/chugoku"
|
||||
href="shop-list/#chugoku"
|
||||
className="group col-span-1 flex flex-row items-center justify-between p-6 outline outline-1 outline-subtle"
|
||||
>
|
||||
<div>{t('shops.chugoku')}</div>
|
||||
@ -75,7 +75,7 @@ export default function Shoplist() {
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
href="shops/kyushu"
|
||||
href="shop-list/#kyushu"
|
||||
className="group col-span-1 flex flex-row items-center justify-between p-6 outline outline-1 outline-subtle"
|
||||
>
|
||||
<div>{t('shops.kyushu')}</div>
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"Index": {
|
||||
"menu": {
|
||||
"title": "menu",
|
||||
"products": "products",
|
||||
"shops": "shop list",
|
||||
"about": "about narai",
|
||||
@ -10,6 +11,13 @@
|
||||
"company": "company",
|
||||
"contact": "contact"
|
||||
},
|
||||
"shopping-guide": {
|
||||
"title": "shopping guide",
|
||||
"terms": "terms of use",
|
||||
"legal": "legal notice",
|
||||
"privacy": "privacy policy",
|
||||
"contact": "contact"
|
||||
},
|
||||
"newsletter": {
|
||||
"title": "newsletter",
|
||||
"description": "Subscribe to our newsletter to receive free shipping on your first order, and access to exclusive information regarding events and pairing dinners.",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { SupportedLocale } from 'components/layout/navbar/language-control';
|
||||
import 'server-only';
|
||||
import type { Locale } from '../i18n-config';
|
||||
|
||||
// We enumerate all dictionaries here for better linting and typescript support
|
||||
// We also get the default import for cleaner types
|
||||
@ -8,5 +8,5 @@ const dictionaries = {
|
||||
ja: () => import('./ja.json').then((module) => module.default)
|
||||
};
|
||||
|
||||
export const getDictionary = async (locale: Locale) =>
|
||||
export const getDictionary = async (locale: SupportedLocale) =>
|
||||
dictionaries[locale]?.() ?? dictionaries.en();
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"Index": {
|
||||
"menu": {
|
||||
"title": "menu",
|
||||
"products": "商品",
|
||||
"shops": "取り扱い店",
|
||||
"about": "naraiについて",
|
||||
@ -10,6 +11,13 @@
|
||||
"company": "会社概要",
|
||||
"contact": "contact"
|
||||
},
|
||||
"shopping-guide": {
|
||||
"title": "shopping guide",
|
||||
"terms": "利用規約",
|
||||
"legal": "特定商取引法表記",
|
||||
"privacy": "プライバシーポリシー",
|
||||
"contact": "お問い合わせ"
|
||||
},
|
||||
"newsletter": {
|
||||
"title": "newsletter",
|
||||
"description": "ニュースレターにご登録いただくと、初回送料無料クーポン、購読者限定の情報やペアリングディナーなどのご案内をお送りさせていただきます。",
|
||||
|
@ -13,7 +13,7 @@ module.exports = {
|
||||
fontFamily: {
|
||||
serif: ['var(--font-alpina)', 'serif'],
|
||||
title: ['var(--font-cinzel)', 'serif'],
|
||||
japan: ['var(--font-noto)', 'sans-serif']
|
||||
japan: ['var(--font-noto)', 'serif']
|
||||
},
|
||||
aspectRatio: {
|
||||
tall: '596 / 845'
|
||||
|
Loading…
x
Reference in New Issue
Block a user