Learn page svgs updated

This commit is contained in:
adilallo
2026-05-20 23:01:55 -06:00
parent 1688ac85c9
commit ea346abad8
55 changed files with 948 additions and 764 deletions
@@ -6,9 +6,8 @@
*/
import { memo } from "react";
import {
getAssetPath,
ASSETS,
contentBlogTagPath,
contentCatalogSlugForFallback,
CONTENT_CATALOG_SLUG_ORDER,
} from "../../../../lib/assetUtils";
import ContentContainerView from "./ContentContainer.view";
@@ -36,26 +35,14 @@ const ContentContainerContainer = memo<ContentContainerProps>(
: "text-[var(--color-content-inverse-brand-royal)]";
const getIconImage = (slug: string): string => {
const icons = [
getAssetPath(ASSETS.ICON_1),
getAssetPath(ASSETS.ICON_2),
getAssetPath(ASSETS.ICON_3),
];
const resolvedSlug =
CONTENT_CATALOG_SLUG_ORDER.indexOf(
slug as (typeof CONTENT_CATALOG_SLUG_ORDER)[number],
) >= 0
? slug
: contentCatalogSlugForFallback(slug);
if (!slug) return icons[0];
const index = CONTENT_CATALOG_SLUG_ORDER.indexOf(
slug as (typeof CONTENT_CATALOG_SLUG_ORDER)[number],
);
if (index >= 0) {
return contentBlogTagPath(slug);
}
const fallbackIndex =
Math.abs(
slug.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0),
) % icons.length;
return icons[fallbackIndex];
return contentBlogTagPath(resolvedSlug);
};
const iconImage = leadingImageSrc ?? getIconImage(post.slug);
@@ -1,11 +1,16 @@
"use client";
/**
* Figma: "Components" / ContentThumnailTemplate (19614-14838, 19041-13415).
* Vertical 260×390 (19060-15787); horizontal 320×225.5 (19041-13550).
* Figma: "Components" / Thumbnail (19428:22574).
* Vertical 260×390; horizontal 320×225.5; per-article backgrounds in public/content/blog/.
*/
import { memo } from "react";
import { getAssetPath, ASSETS } from "../../../../lib/assetUtils";
import {
contentBlogHorizontalPath,
contentBlogVerticalPath,
contentCatalogSlugForFallback,
CONTENT_CATALOG_SLUG_ORDER,
} from "../../../../lib/assetUtils";
import ContentThumbnailTemplateView from "./ContentThumbnailTemplate.view";
import type { ContentThumbnailTemplateProps } from "./ContentThumbnailTemplate.types";
@@ -23,7 +28,6 @@ const ContentThumbnailTemplateContainer = memo<ContentThumbnailTemplateProps>(
post: ContentThumbnailTemplateProps["post"],
variant: "vertical" | "horizontal",
): string => {
// Check if post has thumbnail images defined in frontmatter
if (post.frontmatter?.thumbnail) {
const imageName =
variant === "vertical"
@@ -31,18 +35,21 @@ const ContentThumbnailTemplateContainer = memo<ContentThumbnailTemplateProps>(
: post.frontmatter.thumbnail.horizontal;
if (imageName) {
// Return path to image in public/content/blog directory
return `/content/blog/${imageName}`;
}
}
// Fallback to default images if no thumbnail specified
const fallbackImages: Record<string, string> = {
vertical: getAssetPath(ASSETS.VERTICAL_1),
horizontal: getAssetPath(ASSETS.HORIZONTAL_1),
};
const slug = post.slug;
const resolvedSlug =
CONTENT_CATALOG_SLUG_ORDER.indexOf(
slug as (typeof CONTENT_CATALOG_SLUG_ORDER)[number],
) >= 0
? slug
: contentCatalogSlugForFallback(slug);
return fallbackImages[variant] || fallbackImages.vertical;
return variant === "vertical"
? contentBlogVerticalPath(resolvedSlug)
: contentBlogHorizontalPath(resolvedSlug);
};
const backgroundImage = getBackgroundImage(post, variant);
@@ -1,12 +1,17 @@
"use client";
import { memo } from "react";
import { getAssetPath } from "../../../../lib/assetUtils";
import {
getAssetPath,
contentBlogHorizontalPath,
contentBlogSectionPath,
CONTENT_CATALOG_SLUG_ORDER,
} from "../../../../lib/assetUtils";
import type { BlogPost } from "../../../../lib/content";
import ContentBannerView from "./ContentBanner.view";
import type { ContentBannerProps } from "./ContentBanner.types";
/** Figma: Section / ContentBanner — article (blog) and guide (content page template 22078:791901). */
/** Figma: Content page Template (19003:23305) — article ContentBanner per breakpoint. */
const ContentBannerContainer = memo<ContentBannerProps>(
({
post,
@@ -18,27 +23,42 @@ const ContentBannerContainer = memo<ContentBannerProps>(
}) => {
const variant = variantProp;
const getBackgroundImage = (blogPost: BlogPost): string => {
const resolveHorizontalImage = (blogPost: BlogPost): string => {
if (blogPost.frontmatter?.thumbnail?.horizontal) {
return `/content/blog/${blogPost.frontmatter.thumbnail.horizontal}`;
}
if (
CONTENT_CATALOG_SLUG_ORDER.includes(
blogPost.slug as (typeof CONTENT_CATALOG_SLUG_ORDER)[number],
)
) {
return contentBlogHorizontalPath(blogPost.slug);
}
return getAssetPath("assets/Content_Banner.svg");
};
const getBannerImageMd = (blogPost: BlogPost): string => {
const resolveSectionImage = (blogPost: BlogPost): string => {
if (blogPost.frontmatter?.banner?.horizontal) {
return `/content/blog/${blogPost.frontmatter.banner.horizontal}`;
}
if (blogPost.frontmatter?.thumbnail?.horizontal) {
return `/content/blog/${blogPost.frontmatter.thumbnail.horizontal}`;
if (
CONTENT_CATALOG_SLUG_ORDER.includes(
blogPost.slug as (typeof CONTENT_CATALOG_SLUG_ORDER)[number],
)
) {
return contentBlogSectionPath(blogPost.slug);
}
return getAssetPath("assets/Content_Banner_2.svg");
return resolveHorizontalImage(blogPost);
};
const backgroundImageSm =
variant === "article" ? getBackgroundImage(post) : undefined;
const backgroundImageMd =
variant === "article" ? getBannerImageMd(post) : undefined;
const backgroundImageHorizontal =
variant === "article" ? resolveHorizontalImage(post) : undefined;
const backgroundImageSection =
variant === "article" ? resolveSectionImage(post) : undefined;
return (
<ContentBannerView
@@ -46,8 +66,8 @@ const ContentBannerContainer = memo<ContentBannerProps>(
post={post}
leadingImageSrc={leadingImageSrc}
leadingImageAlt={leadingImageAlt}
backgroundImageSm={backgroundImageSm}
backgroundImageMd={backgroundImageMd}
backgroundImageHorizontal={backgroundImageHorizontal}
backgroundImageSection={backgroundImageSection}
rulePreview={rulePreview}
contentTone={contentTone}
/>
@@ -35,8 +35,10 @@ export interface ContentBannerViewProps {
post: BlogPost;
leadingImageSrc?: string;
leadingImageAlt?: string;
backgroundImageSm?: string;
backgroundImageMd?: string;
/** Article variant: horizontal thumbnail below lg (`320×225.5`). */
backgroundImageHorizontal?: string;
/** Article variant: section banner at md+ (`1920×672`, Figma Section orientation). */
backgroundImageSection?: string;
rulePreview?: ContentBannerRulePreview;
contentTone?: ContentContainerToneValue;
}
@@ -68,44 +68,71 @@ function ContentBannerGuideView({
);
}
/**
* Figma: Content page Template (19003:23305) — ContentBanner article instances.
* Horizontal thumbnail below md; Section SVG (1920×672) at md+.
*/
function ContentBannerArticleView({
post,
leadingImageSrc,
leadingImageAlt,
backgroundImageSm,
backgroundImageMd,
backgroundImageHorizontal,
backgroundImageSection,
}: ContentBannerViewProps) {
if (!backgroundImageSm || !backgroundImageMd) {
if (!backgroundImageHorizontal || !backgroundImageSection) {
return null;
}
return (
<div className="relative h-[275px] w-full pt-[var(--measures-spacing-016)] sm:h-[326px] sm:overflow-hidden md:h-[224px] md:pt-[var(--measures-spacing-008)] lg:h-[358.4px] lg:pt-[50px] xl:h-[504px] xl:pt-[112px]">
<div
data-node-id="19189:9053"
className="
relative z-[1] w-full overflow-visible
min-h-[275px]
pt-[var(--spacing-scale-016)] px-[var(--spacing-scale-016)]
pb-[var(--spacing-scale-064)]
sm:min-h-[326px] sm:pb-[var(--spacing-scale-048)]
md:min-h-[224px] md:px-[var(--spacing-scale-024)] md:pb-0
md:pt-[var(--spacing-scale-008)]
lg:min-h-[358.4px] lg:px-[var(--spacing-scale-048)] lg:py-[var(--spacing-scale-040)]
xl:min-h-[504px] xl:px-[var(--spacing-scale-064)] xl:py-[var(--spacing-scale-076)]
"
>
<div
className="absolute inset-0 aspect-[320/225.5] h-full w-full bg-cover bg-no-repeat"
style={{
backgroundImage: `url(${backgroundImageSm})`,
backgroundPosition: "center bottom",
}}
/>
aria-hidden
className="pointer-events-none absolute inset-x-0 top-0 -bottom-[var(--spacing-scale-024)] sm:-bottom-[var(--spacing-scale-032)] md:hidden"
data-name="ContentBannerBackgroundHorizontal"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={backgroundImageHorizontal}
alt=""
className="absolute inset-0 size-full max-w-none object-cover object-bottom"
/>
</div>
<div
className="absolute inset-0 hidden aspect-[640/224] h-full w-full bg-cover bg-no-repeat md:block"
style={{
backgroundImage: `url(${backgroundImageMd})`,
backgroundPosition: "center bottom",
}}
/>
aria-hidden
className="pointer-events-none absolute inset-x-0 top-0 -bottom-[var(--spacing-scale-032)] hidden md:block"
data-name="ContentBannerBackgroundSection"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={backgroundImageSection}
alt=""
className="absolute inset-0 size-full max-w-none object-cover object-center"
/>
</div>
<div
data-node-id="19189:9010"
className="
relative z-10 flex h-full flex-col
pl-[var(--measures-spacing-016)] pr-[96px]
justify-start
md:absolute md:inset-x-0 md:top-1/2 md:h-auto md:w-full md:-translate-y-1/2
md:pl-[var(--measures-spacing-024)] md:pr-[350px]
lg:static lg:top-auto lg:h-full lg:translate-y-0 lg:justify-start
lg:pl-[var(--measures-spacing-064)]
relative z-10
max-w-[calc(100%-96px)]
sm:max-w-[calc(100%-151px)]
md:max-w-[280px]
lg:max-w-[365px]
xl:max-w-[623px]
"
>
<ContentContainer