mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 07:56:59 +00:00
feat: Newsletter signup
This commit is contained in:
parent
0580deda76
commit
9decd30d41
14
.env.example
14
.env.example
@ -1,7 +1,11 @@
|
|||||||
COMPANY_NAME="Vercel Inc."
|
COMPANY_NAME="Suginomori Brewery"
|
||||||
TWITTER_CREATOR="@vercel"
|
TWITTER_SITE="https://narai.jp"
|
||||||
TWITTER_SITE="https://nextjs.org/commerce"
|
SITE_NAME="suginomori brewery"
|
||||||
SITE_NAME="Next.js Commerce"
|
|
||||||
SHOPIFY_REVALIDATION_SECRET=
|
SHOPIFY_REVALIDATION_SECRET=
|
||||||
SHOPIFY_STOREFRONT_ACCESS_TOKEN=
|
SHOPIFY_STOREFRONT_ACCESS_TOKEN=
|
||||||
SHOPIFY_STORE_DOMAIN=
|
SHOPIFY_STORE_DOMAIN=shop.narai.jp
|
||||||
|
NEXT_PUBLIC_GTM_ID=
|
||||||
|
NEXT_PUBLIC_MAILCHIMP_HOST=
|
||||||
|
NEXT_PUBLIC_MAILCHIMP_USER_ID=
|
||||||
|
NEXT_PUBLIC_MAILCHIMP_LIST_ID=
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Navbar from 'components/layout/navbar';
|
import Navbar from 'components/layout/navbar';
|
||||||
import { Locale, i18n } from 'i18n-config';
|
import { Locale, i18n } from 'i18n-config';
|
||||||
|
import { Noto_Sans_JP } from 'next/font/google';
|
||||||
import localFont from 'next/font/local';
|
import localFont from 'next/font/local';
|
||||||
import { ReactNode, Suspense } from 'react';
|
import { ReactNode, Suspense } from 'react';
|
||||||
|
|
||||||
@ -55,6 +56,13 @@ const alpina = localFont({
|
|||||||
variable: '--font-alpina'
|
variable: '--font-alpina'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const noto = Noto_Sans_JP({
|
||||||
|
subsets: ['latin'],
|
||||||
|
display: 'swap',
|
||||||
|
weight: ['300', '600'],
|
||||||
|
variable: '--font-noto'
|
||||||
|
});
|
||||||
|
|
||||||
const mincho = localFont({
|
const mincho = localFont({
|
||||||
src: '../fonts/A-OTF-A1MinchoStd-Bold.otf',
|
src: '../fonts/A-OTF-A1MinchoStd-Bold.otf',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
@ -75,7 +83,7 @@ export default async function RootLayout({
|
|||||||
const dictionary = await getDictionary(params?.lang);
|
const dictionary = await getDictionary(params?.lang);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang={params.lang} className={`${cinzel.variable} ${alpina.variable} ${mincho.variable}`}>
|
<html lang={params.lang} className={`${cinzel.variable} ${alpina.variable} ${noto.variable}`}>
|
||||||
<body className="bg-dark text-white selection:bg-green-800 selection:text-green-400">
|
<body className="bg-dark text-white selection:bg-green-800 selection:text-green-400">
|
||||||
<div className="mx-auto max-w-screen-2xl">
|
<div className="mx-auto max-w-screen-2xl">
|
||||||
<LanguageProvider language={params.lang as Locale} dictionary={dictionary}>
|
<LanguageProvider language={params.lang as Locale} dictionary={dictionary}>
|
||||||
|
@ -5,6 +5,7 @@ import { LanguageControl } from 'components/layout/navbar/language-control';
|
|||||||
import type { Locale } from '../../i18n-config';
|
import type { Locale } from '../../i18n-config';
|
||||||
|
|
||||||
import LogoNamemark from 'components/icons/namemark';
|
import LogoNamemark from 'components/icons/namemark';
|
||||||
|
import NewsletterSignup from 'components/layout/newsletter-signup';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
@ -28,6 +29,9 @@ export default async function HomePage({ params: { lang } }: { params: { lang: L
|
|||||||
<LogoNamemark className="w-[260px] fill-current md:w-[600px]" />
|
<LogoNamemark className="w-[260px] fill-current md:w-[600px]" />
|
||||||
</div>
|
</div>
|
||||||
<ThreeItemGrid lang={lang} />
|
<ThreeItemGrid lang={lang} />
|
||||||
|
<div className="py-24">
|
||||||
|
<NewsletterSignup />
|
||||||
|
</div>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<Carousel />
|
<Carousel />
|
||||||
<Suspense>
|
<Suspense>
|
||||||
|
@ -14,9 +14,9 @@ const Label = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={clsx('@container/label')}>
|
<div className={clsx('@container/label')}>
|
||||||
<div className="font-multilingual flex flex-col space-y-2">
|
<div className="flex flex-col space-y-2">
|
||||||
<h3 className="mr-4 line-clamp-2 flex-grow text-3xl">{title}</h3>
|
<h3 className="mr-4 line-clamp-2 flex-grow font-serif text-3xl md:text-4xl">{title}</h3>
|
||||||
<div className="flex flex-row items-center space-x-2">
|
<div className="font-multilingual flex flex-row items-center space-x-2">
|
||||||
<Price
|
<Price
|
||||||
className="flex-none"
|
className="flex-none"
|
||||||
amount={amount}
|
amount={amount}
|
||||||
|
@ -23,6 +23,7 @@ export const LanguageControl = ({ lang }: { lang?: Locale }) => {
|
|||||||
lang === 'ja' ? 'opacity-100' : 'opacity-50 hover:opacity-70',
|
lang === 'ja' ? 'opacity-100' : 'opacity-50 hover:opacity-70',
|
||||||
'transition-opacity duration-150'
|
'transition-opacity duration-150'
|
||||||
)}
|
)}
|
||||||
|
scroll={false}
|
||||||
>
|
>
|
||||||
JP
|
JP
|
||||||
</Link>
|
</Link>
|
||||||
@ -35,6 +36,7 @@ export const LanguageControl = ({ lang }: { lang?: Locale }) => {
|
|||||||
lang === 'en' ? 'opacity-100' : 'opacity-50 hover:opacity-70',
|
lang === 'en' ? 'opacity-100' : 'opacity-50 hover:opacity-70',
|
||||||
'transition-opacity duration-150'
|
'transition-opacity duration-150'
|
||||||
)}
|
)}
|
||||||
|
scroll={false}
|
||||||
>
|
>
|
||||||
EN
|
EN
|
||||||
</Link>
|
</Link>
|
||||||
|
60
components/layout/newsletter-signup.tsx
Normal file
60
components/layout/newsletter-signup.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
'use client';
|
||||||
|
import { useLanguage } from 'app/context/language-context';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
export default function NewsletterSignup() {
|
||||||
|
const { currentDictionary } = useLanguage();
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-xl space-y-4">
|
||||||
|
<h3 className="font-serif text-2xl tracking-wider">{currentDictionary?.newsletter?.title}</h3>
|
||||||
|
<div className="font-multilingual">{currentDictionary?.newsletter?.description}</div>
|
||||||
|
<form
|
||||||
|
className="max-w-xl 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"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<label htmlFor="email-address" className="sr-only">
|
||||||
|
{currentDictionary.newsletter.placeholder}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email-address"
|
||||||
|
id="email-address"
|
||||||
|
autoComplete="email"
|
||||||
|
required
|
||||||
|
className={clsx(
|
||||||
|
'w-full min-w-0 appearance-none',
|
||||||
|
'outline-none',
|
||||||
|
'px-4 py-2 focus:outline-none',
|
||||||
|
'focus:ring-2 focus:ring-inset focus:ring-emerald-300 focus:ring-offset-0',
|
||||||
|
'text-gray-900 placeholder-gray-400'
|
||||||
|
)}
|
||||||
|
placeholder={currentDictionary.newsletter.placeholder}
|
||||||
|
/>
|
||||||
|
<div className="mt-3 rounded-md sm:ml-3 sm:mt-0 sm:flex-shrink-0">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className={clsx(
|
||||||
|
'px-4 py-2',
|
||||||
|
'transition-colors duration-150',
|
||||||
|
'flex w-full items-center justify-center',
|
||||||
|
'border border-white/30 hover:border-white',
|
||||||
|
'focus:border-emerald-300 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-emerald-300 focus:ring-offset-0'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{currentDictionary.newsletter.button}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div style={{ position: 'absolute', left: '-5000px' }} aria-hidden="true">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name={`b_${process?.env?.NEXT_PUBLIC_MAILCHIMP_USER_ID}_${process?.env?.NEXT_PUBLIC_MAILCHIMP_LIST_ID}`}
|
||||||
|
defaultValue=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -8,5 +8,11 @@
|
|||||||
"stories": "stories",
|
"stories": "stories",
|
||||||
"company": "company",
|
"company": "company",
|
||||||
"contact": "contact"
|
"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.",
|
||||||
|
"placeholder": "Email",
|
||||||
|
"button": "Notify me"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,11 @@
|
|||||||
"stories": "ストーリー",
|
"stories": "ストーリー",
|
||||||
"company": "会社概要",
|
"company": "会社概要",
|
||||||
"contact": "contact"
|
"contact": "contact"
|
||||||
|
},
|
||||||
|
"newsletter": {
|
||||||
|
"title": "newsletter",
|
||||||
|
"description": "ニュースレターにご登録いただくと、初回送料無料クーポン、購読者限定の情報やペアリングディナーなどのご案内をお送りさせていただきます。",
|
||||||
|
"placeholder": "メールアドレス",
|
||||||
|
"button": "登録する"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,9 @@ module.exports = {
|
|||||||
dark: '#212720'
|
dark: '#212720'
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['var(--font-alpina)', 'sans-serif'],
|
serif: ['var(--font-alpina)', 'serif'],
|
||||||
title: ['var(--font-cinzel)', 'sans-serif'],
|
title: ['var(--font-cinzel)', 'serif'],
|
||||||
japan: ['var(--font-mincho)', 'sans-serif']
|
japan: ['var(--font-noto)', 'sans-serif']
|
||||||
},
|
},
|
||||||
aspectRatio: {
|
aspectRatio: {
|
||||||
tall: '596 / 845'
|
tall: '596 / 845'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user