Merge pull request #2 from zenzen-sol/sol/2023-08-23-updates

fix: Various fixes and feedback from previews
This commit is contained in:
Sol Irvine 2023-08-24 18:01:29 +09:00 committed by GitHub
commit 40e20fbc2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 458 additions and 3691 deletions

View File

@ -1,4 +1,4 @@
COMPANY_NAME="Suginomori Brewery"
COMPANY_NAME="suginomori brewery"
TWITTER_SITE="https://narai.jp"
SITE_NAME="suginomori brewery"
SHOPIFY_REVALIDATION_SECRET=

View File

@ -19,30 +19,30 @@ module.exports = {
case: 'kebabCase'
}
],
"prettier/prettier": "warn",
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
"no-template-curly-in-string": "error",
"unused-imports/no-unused-vars": [
"warn",
'prettier/prettier': 'warn',
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
'no-template-curly-in-string': 'error',
'unused-imports/no-unused-vars': [
'warn',
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_'
}
]
},
"settings": {
"tailwindcss": {
"config": "./tailwind.config.js",
"callees": ["cx"]
settings: {
tailwindcss: {
config: './tailwind.config.js',
callees: ['cx']
},
"tailwindcss/classnames-order": [
'tailwindcss/classnames-order': [
true,
{
"callees": ["cx"],
"config": "./tailwind.config.js"
callees: ['cx'],
config: './tailwind.config.js'
}
]
}

Binary file not shown.

View File

@ -80,18 +80,12 @@ Once installed, you'll need to create a `SHOPIFY_STOREFRONT_ACCESS_TOKEN` enviro
<summary>Expand to view detailed walkthrough</summary>
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/settings/apps`.
1. Click the green `Shopify App Store` button.
![Shopify App Store](https://user-images.githubusercontent.com/446260/233220545-cb4c1461-ebc5-424e-a421-bf0d32044027.jpg)
1. Search for `Headless` and click on the `Headless` app.
![Headless](https://user-images.githubusercontent.com/446260/233220547-6d93b5ef-16c7-45db-99e7-13ae7e18eb39.jpg)
1. Click the black `Add app` button.
![Add app](https://user-images.githubusercontent.com/446260/233220550-a34c8bda-75a8-437a-9673-125f3794ff35.jpg)
1. Click the green `Add sales channel` button.
![Add sales channel](https://user-images.githubusercontent.com/446260/233220553-42d94a74-421d-4f8a-99ab-a95936b707a3.jpg)
1. Click the green `Create storefront` button.
![Create storefront](https://user-images.githubusercontent.com/446260/233220556-1eee15c4-a45d-446e-9f73-2e7c9f56b29c.jpg)
1. Copy and paste the public access token and assign it to a `SHOPIFY_STOREFRONT_ACCESS_TOKEN` environment variable.
![Pubic access token](https://user-images.githubusercontent.com/446260/233220558-5db04ff9-b894-40fe-bfba-0e92f26b8e1f.jpg)
1. Click the green `Shopify App Store` button. ![Shopify App Store](https://user-images.githubusercontent.com/446260/233220545-cb4c1461-ebc5-424e-a421-bf0d32044027.jpg)
1. Search for `Headless` and click on the `Headless` app. ![Headless](https://user-images.githubusercontent.com/446260/233220547-6d93b5ef-16c7-45db-99e7-13ae7e18eb39.jpg)
1. Click the black `Add app` button. ![Add app](https://user-images.githubusercontent.com/446260/233220550-a34c8bda-75a8-437a-9673-125f3794ff35.jpg)
1. Click the green `Add sales channel` button. ![Add sales channel](https://user-images.githubusercontent.com/446260/233220553-42d94a74-421d-4f8a-99ab-a95936b707a3.jpg)
1. Click the green `Create storefront` button. ![Create storefront](https://user-images.githubusercontent.com/446260/233220556-1eee15c4-a45d-446e-9f73-2e7c9f56b29c.jpg)
1. Copy and paste the public access token and assign it to a `SHOPIFY_STOREFRONT_ACCESS_TOKEN` environment variable. ![Pubic access token](https://user-images.githubusercontent.com/446260/233220558-5db04ff9-b894-40fe-bfba-0e92f26b8e1f.jpg)
1. If you ever need to reference the public access token again, you can navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/headless_storefronts`.
</details>
@ -106,21 +100,14 @@ Follow the installation instructions and configure the theme with your headless
<details>
<summary>Expand to view detailed walkthrough</summary>
1. Download [Shopify Headless Theme](https://github.com/instantcommerce/shopify-headless-theme).
![Download Shoify Headless Theme](https://user-images.githubusercontent.com/446260/233220560-9f3f5ab0-ffb4-4305-b4ee-2c9d33eea90f.jpg)
1. Download [Shopify Headless Theme](https://github.com/instantcommerce/shopify-headless-theme). ![Download Shoify Headless Theme](https://user-images.githubusercontent.com/446260/233220560-9f3f5ab0-ffb4-4305-b4ee-2c9d33eea90f.jpg)
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/themes`.
1. Click `Add theme`, then `Upload zip file`.
![Upload zip file](https://user-images.githubusercontent.com/446260/233220561-7a53809e-0d95-45eb-b52f-3a52e3663a9c.jpg)
1. Select the downloaded zip file from above, and click the green `Upload file` button.
![Select and upload file](https://user-images.githubusercontent.com/446260/233220563-135fb9f7-2921-4189-8f17-3b1cc15c0ea6.jpg)
1. Click `Customize`.
![Customize theme](https://user-images.githubusercontent.com/446260/233220565-24b9c954-c18a-46f1-9db5-3d2a00040e48.jpg)
1. Click `Theme settings` (ie. the paintbrush icon), expand the `STOREFRONT` section, enter your headless store domain, click the gray `Publish` button.
![Set headless domain in theme settings](https://user-images.githubusercontent.com/446260/233220566-acaee14d-03f8-400d-a2a2-28e85eb5ecdc.jpg)
1. Confirm the theme change by clicking the green `Save and publish` button.
![Confirm save and publish](https://user-images.githubusercontent.com/446260/233220567-504d5bde-cfb9-426d-a264-f9a12d02af13.jpg)
1. The headless theme should now be your current active theme.
![Headless theme is current and active](https://user-images.githubusercontent.com/446260/233220569-63cab2b4-241b-4bf1-9b5b-451daaeceb91.jpg)
1. Click `Add theme`, then `Upload zip file`. ![Upload zip file](https://user-images.githubusercontent.com/446260/233220561-7a53809e-0d95-45eb-b52f-3a52e3663a9c.jpg)
1. Select the downloaded zip file from above, and click the green `Upload file` button. ![Select and upload file](https://user-images.githubusercontent.com/446260/233220563-135fb9f7-2921-4189-8f17-3b1cc15c0ea6.jpg)
1. Click `Customize`. ![Customize theme](https://user-images.githubusercontent.com/446260/233220565-24b9c954-c18a-46f1-9db5-3d2a00040e48.jpg)
1. Click `Theme settings` (ie. the paintbrush icon), expand the `STOREFRONT` section, enter your headless store domain, click the gray `Publish` button. ![Set headless domain in theme settings](https://user-images.githubusercontent.com/446260/233220566-acaee14d-03f8-400d-a2a2-28e85eb5ecdc.jpg)
1. Confirm the theme change by clicking the green `Save and publish` button. ![Confirm save and publish](https://user-images.githubusercontent.com/446260/233220567-504d5bde-cfb9-426d-a264-f9a12d02af13.jpg)
1. The headless theme should now be your current active theme. ![Headless theme is current and active](https://user-images.githubusercontent.com/446260/233220569-63cab2b4-241b-4bf1-9b5b-451daaeceb91.jpg)
</details>
### Branding & Design
@ -141,27 +128,21 @@ You can use Shopify's admin to customize these pages to match your brand and des
#### Checkout, order status, and order history
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/settings/checkout`.
1. Click the green `Customize` button.
![Customize](https://user-images.githubusercontent.com/446260/233220530-9beda4b4-5008-440a-b923-9d196b722539.jpg)
1. Click `Branding` (ie. the paintbrush icon) and customize your brand. Please note, there are three steps / pages to the checkout flow. Use the dropdown to change pages and adjust branding as needed on each page. Click `Save` when you are done.
![Branding](https://user-images.githubusercontent.com/446260/233220534-e884d9fd-1a39-4f4d-9d09-163dde47c2e8.jpg)
1. Click the green `Customize` button. ![Customize](https://user-images.githubusercontent.com/446260/233220530-9beda4b4-5008-440a-b923-9d196b722539.jpg)
1. Click `Branding` (ie. the paintbrush icon) and customize your brand. Please note, there are three steps / pages to the checkout flow. Use the dropdown to change pages and adjust branding as needed on each page. Click `Save` when you are done. ![Branding](https://user-images.githubusercontent.com/446260/233220534-e884d9fd-1a39-4f4d-9d09-163dde47c2e8.jpg)
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/settings/branding`.
1. Customize settings to match your brand.
![Branding](https://user-images.githubusercontent.com/446260/233220536-452b8802-9a1e-40f0-9a12-52b3dace84a5.jpg)
1. Customize settings to match your brand. ![Branding](https://user-images.githubusercontent.com/446260/233220536-452b8802-9a1e-40f0-9a12-52b3dace84a5.jpg)
#### Emails
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/settings/email_settings`.
1. Customize settings to match your brand.
![Branding](https://user-images.githubusercontent.com/446260/233220538-13c83a9e-55f8-41e6-9b34-a39ee0848a8a.jpg)
1. Customize settings to match your brand. ![Branding](https://user-images.githubusercontent.com/446260/233220538-13c83a9e-55f8-41e6-9b34-a39ee0848a8a.jpg)
#### Favicon
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/themes`.
1. Click the green `Customize` button.
![Customize theme](https://user-images.githubusercontent.com/446260/233220539-4869a6cd-f59f-4de6-8091-95ed81d2302d.jpg)
1. Click `Theme settings` (ie. the paintbrush icon), expand the `FAVICON` section, upload favicon, then click the `Save` button.
![Favicon](https://user-images.githubusercontent.com/446260/233220542-ac81b674-d86e-4172-ab38-c79d1ad1ff36.jpg)
1. Click the green `Customize` button. ![Customize theme](https://user-images.githubusercontent.com/446260/233220539-4869a6cd-f59f-4de6-8091-95ed81d2302d.jpg)
1. Click `Theme settings` (ie. the paintbrush icon), expand the `FAVICON` section, upload favicon, then click the `Save` button. ![Favicon](https://user-images.githubusercontent.com/446260/233220542-ac81b674-d86e-4172-ab38-c79d1ad1ff36.jpg)
</details>
@ -189,9 +170,7 @@ Next.js is pre-configured to listen for the following Shopify webhook events and
#### Configure Shopify webhooks
1. Navigate to `https://[your-shopify-store-subdomain].myshopify.com/admin/settings/notifications`.
1. Add webhooks for all six event topics listed above. You can add more sets for other preview urls, environments, or local development. Append `?secret=[SECRET]` to each url, where `[SECRET]` is the secret you created above.
![Shopify store webhooks](https://github.com/vercel/commerce/assets/446260/3d713fd7-b642-46e2-b2ce-f2b695ff6d2b)
![Shopify store add webhook](https://github.com/vercel/commerce/assets/446260/f0240a22-be07-42bc-bf6c-b97873868677)
1. Add webhooks for all six event topics listed above. You can add more sets for other preview urls, environments, or local development. Append `?secret=[SECRET]` to each url, where `[SECRET]` is the secret you created above. ![Shopify store webhooks](https://github.com/vercel/commerce/assets/446260/3d713fd7-b642-46e2-b2ce-f2b695ff6d2b) ![Shopify store add webhook](https://github.com/vercel/commerce/assets/446260/f0240a22-be07-42bc-bf6c-b97873868677)
#### Testing webhooks during local development
@ -200,11 +179,8 @@ The easiest way to test webhooks while developing locally is to use [ngrok](http
1. [Install and configure ngrok](https://ngrok.com/download) (you will need to create an account).
1. Run your app locally, `npm run dev`.
1. In a separate terminal session, run `ngrok http 3000`.
1. Use the url generated by ngrok and add or update your webhook urls in Shopify.
![ngrok](https://github.com/vercel/commerce/assets/446260/5dc09c5d-0e48-479c-ab64-de8dc9a2c4b1)
![Shopify store edit webhook](https://github.com/vercel/commerce/assets/446260/13fd397d-4666-4e8d-b25f-4adc674345c0)
1. You can now make changes to your store and your local app should receive updates. You can also use the `Send test notification` button to trigger a generic webhook test.
![Shopify store webhook send test notification](https://github.com/vercel/commerce/assets/446260/e872e233-1663-446d-961f-8c9455358530)
1. Use the url generated by ngrok and add or update your webhook urls in Shopify. ![ngrok](https://github.com/vercel/commerce/assets/446260/5dc09c5d-0e48-479c-ab64-de8dc9a2c4b1) ![Shopify store edit webhook](https://github.com/vercel/commerce/assets/446260/13fd397d-4666-4e8d-b25f-4adc674345c0)
1. You can now make changes to your store and your local app should receive updates. You can also use the `Send test notification` button to trigger a generic webhook test. ![Shopify store webhook send test notification](https://github.com/vercel/commerce/assets/446260/e872e233-1663-446d-961f-8c9455358530)
</details>

View File

@ -16,12 +16,12 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
return (
<div className="w-full px-6">
<div className="font-multilingual flex w-full flex-col items-center space-y-2 pb-24 text-center font-extralight md:pb-48">
<div className="font-multilingual flex w-full flex-col items-center space-y-px pb-24 text-center font-extralight md:pb-48">
<h1 className="text-6xl">{t('about.001.title')}</h1>
<h1 className="text-6xl">{t('about.001.subtitle')}</h1>
</div>
<div className="max-w-screen-2x relative mx-auto">
<div className="relative mx-auto max-w-screen-2xl">
<Image
src={AboutImage001}
priority={true}
@ -39,7 +39,7 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
<p className="text-base leading-loose">{t('about.002.para002')}</p>
</div>
<div className="max-w-screen-2x relative mx-auto">
<div className="relative mx-auto max-w-screen-2xl">
<Image
src={AboutImage002}
priority={true}
@ -78,7 +78,7 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
>
<div className="font-multilingual flex flex-row items-baseline space-x-4">
<h2 className="text-5xl">{t('about.awards.title')}</h2>
<h3 className="text-2xl font-extralight">{t('about.awards.subtitle')}</h3>
<h3 className="text-xl font-extralight">{t('about.awards.subtitle')}</h3>
</div>
<div className="border-y border-white/20 py-12">
@ -94,7 +94,10 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
>
<div className="flex flex-col space-y-24">
<div className="font-multilingual font-extralight">
<div className="flex flex-row items-baseline space-x-3">
<h2 className="text-5xl">{t('about.materials.title')}</h2>
<h2 className="text-4xl">{t('about.materials.subtitle')}</h2>
</div>
</div>
<Image
@ -106,10 +109,12 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
<div className="font-multilingual flex flex-col space-y-12 font-extralight md:flex-row md:space-x-6 md:space-y-0">
<div className="md:w-1/2">
<h2 className="max-w-sm text-5xl">{t('about.materials.water.title')}</h2>
<h2 className="max-w-title text-3xl leading-normal">
{t('about.materials.water.title')}
</h2>
</div>
<div className="md:w-1/2">
<p className="text-xl leading-relaxed">{t('about.materials.water.body')}</p>
<p className="text-base leading-relaxed">{t('about.materials.water.body')}</p>
</div>
</div>
</div>
@ -124,10 +129,12 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
<div className="font-multilingual flex flex-col space-y-12 font-extralight md:flex-row md:space-x-6 md:space-y-0">
<div className="md:w-1/2">
<h2 className="max-w-sm text-5xl">{t('about.materials.rice.title')}</h2>
<h2 className="max-w-title text-3xl leading-normal">
{t('about.materials.rice.title')}
</h2>
</div>
<div className="md:w-1/2">
<p className="text-xl leading-relaxed">{t('about.materials.rice.body')}</p>
<p className="text-base leading-relaxed">{t('about.materials.rice.body')}</p>
</div>
</div>
</div>
@ -142,10 +149,12 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
<div className="font-multilingual flex flex-col space-y-12 font-extralight md:flex-row md:space-x-6 md:space-y-0">
<div className="md:w-1/2">
<h2 className="max-w-sm text-5xl">{t('about.materials.koji.title')}</h2>
<h2 className="max-w-title text-3xl leading-normal">
{t('about.materials.koji.title')}
</h2>
</div>
<div className="md:w-1/2">
<p className="text-xl leading-relaxed">{t('about.materials.koji.body')}</p>
<p className="text-base leading-relaxed">{t('about.materials.koji.body')}</p>
</div>
</div>
</div>
@ -156,8 +165,8 @@ export default function AboutNaraiDetail({ awards }: { awards: string }) {
<div className="border-t border-white/20"></div>
</div>
<div className="font-multilingual max-w-xl font-extralight">
<p className="text-xl">{t('about.irie.title')}</p>
<p className="text-xl leading-relaxed">{t('about.irie.body')}</p>
<p className="text-lg">{t('about.irie.title')}</p>
<p className="text-lg leading-relaxed">{t('about.irie.body')}</p>
</div>
<Image

View File

@ -15,7 +15,7 @@ export default function SagyobarDetail() {
return (
<div className="w-full px-6">
<div className="max-w-screen-2x relative mx-auto">
<div className="relative mx-auto max-w-screen-2xl">
<Image
src={BarImage001}
priority={true}
@ -29,9 +29,10 @@ export default function SagyobarDetail() {
'font-multilingual mx-auto flex w-full flex-col space-y-12 py-12 text-left font-extralight md:flex-row md:space-x-6 md:space-y-0 md:py-24 md:pb-24'
)}
>
<div className="md:w-1/2">
<h2 className="max-w-sm text-4xl md:text-5xl">{t('bar.001.title')}</h2>
<h2 className="max-w-sm text-4xl md:text-5xl">{t('bar.001.subtitle')}</h2>
<div className="flex flex-col space-y-4 md:w-1/2">
<h2 className="max-w-sm text-4xl md:text-5xl">{t('bar.001.title.line001')}</h2>
<h2 className="max-w-sm text-4xl md:text-5xl">{t('bar.001.title.line002')}</h2>
<h2 className="max-w-sm text-4xl md:text-5xl">{t('bar.001.title.line003')}</h2>
</div>
<div className="flex flex-col space-y-12 md:w-1/2">
<p className="text-base leading-loose">{t('bar.001.para001')}</p>
@ -39,7 +40,7 @@ export default function SagyobarDetail() {
</div>
</div>
<div className="max-w-screen-2x relative mx-auto flex flex-col space-y-24">
<div className="relative mx-auto flex max-w-screen-2xl flex-col space-y-24">
<Image
src={BarImage002}
priority={true}
@ -95,13 +96,13 @@ export default function SagyobarDetail() {
<div className="h-4 w-4 rounded-full bg-white"></div>
<p className="text-xl">{t('bar.access.title')}</p>
</div>
<p className="text-base leading-relaxed">{t('bar.access.para001')}</p>
<p className="text-base leading-relaxed">{t('bar.access.para002')}</p>
<p className="text-base leading-relaxed">{t('bar.access.para003')}</p>
<p className="text-base leading-relaxed">{t('bar.access.para004')}</p>
<p className="text-base leading-relaxed">{t('bar.access.para005')}</p>
<p className="text-base leading-relaxed">{t('bar.access.para006')}</p>
<p className="text-base leading-relaxed">{t('bar.access.para007')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para001')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para002')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para003')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para004')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para005')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para006')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.access.para007')}</p>
</div>
</div>
@ -111,9 +112,9 @@ export default function SagyobarDetail() {
<div className="h-4 w-4 rounded-full bg-white"></div>
<p className="text-xl">{t('bar.hours.title')}</p>
</div>
<p className="pb-6 text-base leading-relaxed">{t('bar.hours.para001')}</p>
<p className="text-base leading-relaxed">{t('bar.hours.para002')}</p>
<p className="text-base leading-relaxed">{t('bar.hours.para003')}</p>
<p className="pb-6 text-[15px] leading-relaxed">{t('bar.hours.para001')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.hours.para002')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.hours.para003')}</p>
</div>
</div>
@ -123,8 +124,11 @@ export default function SagyobarDetail() {
<div className="h-4 w-4 rounded-full bg-white"></div>
<p className="text-xl">{t('bar.menu.title')}</p>
</div>
<p className="pb-6 text-base leading-relaxed">
<Link href="/menu" className="transition-opacity duration-150 hover:opacity-90">
<p className="pb-6 text-[15px] leading-relaxed">
<Link
href="https://cdn.shopify.com/s/files/1/0578/5570/5261/files/sagyobar_menu.pdf?v=1692861259"
className="transition-opacity duration-150 hover:opacity-90"
>
{t('bar.menu.para001')}
</Link>
</p>
@ -136,8 +140,8 @@ export default function SagyobarDetail() {
<div className="border-t border-white/20"></div>
</div>
<div className="font-multilingual max-w-xl font-extralight">
<p className="text-xl">{t('bar.clerk.title')}</p>
<p className="text-xl leading-relaxed">{t('bar.clerk.body')}</p>
<p className="text-[15px]">{t('bar.clerk.title')}</p>
<p className="text-[15px] leading-relaxed">{t('bar.clerk.body')}</p>
</div>
<Image

View File

@ -30,7 +30,7 @@ export default function CompanyDetail() {
<div>
<h3 className="text-2xl">{t('company.subtitle001')}</h3>
<ul className="font-multilingual flex flex-col space-y-4 py-4 text-xl font-extralight">
<ul className="font-multilingual flex flex-col space-y-4 py-4 text-base font-extralight">
<li className="border-t border-white/20 py-4">
<div className="flex flex-col space-y-2 md:flex-row md:space-x-3 md:space-y-0">
<div className="w-1/3">{t('company.name.label')}</div>
@ -67,7 +67,7 @@ export default function CompanyDetail() {
<div>
<h3 className="pb-4 text-2xl">{t('company.subtitle002')}</h3>
<div className="grid grid-cols-1 gap-4 border-t border-white/20 md:grid-cols-3">
<div className="font-multilingual col-span-1 py-4 text-lg font-extralight">
<div className="font-multilingual col-span-1 py-4 text-base font-extralight">
<div className="relative aspect-square">
<Image
src={CompanyImage001}
@ -78,7 +78,7 @@ export default function CompanyDetail() {
</div>
<div className="pt-2">{t('company.irie.japanese')}</div>
<div className="pb-4">{t('company.irie.english')}</div>
<div className="text-base">{t('company.irie.role')}</div>
<div className="text-sm">{t('company.irie.role')}</div>
</div>
<div className="font-multilingual col-span-1 py-4 text-lg font-extralight">
@ -92,7 +92,7 @@ export default function CompanyDetail() {
</div>
<div className="pt-2">{t('company.nishikawa.japanese')}</div>
<div className="pb-4">{t('company.nishikawa.english')}</div>
<div className="text-base">{t('company.nishikawa.role')}</div>
<div className="text-sm">{t('company.nishikawa.role')}</div>
</div>
<div className="font-multilingual col-span-1 py-4 text-lg font-extralight">
@ -106,7 +106,7 @@ export default function CompanyDetail() {
</div>
<div className="pt-2">{t('company.sundberg.japanese')}</div>
<div className="pb-4">{t('company.sundberg.english')}</div>
<div className="text-base">{t('company.sundberg.role')}</div>
<div className="text-sm">{t('company.sundberg.role')}</div>
</div>
<div className="font-multilingual col-span-1 py-4 text-lg font-extralight">
@ -120,7 +120,7 @@ export default function CompanyDetail() {
</div>
<div className="pt-2">{t('company.yamano.japanese')}</div>
<div className="pb-4">{t('company.yamano.english')}</div>
<div className="text-base">{t('company.yamano.role')}</div>
<div className="text-sm">{t('company.yamano.role')}</div>
</div>
<div className="font-multilingual col-span-1 py-4 text-lg font-extralight">
@ -134,7 +134,7 @@ export default function CompanyDetail() {
</div>
<div className="pt-2">{t('company.yoshida.japanese')}</div>
<div className="pb-4">{t('company.yoshida.english')}</div>
<div className="text-base">{t('company.yoshida.role')}</div>
<div className="text-sm">{t('company.yoshida.role')}</div>
</div>
<div className="font-multilingual col-span-1 py-4 text-lg font-extralight">
@ -148,7 +148,7 @@ export default function CompanyDetail() {
</div>
<div className="pt-2">{t('company.ikegaya.japanese')}</div>
<div className="pb-4">{t('company.ikegaya.english')}</div>
<div className="text-base">{t('company.ikegaya.role')}</div>
<div className="text-sm">{t('company.ikegaya.role')}</div>
</div>
</div>
</div>

View File

@ -11,7 +11,7 @@ export default function ConceptDetail() {
return (
<div className="w-full px-6">
<div className="max-w-screen-2x relative mx-auto">
<div className="relative mx-auto max-w-screen-2xl">
<Image
src={ConceptImage001}
priority={true}
@ -29,24 +29,24 @@ export default function ConceptDetail() {
>
<div className="md:w-1/2">
<h2 className="max-w-sm pb-12 text-4xl md:text-5xl">{t('concept.title')}</h2>
<p className="font-multilingual text-lg font-extralight">
<p className="font-multilingual text-base font-extralight">
{t('concept.para001')} {t('concept.para002')} {t('concept.para003')}
</p>
<div className="font-multilingual pt-24 font-extralight">
<p className="pb-6 text-xl font-normal">{t('concept.subtitle001')}</p>
<p className="pb-24 text-lg leading-relaxed">{t('concept.para004')}</p>
<p className="pb-24 text-base leading-relaxed">{t('concept.para004')}</p>
<p className="pb-6 text-xl font-normal">{t('concept.subtitle002')}</p>
<p className="pb-4 text-lg leading-relaxed">{t('concept.para005')}</p>
<p className="pb-4 text-lg leading-relaxed">
<p className="pb-4 text-base leading-relaxed">{t('concept.para005')}</p>
<p className="pb-4 text-base leading-relaxed">
{t('concept.para006')} {t('concept.para007')} {t('concept.para008')}
</p>
<p className="pb-4 text-lg leading-relaxed">{t('concept.para009')}</p>
<p className="text-lg leading-relaxed">{t('concept.para010')}</p>
<p className="pb-4 text-base leading-relaxed">{t('concept.para009')}</p>
<p className="text-base leading-relaxed">{t('concept.para010')}</p>
</div>
</div>
<div className="flex flex-row items-start justify-end md:w-1/2">
<div className="pb-24">
<Logo className="h-30 w-48" />
<Logo className="h-32 w-48" />
</div>
</div>
</div>

View File

@ -12,8 +12,8 @@ export default function Disclosures() {
{t('disclosurePage.title')}
</h4>
<div className="mx-auto max-w-4xl">
<div className="font-multilingual my-12 text-lg">
<section className="font-multilingual mb-36 mt-12 flex flex-col space-y-6 text-lg md:space-y-3">
<div className="font-multilingual my-12">
<section className="font-multilingual mb-36 mt-12 flex flex-col space-y-6 text-base md:space-y-3">
<div className="flex flex-col space-y-2 md:flex-row md:space-x-3 md:space-y-0">
<div className="md:w-1/3">{t('disclosurePage.distributor.label')}</div>
<div className="md:w-2/3">

View File

@ -25,5 +25,5 @@ button {
}
[lang='ja'] .font-multilingual {
@apply font-japan;
@apply font-japan tracking-widest;
}

View File

@ -1,4 +1,3 @@
import { ThreeItemGrid } from 'components/grid/three-items';
import Footer from 'components/layout/footer';
import { SupportedLocale } from 'components/layout/navbar/language-control';
@ -11,6 +10,7 @@ import HomeImage006 from '@images/home-images/home-image-006.webp';
import HomeImage007 from '@images/home-images/home-image-007.webp';
import HomeImage008 from '@images/home-images/home-image-008.webp';
import clsx from 'clsx';
import { HomepageProducts } from 'components/grid/homepage-products';
import AboutNaraiPreview from 'components/layout/about-narai-preview';
import ConceptPreview from 'components/layout/concept-preview';
import LocationPreview from 'components/layout/location-preview';
@ -18,7 +18,7 @@ import Navbar from 'components/layout/navbar';
import NewsletterSignup from 'components/layout/newsletter-signup';
import SagyobarPreview from 'components/layout/sagyobar-preview';
import Shoplist from 'components/layout/shoplist';
import Stories from 'components/layout/stories';
import StoriesPreview from 'components/layout/stories-preview';
import { BLOG_HANDLE } from 'lib/constants';
import { getCart } from 'lib/shopify';
import { cookies } from 'next/headers';
@ -52,7 +52,7 @@ export default async function HomePage({
<div>
<Navbar cart={cart} locale={locale} />
<div className="pt-12 md:pt-48">
<ThreeItemGrid lang={locale} />
<HomepageProducts lang={locale} />
</div>
<div className="py-48">
<NewsletterSignup />
@ -132,7 +132,7 @@ export default async function HomePage({
</div>
<div className="relative">
<Stories handle={BLOG_HANDLE} articles={3} locale={locale} more />
<StoriesPreview handle={BLOG_HANDLE} articles={3} locale={locale} more />
</div>
<div className="relative">

View File

@ -7,11 +7,11 @@ export default function PrivacyPolicy() {
return (
<>
<div className="mx-auto max-w-3xl text-white">
<div className="md:text-4x text-center font-serif text-3xl font-bold leading-tight text-white md:mb-16">
<div className="text-center font-serif text-3xl font-bold leading-tight text-white md:mb-16 md:text-4xl">
{t('privacy.title')}
</div>
<div className="mb-24 text-lg leading-normal">
<div className="text-sb-highlight text-center">{t('privacy.lastModifiedDate')}</div>
<div className="text-center">{t('privacy.lastModifiedDate')}</div>
<div className="mt-4">
<p>{t('privacy.pleaseRead')}</p>
<p className="mt-4">{t('privacy.usedFor')}</p>

View File

@ -2,6 +2,7 @@ import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { Suspense } from 'react';
import clsx from 'clsx';
import { AddToCart } from 'components/cart/add-to-cart';
import { GridTileImage } from 'components/grid/tile';
import Label from 'components/label';
@ -64,13 +65,16 @@ export default async function ProductPage({
}: {
params: { handle: string; locale?: SupportedLocale };
}) {
const numberOfOtherImages = 3;
const product = await getProduct({
handle: params.handle,
language: params?.locale?.toUpperCase()
});
let otherImages: MediaImage[] = [];
if (!!product) {
otherImages = product.images.filter((image) => image?.url !== product.featuredImage?.url);
otherImages = product.images
.slice(0, numberOfOtherImages + 1) // +1 to account for featured image
.filter((image) => image?.url !== product.featuredImage?.url);
}
if (!product) return notFound();
@ -102,7 +106,7 @@ export default async function ProductPage({
/>
<div className="mx-auto max-w-screen-xl py-24">
<div className="flex flex-col space-y-12">
<div className="relative aspect-square h-full w-full">
<div className="relative h-full w-full">
<Image
src={product.featuredImage?.url}
alt={product.featuredImage?.altText}
@ -147,8 +151,18 @@ export default async function ProductPage({
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{!!otherImages &&
otherImages?.length > 0 &&
otherImages.map((image) => (
<div key={image.url} className="relative aspect-square h-full w-full">
otherImages.map((image, index) => {
const isOdd = otherImages.length % 2 != 0;
const isLast = index === otherImages.length - 1;
const isOddAndLast = isOdd && isLast;
return (
<div
key={image.url}
className={clsx(
isOddAndLast ? 'col-span-2' : 'col-span-1 aspect-square',
'relative h-full w-full bg-gray-900/10'
)}
>
<Image
src={image.url}
alt={image.altText}
@ -157,7 +171,8 @@ export default async function ProductPage({
className="h-full w-full object-cover"
/>
</div>
))}
);
})}
</div>
<Suspense>
<RelatedProducts id={product.id} />

View File

@ -1,7 +1,7 @@
import { ThreeItemGrid } from 'components/grid/three-items';
import Footer from 'components/layout/footer';
import { SupportedLocale } from 'components/layout/navbar/language-control';
import { ProductGrid } from 'components/grid/product-grid';
import Navbar from 'components/layout/navbar';
import { getCart } from 'lib/shopify';
import { cookies } from 'next/headers';
@ -36,7 +36,7 @@ export default async function ProductPage({
<div>
<Navbar cart={cart} locale={locale} compact />
<div className="py-24 md:py-48">
<ThreeItemGrid lang={locale} />
<ProductGrid lang={locale} />
</div>
<Suspense>

View File

@ -8,7 +8,7 @@ import { getCart, getPage } from 'lib/shopify';
import { cookies } from 'next/headers';
import { notFound } from 'next/navigation';
import { Suspense } from 'react';
import ShopsTitle from './ShopsTitle';
import ShopsNav from './shops-nav';
export const runtime = 'edge';
@ -50,9 +50,9 @@ export default async function Page({ params }: { params: { locale?: SupportedLoc
<div>
<Navbar cart={cart} locale={params?.locale} compact />
<div className="mx-auto max-w-xl px-6 pb-24 pt-12 md:pb-48 md:pt-24">
<ShopsTitle />
<h2 className="mb-8 text-3xl font-medium">{page.title}</h2>
<Prose className="" html={page.body as string} />
<ShopsNav />
<h2 className="font-multilingual mb-8 text-3xl font-medium">{page.title}</h2>
<Prose html={page.body as string} />
</div>
<Suspense>

View File

@ -3,11 +3,11 @@
import { useTranslations } from 'next-intl';
import Link from 'next/link';
export default function ShopsTitle() {
export default function ShopsNav() {
const t = useTranslations('Index');
return (
<div>
<div className="flex flex-row items-baseline space-x-6 pb-12">
<div className="font-multilingual flex flex-row items-baseline space-x-6 pb-12">
<Link href="/#shops">
<span className="flex flex-row items-center space-x-1.5">
<span></span>
@ -15,7 +15,7 @@ export default function ShopsTitle() {
</span>
</Link>
<div>|</div>
<div className="font-medium">{t('shops.title')}</div>
<div className="font-multilingual font-medium">{t('shops.title')}</div>
</div>
</div>
);

View File

@ -127,7 +127,6 @@ export default function TermsOfUse() {
{t('terms.contactUs.instructions')}
<a
href={`mailto:${t('email-address.support')}`}
className="branded-link"
aria-label={t('privacy.contactUs.ariaLabel')}
>
{t('email-address.support')}

View File

@ -37,7 +37,7 @@ export default function DeleteItemButton({ item }: { item: CartItem }) {
{isPending ? (
<LoadingDots className="bg-white" />
) : (
<XMarkIcon className="hover:text-accent-3 mx-[1px] h-4 w-4 text-white dark:text-black" />
<XMarkIcon className="mx-[1px] h-4 w-4 text-white transition-opacity duration-150 hover:opacity-60 dark:text-black" />
)}
</button>
);

View File

@ -0,0 +1,75 @@
'use client';
import clsx from 'clsx';
import { addItem } from 'components/cart/actions';
import LoadingDots from 'components/loading-dots';
import { ProductVariant } from 'lib/shopify/types';
import { useTranslations } from 'next-intl';
import { useRouter, useSearchParams } from 'next/navigation';
import { useTransition } from 'react';
export function InlineAddToCart({
variants,
availableForSale
}: {
variants: ProductVariant[];
availableForSale: boolean;
}) {
const router = useRouter();
const searchParams = useSearchParams();
const t = useTranslations('Index');
const [isPending, startTransition] = useTransition();
const defaultVariantId = variants.length === 1 ? variants[0]?.id : undefined;
const variant = variants.find((variant: ProductVariant) =>
variant.selectedOptions.every(
(option) => option.value === searchParams.get(option.name.toLowerCase())
)
);
const selectedVariantId = variant?.id || defaultVariantId;
const title = !availableForSale
? 'Out of stock'
: !selectedVariantId
? 'Please select options'
: undefined;
return (
<button
aria-label="Add item to cart"
disabled={isPending || !availableForSale || !selectedVariantId}
title={title}
onClick={() => {
// Safeguard in case someone messes with `disabled` in devtools.
if (!availableForSale || !selectedVariantId) return;
startTransition(async () => {
const error = await addItem(selectedVariantId);
if (error) {
// Trigger the error boundary in the root error.js
throw new Error(error.toString());
}
router.refresh();
});
}}
className={clsx(
'p-4',
'relative flex w-full items-center justify-center',
'border border-white/20 hover:border-white',
'font-serif text-base tracking-wider text-white',
'transition-colors duration-150',
{
'cursor-not-allowed opacity-60 hover:opacity-60': !availableForSale || !selectedVariantId,
'cursor-not-allowed': isPending
}
)}
>
{!isPending ? (
<span>{availableForSale ? t('cart.add') : t('cart.out-of-stock')}</span>
) : (
<LoadingDots className="my-3 bg-white" />
)}
</button>
);
}

View File

@ -67,7 +67,7 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) {
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<Dialog.Panel className="fixed bottom-0 right-0 top-0 flex h-full w-full flex-col border-l border-white/20 bg-dark p-6 font-sans text-white backdrop-blur-xl md:w-[390px]">
<Dialog.Panel className="fixed inset-y-0 right-0 flex h-full w-full flex-col border-l border-white/20 bg-dark p-6 font-sans text-white backdrop-blur-xl md:w-[390px]">
<div className="flex items-center justify-between">
<p className="text-lg font-semibold">Cart</p>
@ -83,7 +83,7 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) {
</div>
) : (
<div className="flex h-full flex-col justify-between overflow-hidden p-1">
<ul className="flex-grow overflow-auto py-4">
<ul className="grow overflow-auto py-4">
{cart.lines.map((item, i) => {
const merchandiseSearchParams = {} as MerchandiseSearchParams;
@ -159,11 +159,11 @@ export default function CartModal({ cart }: { cart: Cart | undefined }) {
currencyCode={cart.cost.totalTaxAmount.currencyCode}
/>
</div>
<div className="mb-3 flex items-center justify-between border-b border-white/20 pb-1 pt-1">
<div className="mb-3 flex items-center justify-between border-b border-white/20 py-1">
<p>Shipping</p>
<p className="text-right text-white/50">Calculated at checkout</p>
</div>
<div className="mb-3 flex items-center justify-between border-b border-white/20 pb-1 pt-1">
<div className="mb-3 flex items-center justify-between border-b border-white/20 py-1">
<p>Total</p>
<Price
className="text-right text-base text-white"

View File

@ -19,7 +19,7 @@ export default function OpenCart({
/>
{quantity ? (
<div className="absolute right-[23%] top-[85%] -mr-2 -mt-2 h-5 w-5 -translate-x-1/2 -translate-y-1/2 transform font-sans text-[12px] font-medium text-white">
<div className="absolute right-[23%] top-[85%] -mr-2 -mt-2 h-5 w-5 -translate-x-1/2 -translate-y-1/2 font-sans text-[12px] font-medium text-white">
{quantity}
</div>
) : null}

View File

@ -0,0 +1,78 @@
import { ChevronRightIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx';
import { InlineAddToCart } from 'components/cart/inline-add-to-cart';
import { SupportedLocale } from 'components/layout/navbar/language-control';
import { getCollectionProducts } from 'lib/shopify';
import type { Product } from 'lib/shopify/types';
import Link from 'next/link';
import Label from '../label';
import { GridTileImage } from './tile';
function HomepageProductsItem({ item, priority }: { item: Product; priority?: boolean }) {
const size = item?.variants?.[0]?.selectedOptions?.find((option) => option.name === 'Size');
const image = item?.variants?.[0]?.image;
return !!image ? (
<div
className={clsx(
'col-span-1 row-span-1 flex flex-col justify-between space-y-6 md:col-span-2 md:row-span-1'
)}
>
<Link className="group block w-full" href={`/product/${item.handle}`}>
<div className="relative block aspect-tall overflow-hidden ">
<GridTileImage
src={image?.url}
fill
sizes={'(min-width: 768px) 33vw, 100vw'}
priority={priority}
alt={item.title}
/>
</div>
<div className="font-multilingual max-w-sm pb-24 pt-4 md:pb-0">
<Label
title={item.title as string}
amount={item.priceRange.maxVariantPrice.amount}
currencyCode={item.priceRange.maxVariantPrice.currencyCode}
size={size?.value}
/>
<div className="line-clamp-4 pt-2 font-extralight">
<span>{item?.summary?.value}</span>{' '}
<span className="ml-2 inline-flex flex-row items-center space-x-1 opacity-50 transition-opacity duration-150 group-hover:opacity-100">
<span>Read more.</span>
<span>
<ChevronRightIcon width={16} />
</span>
</span>
</div>
</div>
</Link>
<InlineAddToCart variants={item.variants} availableForSale={item.availableForSale} />
</div>
) : null;
}
export async function HomepageProducts({ lang }: { lang?: SupportedLocale }) {
// Collections that start with `hidden-*` are hidden from the search page.
const homepageItems = await getCollectionProducts({
collection: 'hidden-homepage-featured-items',
language: lang?.toUpperCase()
});
if (!homepageItems[0] || !homepageItems[1] || !homepageItems[2]) return null;
const [firstProduct, secondProduct, thirdProduct] = homepageItems;
return (
<section
className={clsx(
'mx-auto grid max-w-screen-xl gap-12 px-4 pb-4 ',
'grid-cols-1 md:grid-cols-6',
'grid-rows-3 md:grid-rows-1'
)}
>
<HomepageProductsItem item={firstProduct} priority={true} />
<HomepageProductsItem item={secondProduct} priority={true} />
<HomepageProductsItem item={thirdProduct} />
</section>
);
}

View File

@ -6,12 +6,13 @@ import Link from 'next/link';
import Label from '../label';
import { GridTileImage } from './tile';
function ThreeItemGridItem({ item, priority }: { item: Product; priority?: boolean }) {
function ProductGridItem({ item, priority }: { item: Product; priority?: boolean }) {
const size = item?.variants?.[0]?.selectedOptions?.find((option) => option.name === 'Size');
return (
<div className={clsx('col-span-1 row-span-1 md:col-span-2 md:row-span-1')}>
<Link className="w-full bg-black/30" href={`/product/${item.handle}`}>
<div className="relative block aspect-tall overflow-hidden ">
<div className="relative block aspect-square overflow-hidden ">
<GridTileImage
src={item.featuredImage.url}
fill
@ -34,16 +35,14 @@ function ThreeItemGridItem({ item, priority }: { item: Product; priority?: boole
);
}
export async function ThreeItemGrid({ lang }: { lang?: SupportedLocale }) {
export async function ProductGrid({ lang }: { lang?: SupportedLocale }) {
// Collections that start with `hidden-*` are hidden from the search page.
const homepageItems = await getCollectionProducts({
collection: 'hidden-homepage-featured-items',
const productPageItems = await getCollectionProducts({
collection: 'hidden-products-page-items',
language: lang?.toUpperCase()
});
if (!homepageItems[0] || !homepageItems[1] || !homepageItems[2]) return null;
const [firstProduct, secondProduct, thirdProduct] = homepageItems;
if (!productPageItems?.length) return null;
return (
<section
@ -53,9 +52,9 @@ export async function ThreeItemGrid({ lang }: { lang?: SupportedLocale }) {
'grid-rows-3 md:grid-rows-1'
)}
>
<ThreeItemGridItem item={firstProduct} priority={true} />
<ThreeItemGridItem item={secondProduct} priority={true} />
<ThreeItemGridItem item={thirdProduct} />
{productPageItems.map((item) => (
<ProductGridItem key={item.id} item={item} priority={true} />
))}
</section>
);
}

View File

@ -3,8 +3,8 @@ import Image from 'next/image';
export function GridTileImage({
isInteractive = true,
active,
label,
active: _active,
label: _label,
...props
}: {
isInteractive?: boolean;

View File

@ -15,8 +15,10 @@ const Label = ({
return (
<div className={clsx('@container/label')}>
<div className="flex flex-col space-y-2">
<h3 className="mr-4 line-clamp-2 flex-grow font-serif text-3xl md:text-4xl">{title}</h3>
<div className="font-multilingual flex flex-row items-center space-x-2">
<h3 className="mr-4 line-clamp-2 grow font-serif text-3xl tracking-wider md:text-4xl">
{title}
</h3>
<div className="font-multilingual flex flex-row items-center space-x-2 text-[17px]">
<Price
className="flex-none"
amount={amount}

View File

@ -7,10 +7,10 @@ export default function AboutNaraiPreview() {
return (
<div className="flex flex-col space-y-4 px-6 py-24 md:flex-row md:space-x-12 md:space-y-0 md:p-24">
<div className="font-multilingual flex flex-col space-y-2 font-extralight md:w-1/2">
<div className="max-w-sm text-5xl">{t('home.previews.about-narai.title')}</div>
<div className="max-w-sm text-5xl">{t('home.previews.about-narai.subtitle')}</div>
<div className="max-w-title text-[40px]">{t('home.previews.about-narai.title')}</div>
<div className="max-w-sm text-[40px]">{t('home.previews.about-narai.subtitle')}</div>
</div>
<div className="font-multilingual flex flex-col space-y-6 font-extralight md:w-1/2">
<div className="font-multilingual flex flex-col space-y-6 text-base font-extralight md:w-1/2">
<div>{t('home.previews.about-narai.body')}</div>
</div>
</div>

View File

@ -8,14 +8,14 @@ export default function ConceptPreview() {
return (
<div className="flex flex-col space-y-4 px-6 py-24 md:flex-row md:space-x-12 md:space-y-0 md:p-24">
<div className="font-multilingual flex flex-col space-y-2 font-extralight md:w-1/2">
<div className="max-w-sm text-5xl">{t('home.previews.concept.title')}</div>
<div className="max-w-sm text-5xl">{t('home.previews.concept.subtitle')}</div>
<div className="max-w-sm text-[40px]">{t('home.previews.concept.title')}</div>
<div className="max-w-sm text-[40px]">{t('home.previews.concept.subtitle')}</div>
</div>
<div className="font-multilingual flex flex-col space-y-6 font-extralight md:w-1/2">
<div className="font-multilingual flex flex-col space-y-6 text-base font-extralight md:w-1/2">
<div>{t('home.previews.concept.body')}</div>
<Link
href="/location"
className="max-w-sm border border-white px-6 py-3 text-center text-lg transition-colors duration-150 hover:border-white/50"
href="/concept"
className="max-w-sm border border-white px-6 py-3 text-center text-base transition-colors duration-150 hover:border-white/50"
>
{t('home.previews.concept.button')}
</Link>

View File

@ -10,7 +10,7 @@ export default function FooterMenu() {
<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-extralight">
<nav className="font-multilingual flex flex-col space-y-2 text-left text-sm font-extralight">
<div>
<Link href="/products" className="transition-opacity duration-150 hover:opacity-50">
{t('menu.products')}
@ -59,7 +59,7 @@ export default function FooterMenu() {
<div className="mb-4 text-right font-serif text-base underline">
{t('shopping-guide.title')}
</div>
<nav className="font-multilingual flex flex-col items-end space-y-2 text-left text-base font-extralight">
<nav className="font-multilingual flex flex-col items-end space-y-2 text-left text-sm font-extralight">
<div>
<Link href="/terms" className="transition-opacity duration-150 hover:opacity-50">
{t('shopping-guide.terms')}

View File

@ -35,11 +35,11 @@ export default async function Footer({ cart }: { cart?: Cart }) {
<div className="flex flex-row items-end space-x-6">
<div className="flex flex-col items-start space-y-2">
<p className="font-japan text-3xl font-extralight"></p>
<p className="font-serif text-lg">suginomori brewery</p>
<p className="font-serif text-xs font-semibold">suginomori brewery</p>
</div>
<div className="flex flex-col items-start space-y-2">
<p className="font-japan text-xl font-extralight">551-1</p>
<p className="font-serif text-lg">551-1 Narai, Shiojiri, Nagano</p>
<p className="font-serif text-xs font-semibold">551-1 Narai, Shiojiri, Nagano</p>
</div>
</div>
</div>
@ -52,11 +52,11 @@ export default async function Footer({ cart }: { cart?: Cart }) {
</Link>
<div className="flex grow flex-col items-end space-y-6">
<div className="flex flex-col items-start space-y-2">
<p className="font-japan text-3xl font-extralight"></p>
<p className="font-japan text-[22px] font-extralight"></p>
<p className="font-serif text-lg">suginomori brewery</p>
</div>
<div className="flex flex-col items-start space-y-2">
<p className="font-japan text-xl font-extralight">551-1</p>
<p className="font-japan text-[17px] font-extralight">551-1</p>
<p className="font-serif text-lg">551-1 Narai, Shiojiri, Nagano</p>
</div>
<div className="flex flex-row justify-between space-x-4">

View File

@ -8,14 +8,14 @@ export default function LocationPreview() {
return (
<div className="flex flex-col space-y-4 px-6 py-24 md:flex-row md:space-x-12 md:space-y-0 md:p-24">
<div className="font-multilingual flex flex-col space-y-2 font-extralight md:w-1/2">
<div className="max-w-sm text-5xl">{t('home.previews.location.title')}</div>
<div className="max-w-sm text-5xl">{t('home.previews.location.subtitle')}</div>
<div className="max-w-title text-[40px]">{t('home.previews.location.title')}</div>
<div className="max-w-sm text-[40px]">{t('home.previews.location.subtitle')}</div>
</div>
<div className="font-multilingual flex flex-col space-y-6 font-extralight md:w-1/2">
<div className="font-multilingual flex flex-col space-y-6 text-base font-extralight md:w-1/2">
<div>{t('home.previews.location.body')}</div>
<Link
href="/location"
className="max-w-sm border border-white px-6 py-3 text-center text-lg transition-colors duration-150 hover:border-white/50"
href="/about"
className="max-w-sm border border-white px-6 py-3 text-center text-base transition-colors duration-150 hover:border-white/50"
>
{t('home.previews.location.button')}
</Link>

View File

@ -3,6 +3,7 @@
import { Dialog, Transition } from '@headlessui/react';
import clsx from 'clsx';
import CloseIcon from 'components/icons/close';
import Logo from 'components/icons/logo';
import MenuIcon from 'components/icons/menu';
import { useLocale, useTranslations } from 'next-intl';
import Link from 'next/link';
@ -12,8 +13,8 @@ import { LanguageControl, SupportedLocale } from '../navbar/language-control';
export function MenuModal({ scrolled }: { scrolled: boolean }) {
const t = useTranslations('Index');
const locale = useLocale();
let [isOpen, setIsOpen] = useState(false);
let closeButtonRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const closeButtonRef = useRef(null);
const close = () => {
setIsOpen(false);
@ -55,6 +56,9 @@ export function MenuModal({ scrolled }: { scrolled: boolean }) {
<div className="fixed inset-0 z-30 bg-dark/80 backdrop-blur-sm">
<Dialog.Panel>
<div className="z-40 mx-auto max-w-screen-xl px-6">
<div className="absolute left-6 top-2">
<Logo className="h-[132px] w-[132px]" />
</div>
<div
className={clsx(
'flex flex-row justify-end space-x-6 px-2',

View File

@ -61,7 +61,7 @@ export default function MobileMenu({ menu }: { menu: Menu[] }) {
leaveFrom="translate-x-0"
leaveTo="translate-x-[-100%]"
>
<Dialog.Panel className="fixed bottom-0 left-0 right-0 top-0 flex h-full w-full flex-col bg-white pb-6 dark:bg-black">
<Dialog.Panel className="fixed inset-0 flex h-full w-full flex-col bg-white pb-6 dark:bg-black">
<div className="p-4">
<button
className="mb-4 flex h-11 w-11 items-center justify-center rounded-md border border-neutral-200 text-black transition-colors dark:border-neutral-700 dark:text-white"

View File

@ -32,7 +32,7 @@ export default function Search() {
}
return (
<form onSubmit={onSubmit} className="w-max-[550px] relative w-full lg:w-80 xl:w-full">
<form onSubmit={onSubmit} className="relative w-full max-w-[550px] lg:w-80 xl:w-full">
<input
type="text"
name="search"

View File

@ -36,7 +36,7 @@ export default function NewsletterSignup() {
)}
placeholder={t('newsletter.placeholder')}
/>
<div className="mt-3 rounded-md sm:ml-3 sm:mt-0 sm:flex-shrink-0">
<div className="mt-3 rounded-md sm:ml-3 sm:mt-0 sm:shrink-0">
<button
type="submit"
className={clsx(

View File

@ -8,7 +8,7 @@ export default function NewsletterSignup() {
return (
<div className="mx-auto max-w-xl space-y-4">
<h3 className="font-serif text-2xl tracking-wider">{t('newsletter.title')}</h3>
<div className="font-multilingual font-extralight">{t('newsletter.description')}</div>
<div className="font-multilingual text-sm font-extralight">{t('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}&amp;id=${process?.env?.NEXT_PUBLIC_MAILCHIMP_LIST_ID}`}
@ -26,7 +26,7 @@ export default function NewsletterSignup() {
autoComplete="email"
required
className={clsx(
'w-full min-w-0 appearance-none',
'w-full min-w-0 appearance-none text-sm',
'bg-white outline-none',
'px-4 py-3 focus:outline-none',
'focus:ring-2 focus:ring-inset focus:ring-emerald-300 focus:ring-offset-0',
@ -34,11 +34,11 @@ export default function NewsletterSignup() {
)}
placeholder={t('newsletter.placeholder')}
/>
<div className="mt-3 rounded-md sm:ml-3 sm:mt-0 sm:flex-shrink-0">
<div className="mt-3 rounded-md sm:ml-3 sm:mt-0 sm:shrink-0">
<button
type="submit"
className={clsx(
'px-4 py-3',
'px-4 py-3 text-sm',
'transition-colors duration-150',
'font-multilingual flex w-full items-center justify-center font-extralight',
'border border-white/30 hover:border-white',

View File

@ -7,15 +7,16 @@ export default function SagyobarPreview() {
return (
<div className="flex flex-col space-y-4 px-6 py-24 md:flex-row md:space-x-12 md:space-y-0 md:p-24">
<div className="font-multilingual flex flex-col space-y-2 font-extralight md:w-1/2">
<div className="max-w-sm text-5xl">{t('home.previews.bar.title')}</div>
<div className="max-w-sm text-5xl">{t('home.previews.bar.subtitle')}</div>
<div className="font-multilingual flex flex-col font-extralight md:w-1/2">
<div className="max-w-sm text-[40px]">{t('home.previews.bar.title.line001')}</div>
<div className="max-w-sm text-[40px]">{t('home.previews.bar.title.line002')}</div>
<div className="max-w-sm text-[40px]">{t('home.previews.bar.title.line003')}</div>
</div>
<div className="font-multilingual flex flex-col space-y-6 font-extralight md:w-1/2">
<div className="font-multilingual flex flex-col space-y-6 text-base font-extralight md:w-1/2">
<div>{t('home.previews.bar.body')}</div>
<Link
href="/location"
className="max-w-sm border border-white px-6 py-3 text-center text-lg transition-colors duration-150 hover:border-white/50"
href="/sagyobar"
className="max-w-sm border border-white px-6 py-3 text-center text-base transition-colors duration-150 hover:border-white/50"
>
{t('home.previews.bar.button')}
</Link>

View File

@ -6,12 +6,10 @@ import Link from 'next/link';
export default function Shoplist() {
const t = useTranslations('Index');
return (
<div className="mx-auto max-w-screen-xl space-y-4 px-6" id="shops">
<div className="font-multilingual mx-auto max-w-screen-xl space-y-4 px-6" id="shops">
<div className="flex w-full flex-row items-baseline space-x-12 pb-6">
<h2 className="font-serif text-6xl tracking-wider">shop list</h2>
<h3 className="font-multilingual text-2xl font-extralight tracking-wider">
{t('shops.subtitle')}
</h3>
<h3 className="text-2xl font-extralight tracking-wider">{t('shops.subtitle')}</h3>
</div>
<div className="grid w-full grid-cols-2 gap-px">
<Link

View File

@ -4,7 +4,7 @@ import Image from 'next/image';
import Link from 'next/link';
import { SupportedLocale } from './navbar/language-control';
export default async function Stories({
export default async function StoriesPreview({
locale,
handle,
articles,
@ -21,7 +21,7 @@ export default async function Stories({
language: locale?.toUpperCase()
});
if (!blog) return null;
if (!blog || !!blog?.articles) return null;
return (
<div className="bg-white px-6 py-24 text-black">
@ -60,7 +60,7 @@ export default async function Stories({
<div className="flex w-full flex-row justify-center pt-12">
<Link
href="/stories"
className="mx-auto max-w-sm border border-dark px-24 py-3 text-center text-lg transition-colors duration-150 hover:border-dark/40"
className="mx-auto max-w-sm border border-dark px-24 py-3 text-center text-[15px] transition-colors duration-150 hover:border-dark/40"
>
more stories
</Link>

View File

@ -5,8 +5,8 @@ export default function LogoSquare({ size }: { size?: 'sm' | undefined }) {
return (
<div
className={clsx('flex flex-none items-center justify-center', {
'h-[40px] w-[40px] rounded-xl': !size,
'h-[30px] w-[30px] rounded-lg': size === 'sm'
'h-[40px] w-[40px]': !size,
'h-[30px] w-[30px]': size === 'sm'
})}
>
<Logo

View File

@ -100,7 +100,7 @@ const AgeGateForm: FC<AgeGateFormProps> = ({ checkoutUrl, didCancel }) => {
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className="inline-block transform space-y-6 overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom text-dark shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="inline-block space-y-6 overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left align-bottom text-dark shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div>
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100 dark:bg-green-900">
<CheckIcon
@ -116,9 +116,7 @@ const AgeGateForm: FC<AgeGateFormProps> = ({ checkoutUrl, didCancel }) => {
{t('age-gate.title')}
</Dialog.Title>
<div className="mt-2">
<p className="dark:text-secondary-neutral text-sm text-white">
{t('age-gate.description')}
</p>
<p className="text-sm text-white">{t('age-gate.description')}</p>
</div>
</div>
</div>

View File

@ -11,7 +11,7 @@ const Prose: FunctionComponent<TextProps> = ({ html, className }) => {
<div
className={clsx(
'prose text-lg leading-7',
'font-multilingual font-extralight text-white',
'font-multilingual text-[15px] font-extralight text-white',
'prose-headings:mt-8 prose-headings:font-semibold prose-headings:tracking-wide prose-headings:text-white',
'prose-h1:text-5xl prose-h2:text-4xl prose-h3:text-3xl prose-h4:text-2xl prose-h5:text-xl prose-h6:text-lg',
'prose-a:text-white/80 prose-a:underline hover:prose-a:text-white',
@ -20,6 +20,7 @@ const Prose: FunctionComponent<TextProps> = ({ html, className }) => {
'prose-tr:border-subtle',
'prose-ol:mt-8 prose-ol:list-decimal prose-ol:pl-6 prose-ul:mt-8 prose-ul:list-disc prose-ul:pl-6',
'dark:text-white dark:prose-headings:text-white dark:prose-a:text-white dark:prose-strong:text-white',
'!tracking-normal',
className
)}
dangerouslySetInnerHTML={{ __html: html as string }}

View File

@ -40,6 +40,9 @@ const productFragment = /* GraphQL */ `
name
value
}
image {
...image
}
price {
amount
currencyCode

View File

@ -98,6 +98,7 @@ export type ProductVariant = {
value: string;
}[];
price: Money;
image: Image;
};
export type SEO = {

View File

@ -2,20 +2,8 @@ The MIT License (MIT)
Copyright (c) 2023 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -41,8 +41,11 @@
"button": "about narai"
},
"bar": {
"title": "sagyobar : a brewery-operated bar & workspace",
"subtitle": "",
"title": {
"line001": "sagyobar : a brewery-operated bar & workspace",
"line002": "",
"line003": ""
},
"body": "Introducing sagyobar: a place where brewery operations (sagyo) and drinking (bar) come together. We have combined our brewery workspace, where we pack boxes and fulfill orders, with a place to enjoy sake served from our very own suginomori wagon. It is a renovated warehouse located a one-minute walk from the brewery, just across the railway tracks.",
"button": "about sagyobar"
},
@ -71,8 +74,8 @@
}
},
"cart": {
"add": "Add to cart",
"out-of-stock": "Out of stock",
"add": "add to cart",
"out-of-stock": "out of stock",
"title": "Shopping Bag",
"subtitle": "Review your Order",
"empty": "Your shopping bag is empty",
@ -92,7 +95,7 @@
"editNote": "Edit note",
"hideNote": "Hide",
"saving": "Saving...",
"addFeaturedProduct": "+ Add"
"addFeaturedProduct": "+ add"
},
"age-gate": {
"title": "Confirm Your Age",
@ -127,6 +130,7 @@
},
"materials": {
"title": "materials",
"subtitle": "",
"water": {
"title": "water - the foundation",
"body": "While most breweries use well water with stable properties, narai uses natural mountain water flowing from an altitude of over 1,000 meters. This mountain water, which springs near the divide between the Shinano and Kiso Rivers, is one of the clearest in Japan with a hardness of less than 25 and a round, smooth texture."
@ -147,8 +151,11 @@
},
"bar": {
"001": {
"title": "sagyobar : a brewery-operated bar & workspace",
"subtitle": "",
"title": {
"line001": "sagyobar : a brewery-operated bar & workspace",
"line002": "",
"line003": ""
},
"para001": "Introducing sagyobar: a place where brewery operations (sagyo) and drinking (bar) come together. We have combined our brewery workspace, where we pack boxes and fulfill orders, with a place to enjoy sake served from our very own suginomori wagon.",
"para002": "The renovated warehouse was originally used for storing equipment and business supplies left from the old Suginomori Shuzo, the precursor to suginomori brewery that was established in 1793. While maintaining its original structure, we have revamped its entrance and installed new systems such as lighting and air conditioning. We utilize “P-boxes” containers used to transport sake bottles that can be flexibly arranged to transform the space into standing bar."
},

View File

@ -5,13 +5,13 @@
},
"menu": {
"title": "menu",
"products": "商品",
"shops": "取り扱い店",
"about": "naraiについて",
"products": "products",
"shops": "shop list",
"about": "about narai",
"bar": "sagyobar",
"concept": "コンセプト",
"stories": "ストーリー",
"company": "会社概要",
"concept": "concept",
"stories": "stories",
"company": "company",
"contact": "contact"
},
"shopping-guide": {
@ -41,8 +41,11 @@
"button": "naraiについて"
},
"bar": {
"title": "酒蔵直営の角打ち&作業場",
"subtitle": "sagyobar",
"title": {
"line001": "酒蔵直営の",
"line002": "角打ち&作業場",
"line003": "sagyobar"
},
"body": "ここは、ボトルの箱詰めや出荷などの酒蔵作業 (sagyo) と、日本酒移動販売車「suginomori wagon」から提供されるSAKEを楽しむこともできる場(bar)が融合した、弊蔵の直営店です。酒蔵から徒歩1分。線路を挟み向かいの倉庫をリノベーションしました。",
"button": "sagyobarについて"
},
@ -126,7 +129,8 @@
"subtitle": "受賞歴"
},
"materials": {
"title": "自然を紡ぐ naraiの素材",
"title": "自然を紡ぐ",
"subtitle": " naraiの素材",
"water": {
"title": "水 土台",
"body": "多くの酒蔵が水の性質が安定している井戸水を使用しますが、naraiは標高1,000m以上から流れる天然の山水を使用。信濃川と木曽川の分水嶺付近の湧き水であるこの山水は、日本でも有数な「硬度25以下」の透明感と丸みのある滑らかな舌触りが特徴です。"
@ -136,7 +140,7 @@
"body": "長野県安曇野エリアで、日本アルプスの恵みで農家を営む「ファームいちまる」によって、丁寧に育てられた米を使用しています。地産米にこだわり、杜氏自ら農家に通い、田植えなどを行いながら相談し、米を厳選しています。"
},
"koji": {
"title": "酵母と麹 (発酵) 構成要素",
"title": "酵母と麹 - 構成要素(発酵)",
"body": "酵母は発酵力が強く、香りを上品にまとめることができることが特徴だと考えている長野由来の協会第7号を使用しています。米を糖に変える麹菌は、酵素力価の良いバランスの取れたものを採用しています。"
}
},
@ -147,8 +151,11 @@
},
"bar": {
"001": {
"title": "酒蔵直営の角打ち&作業場",
"subtitle": "sagyobar",
"title": {
"line001": "酒蔵直営の",
"line002": "角打ち&作業場",
"line003": "sagyobar"
},
"para001": "ここは、ボトルの箱詰めや出荷などの酒蔵作業 (sagyo) と、日本酒移動販売車「suginomori wagon」から提供されるsakeを楽しむこともできる場(bar)が融合した、弊蔵の直営店です。",
"para002": "リベーションした倉庫は、元々は先代の頃の杉の森酒蔵の機材や業務備品の保管用の場所として利用されていました。倉庫の建築はそのままに、入り口部分のゲートを刷新し、照明や空調等の設備を新設。什器は酒蔵の作業でも使用する酒瓶を運ぶための外装容器「P箱」を活用しています。このP箱を自在にレイアウトすることで、角打ちのようなスペースとしても活用できます。"
},
@ -214,7 +221,7 @@
},
"address": {
"label": "所在地",
"value": "〒399-6303長野県塩尻市奈良井551-1"
"value": "〒399-6303 長野県塩尻市奈良井551-1"
},
"telephone": {
"label": "電話番号",

View File

@ -28,6 +28,7 @@
"@thgh/next-gtm": "^0.1.4",
"clsx": "^2.0.0",
"date-fns": "^2.30.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-tailwindcss": "^3.13.0",
"eslint-plugin-unused-imports": "^3.0.0",
"js-cookie": "^3.0.5",

3443
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,18 @@ module.exports = {
title: ['var(--font-cinzel)', 'serif'],
japan: ['var(--font-noto)', 'serif']
},
fontSize: {
'6xl': '65px',
'5xl': '45px',
'3xs': '.5rem'
},
aspectRatio: {
tall: '596 / 845',
video: '1792 / 750'
},
maxWidth: {
title: '281px'
},
keyframes: {
fadeIn: {
from: { opacity: 0 },

View File

@ -1299,6 +1299,7 @@ __metadata:
eslint: ^8.45.0
eslint-config-next: latest
eslint-config-prettier: ^8.8.0
eslint-plugin-prettier: ^5.0.0
eslint-plugin-tailwindcss: ^3.13.0
eslint-plugin-unicorn: ^48.0.0
eslint-plugin-unused-imports: ^3.0.0
@ -1812,6 +1813,25 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-prettier@npm:^5.0.0":
version: 5.0.0
resolution: "eslint-plugin-prettier@npm:5.0.0"
dependencies:
prettier-linter-helpers: ^1.0.0
synckit: ^0.8.5
peerDependencies:
"@types/eslint": ">=8.0.0"
eslint: ">=8.0.0"
prettier: ">=3.0.0"
peerDependenciesMeta:
"@types/eslint":
optional: true
eslint-config-prettier:
optional: true
checksum: 84e88744b9050f2d5ef31b94e85294dda16f3a53c2449f9d33eac8ae6264889b459bf35a68e438fb6b329c2a1d6491aac4bfa00d86317e7009de3dad0311bec6
languageName: node
linkType: hard
"eslint-plugin-react-hooks@npm:5.0.0-canary-7118f5dd7-20230705":
version: 5.0.0-canary-7118f5dd7-20230705
resolution: "eslint-plugin-react-hooks@npm:5.0.0-canary-7118f5dd7-20230705"
@ -2060,6 +2080,13 @@ __metadata:
languageName: node
linkType: hard
"fast-diff@npm:^1.1.2":
version: 1.3.0
resolution: "fast-diff@npm:1.3.0"
checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3
languageName: node
linkType: hard
"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.5, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0":
version: 3.3.1
resolution: "fast-glob@npm:3.3.1"
@ -4057,6 +4084,15 @@ __metadata:
languageName: node
linkType: hard
"prettier-linter-helpers@npm:^1.0.0":
version: 1.0.0
resolution: "prettier-linter-helpers@npm:1.0.0"
dependencies:
fast-diff: ^1.1.2
checksum: 00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392
languageName: node
linkType: hard
"prettier-plugin-organize-imports@npm:^3.2.3":
version: 3.2.3
resolution: "prettier-plugin-organize-imports@npm:3.2.3"