Create use cases pages

This commit is contained in:
adilallo
2026-05-18 16:50:44 -06:00
parent 40ce5064d6
commit 7c46cbd87b
28 changed files with 836 additions and 58 deletions
@@ -10,10 +10,21 @@ const ContentContainerContainer = memo<ContentContainerProps>(
post,
width = "200px",
size: sizeProp = "responsive",
tone: toneProp = "inverse",
leadingImageSrc,
leadingImageAlt,
showLeadingImage: showLeadingImageProp = true,
}) => {
const size = sizeProp;
const tone = toneProp;
const showLeadingImage = showLeadingImageProp;
const onLight = tone === "onLight";
const titleColor = onLight
? "text-[var(--color-content-default-primary)] group-hover:text-[var(--color-content-default-brand-primary)]"
: "text-[var(--color-content-inverse-brand-royal)] group-hover:text-blue-200";
const bodyColor = onLight
? "text-[var(--color-content-default-secondary)]"
: "text-[var(--color-content-inverse-brand-royal)]";
// Get the corresponding icon based on the same logic as background images
const getIconImage = (slug: string): string => {
const icons = [
@@ -67,31 +78,33 @@ const ContentContainerContainer = memo<ContentContainerProps>(
const titleClasses =
size === "xs"
? "font-bricolage font-medium text-[18px] leading-[120%] text-[var(--color-content-inverse-brand-royal)] group-hover:text-blue-200 transition-colors"
: "font-bricolage font-medium text-[18px] leading-[120%] sm:text-[24px] sm:leading-[24px] md:text-[32px] md:leading-[110%] lg:text-[44px] lg:leading-[110%] xl:text-[64px] xl:leading-[110%] text-[var(--color-content-inverse-brand-royal)] group-hover:text-blue-200 transition-colors";
? `font-bricolage font-medium text-[18px] leading-[120%] transition-colors ${titleColor}`
: `font-bricolage font-medium text-[18px] leading-[120%] sm:text-[24px] sm:leading-[24px] md:text-[32px] md:leading-[110%] lg:text-[44px] lg:leading-[110%] xl:text-[64px] xl:leading-[110%] transition-colors ${titleColor}`;
const descriptionClasses =
size === "xs"
? "font-inter font-normal text-[12px] leading-[16px] text-[var(--color-content-inverse-brand-royal)] max-w-md"
: "font-inter font-normal text-[12px] leading-[16px] sm:text-[14px] sm:leading-[20px] md:text-[14px] md:leading-[20px] lg:text-[18px] lg:leading-[130%] xl:text-[24px] xl:leading-[32px] text-[var(--color-content-inverse-brand-royal)]";
? `font-inter font-normal text-[12px] leading-[16px] max-w-md ${bodyColor}`
: `font-inter font-normal text-[12px] leading-[16px] sm:text-[14px] sm:leading-[20px] md:text-[14px] md:leading-[20px] lg:text-[18px] lg:leading-[130%] xl:text-[24px] xl:leading-[32px] ${bodyColor}`;
const authorClasses =
size === "xs"
? "font-inter font-normal text-[10px] leading-[14px] text-[var(--color-content-inverse-brand-royal)]"
: "font-inter font-normal text-[10px] leading-[14px] md:text-[12px] md:leading-[16px] lg:text-[14px] lg:leading-[20px] xl:text-[18px] xl:leading-[130%] text-[var(--color-content-inverse-brand-royal)]";
? `font-inter font-normal text-[10px] leading-[14px] ${bodyColor}`
: `font-inter font-normal text-[10px] leading-[14px] md:text-[12px] md:leading-[16px] lg:text-[14px] lg:leading-[20px] xl:text-[18px] xl:leading-[130%] ${bodyColor}`;
const dateClasses =
size === "xs"
? "font-inter font-normal text-[10px] leading-[14px] text-[var(--color-content-inverse-brand-royal)]"
: "font-inter font-normal text-[10px] leading-[14px] md:text-[12px] md:leading-[16px] lg:text-[14px] lg:leading-[20px] xl:text-[18px] xl:leading-[130%] text-[var(--color-content-inverse-brand-royal)]";
? `font-inter font-normal text-[10px] leading-[14px] ${bodyColor}`
: `font-inter font-normal text-[10px] leading-[14px] md:text-[12px] md:leading-[16px] lg:text-[14px] lg:leading-[20px] xl:text-[18px] xl:leading-[130%] ${bodyColor}`;
return (
<ContentContainerView
post={post}
width={width}
size={size}
tone={tone}
iconImage={iconImage}
iconAlt={iconAlt}
showLeadingImage={showLeadingImage}
containerClasses={containerClasses}
contentGapClasses={contentGapClasses}
textGapClasses={textGapClasses}
@@ -2,6 +2,9 @@ import type { BlogPost } from "../../../../lib/content";
export type ContentContainerSizeValue = "xs" | "responsive";
/** `inverse` — blog hero on imagery; `onLight` — marketing pages on default surface. */
export type ContentContainerToneValue = "inverse" | "onLight";
export interface ContentContainerProps {
post: BlogPost;
width?: string;
@@ -9,18 +12,26 @@ export interface ContentContainerProps {
* Content container size.
*/
size?: ContentContainerSizeValue;
/**
* Text color tokens. Default `inverse` (royal on dark/imagery).
*/
tone?: ContentContainerToneValue;
/** When set, replaces the default slug-based thumbnail icon. */
leadingImageSrc?: string;
/** Alt text for `leadingImageSrc`; defaults to post title. */
leadingImageAlt?: string;
/** When false, omits the icon row above the title. Default true. */
showLeadingImage?: boolean;
}
export interface ContentContainerViewProps {
post: BlogPost;
width: string;
size: "xs" | "responsive";
tone: ContentContainerToneValue;
iconImage: string;
iconAlt: string;
showLeadingImage: boolean;
containerClasses: string;
contentGapClasses: string;
textGapClasses: string;
@@ -7,6 +7,7 @@ function ContentContainerView({
size,
iconImage,
iconAlt,
showLeadingImage,
containerClasses,
contentGapClasses,
textGapClasses,
@@ -23,15 +24,16 @@ function ContentContainerView({
>
{/* Content Container - gap between icon and text */}
<div className={contentGapClasses}>
{/* Icon */}
<div className="w-[60px] h-[30px] flex items-center justify-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={iconImage}
alt={iconAlt}
className="w-[60px] h-[30px] object-contain"
/>
</div>
{showLeadingImage ? (
<div className="flex h-[30px] w-[60px] items-center justify-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={iconImage}
alt={iconAlt}
className="h-[30px] w-[60px] object-contain"
/>
</div>
) : null}
{/* Text Container */}
<div className={textGapClasses}>