128 lines
5.0 KiB
TypeScript
128 lines
5.0 KiB
TypeScript
import {Image} from '@shopify/hydrogen';
|
||
import {AbiirEyebrow} from '~/components/AbiirEyebrow';
|
||
import {PAGE_TITLE_TYPOGRAPHY_CLASS} from '~/lib/pageTitle';
|
||
import type {BrandValueIconKey, BrandValuesCms} from '~/lib/brandValues';
|
||
import {
|
||
BRAND_VALUES_GROQ,
|
||
MOCK_BRAND_VALUES_CMS,
|
||
} from '~/lib/brandValues';
|
||
import iconFlaskSrc from '~/assets/brand-values/icon-flask.svg';
|
||
import iconLeafSrc from '~/assets/brand-values/icon-leaf.svg';
|
||
import iconShieldSrc from '~/assets/brand-values/icon-shield.svg';
|
||
import iconSparklesSrc from '~/assets/brand-values/icon-sparkles.svg';
|
||
|
||
/**
|
||
* Sanity GROQ for this module (loader + future `useQuery`):
|
||
* @see {@link BRAND_VALUES_GROQ}
|
||
*/
|
||
export {BRAND_VALUES_GROQ, MOCK_BRAND_VALUES_CMS};
|
||
export type {BrandValuesCms, BrandValueIconKey} from '~/lib/brandValues';
|
||
|
||
/** Figma 32:7186 — raster icons exported as SVG from MCP asset URLs. */
|
||
const ICON_SRC: Record<BrandValueIconKey, string> = {
|
||
leaf: iconLeafSrc,
|
||
flaskConical: iconFlaskSrc,
|
||
shield: iconShieldSrc,
|
||
sparkles: iconSparklesSrc,
|
||
};
|
||
|
||
/**
|
||
* Figma 32:7200–32:7230 — description block horizontal padding + max width per column.
|
||
*/
|
||
const DESCRIPTION_LAYOUT = [
|
||
{wrapClass: 'px-[5px]', textClass: 'max-w-[228px]'},
|
||
{wrapClass: 'px-[9px]', textClass: 'max-w-[220px]'},
|
||
{wrapClass: '', textClass: 'max-w-[238px]'},
|
||
{wrapClass: 'px-[16px]', textClass: 'max-w-[206px]'},
|
||
] as const;
|
||
|
||
export type BrandValuesProps = {
|
||
cms: BrandValuesCms;
|
||
};
|
||
|
||
export function BrandValues({cms}: BrandValuesProps) {
|
||
return (
|
||
<section
|
||
className="w-full !py-0"
|
||
style={{background: cms.sectionBackground}}
|
||
>
|
||
{/* Figma: px-[206px] py-[94px] gap-[68px] within1710 frame */}
|
||
<div className="mx-auto flex w-full max-w-[1710px] flex-col gap-6 px-6 py-16 sm:px-10 sm:py-20 lg:gap-[68px] lg:px-[206px] lg:py-[94px]">
|
||
<header className="mx-auto w-full max-w-[1298px]">
|
||
{/* Flow layout so type size isn’t fighting absolute + min-height (which only added empty gap). */}
|
||
<div className="flex flex-col items-center gap-3 text-center lg:gap-8">
|
||
<AbiirEyebrow className="mb-0" surface="light" textCase="preserve">
|
||
{cms.eyebrow}
|
||
</AbiirEyebrow>
|
||
<h2
|
||
className={`m-0 max-w-[1298px] text-center ${PAGE_TITLE_TYPOGRAPHY_CLASS}`}
|
||
style={{color: cms.titleColor, marginBottom: '-40px'}}
|
||
>
|
||
{cms.headlinePrefix}
|
||
<span
|
||
className="font-['Cormorant_Garamond',serif] font-light italic"
|
||
style={{fontWeight: 300}}
|
||
>
|
||
{cms.headlineItalic}
|
||
</span>
|
||
</h2>
|
||
</div>
|
||
</header>
|
||
|
||
<div
|
||
className="grid w-full grid-cols-1 gap-px sm:grid-cols-2 lg:grid-cols-4 lg:grid-rows-1"
|
||
style={{background: cms.gridGutterColor}}
|
||
>
|
||
{cms.values.map((value, index) => {
|
||
const layout =
|
||
index < DESCRIPTION_LAYOUT.length
|
||
? DESCRIPTION_LAYOUT[index]
|
||
: {wrapClass: '', textClass: 'max-w-[238px]'};
|
||
return (
|
||
<div
|
||
key={`${value.iconKey}-${value.title}`}
|
||
className="relative min-h-0 py-10 sm:min-h-[200px] lg:h-[269.688px] lg:py-0"
|
||
style={{background: cms.sectionBackground}}
|
||
>
|
||
<div className="flex flex-col items-center gap-[16px] px-4 text-center sm:px-6 lg:absolute lg:left-1/2 lg:top-[42.5px] lg:w-[238px] lg:-translate-x-1/2 lg:px-0">
|
||
<div
|
||
className="flex size-[52px] shrink-0 items-center justify-center px-[16px]"
|
||
style={{background: cms.iconTileBackground}}
|
||
>
|
||
<Image
|
||
alt=""
|
||
aria-hidden
|
||
className="size-[20px] object-contain object-center"
|
||
height={20}
|
||
src={ICON_SRC[value.iconKey]}
|
||
width={20}
|
||
/>
|
||
</div>
|
||
<div className="flex h-[23.375px] w-full items-center justify-center">
|
||
<h3
|
||
className="m-0 whitespace-nowrap font-['Cormorant_Garamond',serif] text-[24px] font-medium leading-[23.375px] tracking-[-0.187px]"
|
||
style={{color: cms.titleColor}}
|
||
>
|
||
{value.title}
|
||
</h3>
|
||
</div>
|
||
<div
|
||
className={`flex w-full items-center justify-center ${layout.wrapClass}`}
|
||
>
|
||
<p
|
||
className={`m-0 w-full font-['Raleway',sans-serif] text-[16px] font-medium leading-[23.698px] ${layout.textClass}`}
|
||
style={{color: cms.bodyColor}}
|
||
>
|
||
{value.description}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|