wip: Working on footer

This commit is contained in:
Sol Irvine 2023-08-18 18:32:01 +09:00
parent ce7f51a600
commit 95d237c4ac
18 changed files with 141 additions and 80 deletions

View File

@ -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() });

View File

@ -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 {

View File

@ -25,7 +25,7 @@ export const metadata = {
export default async function HomePage({
params: { locale }
}: {
params: { locale: SupportedLocale };
params: { locale?: SupportedLocale };
}) {
return (
<>

View File

@ -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} />

View File

@ -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',

View File

@ -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}
<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>
</li>
);
};
</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>
<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>
);
}

View File

@ -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">

View File

@ -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>

View File

@ -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);

View File

@ -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}&amp;id=${process?.env?.NEXT_PUBLIC_MAILCHIMP_LIST_ID}`}
method="post"
name="mc-embedded-subscribe-form"

View File

@ -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>

View File

@ -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.",

View File

@ -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();

View File

@ -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": "ニュースレターにご登録いただくと、初回送料無料クーポン、購読者限定の情報やペアリングディナーなどのご案内をお送りさせていただきます。",

View File

@ -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'