From ea346abad8a8e2fee48095d44d83e404125ccdc4 Mon Sep 17 00:00:00 2001
From: adilallo <39313955+adilallo@users.noreply.github.com>
Date: Wed, 20 May 2026 23:01:55 -0600
Subject: [PATCH] Learn page svgs updated
---
app/(marketing)/blog/[slug]/page.tsx | 17 ++--
app/(marketing)/blog/blog.css | 4 +
.../ContentContainer.container.tsx | 29 ++----
.../ContentThumbnailTemplate.container.tsx | 29 +++---
.../ContentBanner/ContentBanner.container.tsx | 46 +++++++---
.../ContentBanner/ContentBanner.types.ts | 6 +-
.../ContentBanner/ContentBanner.view.tsx | 73 ++++++++++-----
...ing-burnout-sustainability-in-the-ruins.md | 2 +-
...gital-mediation-and-the-death-of-nuance.md | 2 +-
.../blog/how-chaos-concentrates-control.md | 2 +-
...ntegrating-new-members-without-dilution.md | 2 +-
...ge-management-and-institutional-amnesia.md | 2 +-
.../making-decisions-without-hierarchy.md | 2 +-
.../blog/operational-security-mutual-aid.md | 2 +-
docs/guides/content-creation.md | 29 +++---
lib/assetUtils.ts | 44 ++++++---
.../assets/Content_Thumbnail/Horizontal_1.svg | 31 -------
.../assets/Content_Thumbnail/Horizontal_2.svg | 28 ------
.../assets/Content_Thumbnail/Horizontal_3.svg | 25 ------
public/assets/Content_Thumbnail/Icon_1.svg | 14 ---
public/assets/Content_Thumbnail/Icon_2.svg | 18 ----
public/assets/Content_Thumbnail/Icon_3.svg | 16 ----
.../assets/Content_Thumbnail/Vertical_1.svg | 31 -------
.../assets/Content_Thumbnail/Vertical_2.svg | 34 -------
.../assets/Content_Thumbnail/Vertical_3.svg | 35 --------
...sustainability-in-the-ruins-horizontal.svg | 46 +++++-----
...ut-sustainability-in-the-ruins-section.svg | 32 +++++++
...urnout-sustainability-in-the-ruins-tag.svg | 19 +---
...t-sustainability-in-the-ruins-vertical.svg | 52 +++++------
...ion-and-the-death-of-nuance-horizontal.svg | 73 ++++++++++-----
...iation-and-the-death-of-nuance-section.svg | 57 ++++++++++++
...-mediation-and-the-death-of-nuance-tag.svg | 15 +---
...ation-and-the-death-of-nuance-vertical.svg | 89 ++++++++++++++-----
...-chaos-concentrates-control-horizontal.svg | 41 ++++-----
...how-chaos-concentrates-control-section.svg | 29 ++++++
.../how-chaos-concentrates-control-tag.svg | 17 +---
...ow-chaos-concentrates-control-vertical.svg | 65 ++++++++------
...ew-members-without-dilution-horizontal.svg | 42 ++++-----
...g-new-members-without-dilution-section.svg | 36 ++++++++
...ating-new-members-without-dilution-tag.svg | 15 +---
...-new-members-without-dilution-vertical.svg | 46 +++++-----
...t-and-institutional-amnesia-horizontal.svg | 44 ++++-----
...ment-and-institutional-amnesia-section.svg | 31 +++++++
...nagement-and-institutional-amnesia-tag.svg | 19 +---
...ent-and-institutional-amnesia-vertical.svg | 49 +++++-----
...decisions-without-hierarchy-horizontal.svg | 42 ++++-----
...ng-decisions-without-hierarchy-section.svg | 33 +++++++
...g-decisions-without-hierarchy-vertical.svg | 54 +++++------
...ational-security-mutual-aid-horizontal.svg | 39 ++++----
...perational-security-mutual-aid-section.svg | 35 ++++++++
...erational-security-mutual-aid-vertical.svg | 55 ++++++------
.../resolving-active-conflicts-section.svg | 23 +++++
tests/components/ContentBanner.test.tsx | 55 ++++++++++++
tests/pages/blog.test.jsx | 7 +-
tests/unit/ContentContainer.test.jsx | 29 ++++--
55 files changed, 948 insertions(+), 764 deletions(-)
delete mode 100644 public/assets/Content_Thumbnail/Horizontal_1.svg
delete mode 100644 public/assets/Content_Thumbnail/Horizontal_2.svg
delete mode 100644 public/assets/Content_Thumbnail/Horizontal_3.svg
delete mode 100644 public/assets/Content_Thumbnail/Icon_1.svg
delete mode 100644 public/assets/Content_Thumbnail/Icon_2.svg
delete mode 100644 public/assets/Content_Thumbnail/Icon_3.svg
delete mode 100644 public/assets/Content_Thumbnail/Vertical_1.svg
delete mode 100644 public/assets/Content_Thumbnail/Vertical_2.svg
delete mode 100644 public/assets/Content_Thumbnail/Vertical_3.svg
create mode 100644 public/content/blog/avoiding-burnout-sustainability-in-the-ruins-section.svg
create mode 100644 public/content/blog/digital-mediation-and-the-death-of-nuance-section.svg
create mode 100644 public/content/blog/how-chaos-concentrates-control-section.svg
create mode 100644 public/content/blog/integrating-new-members-without-dilution-section.svg
create mode 100644 public/content/blog/knowledge-management-and-institutional-amnesia-section.svg
create mode 100644 public/content/blog/making-decisions-without-hierarchy-section.svg
create mode 100644 public/content/blog/operational-security-mutual-aid-section.svg
create mode 100644 public/content/blog/resolving-active-conflicts-section.svg
diff --git a/app/(marketing)/blog/[slug]/page.tsx b/app/(marketing)/blog/[slug]/page.tsx
index c7dc218..2b1ca9f 100644
--- a/app/(marketing)/blog/[slug]/page.tsx
+++ b/app/(marketing)/blog/[slug]/page.tsx
@@ -1,6 +1,7 @@
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import dynamic from "next/dynamic";
+import type { BlogPost } from "../../../../lib/content";
import {
getBlogPostBySlug,
getAllBlogPosts as getAllPosts,
@@ -201,7 +202,7 @@ export default async function BlogPostPage({ params }: PageProps) {
/>
{/* Content Banner */}
@@ -242,10 +243,16 @@ export default async function BlogPostPage({ params }: PageProps) {
/>
- {/* Main Content */}
-
- {/* Article Content */}
-
+ {/* Main Content — Figma Content page Template (19003:23305) article body instances */}
+
+
diff --git a/app/(marketing)/blog/blog.css b/app/(marketing)/blog/blog.css
index 60e5fad..e5c7fd3 100644
--- a/app/(marketing)/blog/blog.css
+++ b/app/(marketing)/blog/blog.css
@@ -1,4 +1,8 @@
/* Blog post body styling with semantic spacing */
+.post-body > :first-child {
+ margin-block-start: 0;
+}
+
.post-body p {
/* Scales with font size - uses logical properties for better writing mode support */
margin-block: 1em;
diff --git a/app/components/content/ContentContainer/ContentContainer.container.tsx b/app/components/content/ContentContainer/ContentContainer.container.tsx
index a60ca4a..cd119f7 100644
--- a/app/components/content/ContentContainer/ContentContainer.container.tsx
+++ b/app/components/content/ContentContainer/ContentContainer.container.tsx
@@ -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
(
: "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);
diff --git a/app/components/content/ContentThumbnailTemplate/ContentThumbnailTemplate.container.tsx b/app/components/content/ContentThumbnailTemplate/ContentThumbnailTemplate.container.tsx
index 673412a..648b1c3 100644
--- a/app/components/content/ContentThumbnailTemplate/ContentThumbnailTemplate.container.tsx
+++ b/app/components/content/ContentThumbnailTemplate/ContentThumbnailTemplate.container.tsx
@@ -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(
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(
: 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 = {
- 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);
diff --git a/app/components/sections/ContentBanner/ContentBanner.container.tsx b/app/components/sections/ContentBanner/ContentBanner.container.tsx
index 381bf0e..bb05a7f 100644
--- a/app/components/sections/ContentBanner/ContentBanner.container.tsx
+++ b/app/components/sections/ContentBanner/ContentBanner.container.tsx
@@ -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(
({
post,
@@ -18,27 +23,42 @@ const ContentBannerContainer = memo(
}) => {
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 (
(
post={post}
leadingImageSrc={leadingImageSrc}
leadingImageAlt={leadingImageAlt}
- backgroundImageSm={backgroundImageSm}
- backgroundImageMd={backgroundImageMd}
+ backgroundImageHorizontal={backgroundImageHorizontal}
+ backgroundImageSection={backgroundImageSection}
rulePreview={rulePreview}
contentTone={contentTone}
/>
diff --git a/app/components/sections/ContentBanner/ContentBanner.types.ts b/app/components/sections/ContentBanner/ContentBanner.types.ts
index eeff36e..5161ada 100644
--- a/app/components/sections/ContentBanner/ContentBanner.types.ts
+++ b/app/components/sections/ContentBanner/ContentBanner.types.ts
@@ -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;
}
diff --git a/app/components/sections/ContentBanner/ContentBanner.view.tsx b/app/components/sections/ContentBanner/ContentBanner.view.tsx
index e564ee8..646f30e 100644
--- a/app/components/sections/ContentBanner/ContentBanner.view.tsx
+++ b/app/components/sections/ContentBanner/ContentBanner.view.tsx
@@ -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 (
-
+
+ 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 */}
+

+
+ 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 */}
+

+
acc + c.charCodeAt(0), 0),
+ ) % CONTENT_CATALOG_SLUG_ORDER.length;
+ return CONTENT_CATALOG_SLUG_ORDER[index];
+}
+
/**
* Asset paths for common components
*/
@@ -101,17 +132,6 @@ export const ASSETS = {
BLUESKY_LOGO: "assets/Bluesky_Logo.svg",
GITLAB_ICON: "assets/GitLab_Icon.png",
- // Content thumbnails
- VERTICAL_1: "assets/Content_Thumbnail/Vertical_1.svg",
- VERTICAL_2: "assets/Content_Thumbnail/Vertical_2.svg",
- VERTICAL_3: "assets/Content_Thumbnail/Vertical_3.svg",
- HORIZONTAL_1: "assets/Content_Thumbnail/Horizontal_1.svg",
- HORIZONTAL_2: "assets/Content_Thumbnail/Horizontal_2.svg",
- HORIZONTAL_3: "assets/Content_Thumbnail/Horizontal_3.svg",
- ICON_1: "assets/Content_Thumbnail/Icon_1.svg",
- ICON_2: "assets/Content_Thumbnail/Icon_2.svg",
- ICON_3: "assets/Content_Thumbnail/Icon_3.svg",
-
// Content page decorative shapes
CONTENT_SHAPE_1: "assets/Content_Shape_1.svg",
CONTENT_SHAPE_2: "assets/Content_Shape_2.svg",
diff --git a/public/assets/Content_Thumbnail/Horizontal_1.svg b/public/assets/Content_Thumbnail/Horizontal_1.svg
deleted file mode 100644
index 838dafd..0000000
--- a/public/assets/Content_Thumbnail/Horizontal_1.svg
+++ /dev/null
@@ -1,31 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Horizontal_2.svg b/public/assets/Content_Thumbnail/Horizontal_2.svg
deleted file mode 100644
index ff6736d..0000000
--- a/public/assets/Content_Thumbnail/Horizontal_2.svg
+++ /dev/null
@@ -1,28 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Horizontal_3.svg b/public/assets/Content_Thumbnail/Horizontal_3.svg
deleted file mode 100644
index d1a81fa..0000000
--- a/public/assets/Content_Thumbnail/Horizontal_3.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Icon_1.svg b/public/assets/Content_Thumbnail/Icon_1.svg
deleted file mode 100644
index b8fd584..0000000
--- a/public/assets/Content_Thumbnail/Icon_1.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Icon_2.svg b/public/assets/Content_Thumbnail/Icon_2.svg
deleted file mode 100644
index 873505c..0000000
--- a/public/assets/Content_Thumbnail/Icon_2.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Icon_3.svg b/public/assets/Content_Thumbnail/Icon_3.svg
deleted file mode 100644
index 0bf598d..0000000
--- a/public/assets/Content_Thumbnail/Icon_3.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Vertical_1.svg b/public/assets/Content_Thumbnail/Vertical_1.svg
deleted file mode 100644
index ff5f25f..0000000
--- a/public/assets/Content_Thumbnail/Vertical_1.svg
+++ /dev/null
@@ -1,31 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Vertical_2.svg b/public/assets/Content_Thumbnail/Vertical_2.svg
deleted file mode 100644
index 0b9aa36..0000000
--- a/public/assets/Content_Thumbnail/Vertical_2.svg
+++ /dev/null
@@ -1,34 +0,0 @@
-
diff --git a/public/assets/Content_Thumbnail/Vertical_3.svg b/public/assets/Content_Thumbnail/Vertical_3.svg
deleted file mode 100644
index bc3df93..0000000
--- a/public/assets/Content_Thumbnail/Vertical_3.svg
+++ /dev/null
@@ -1,35 +0,0 @@
-
diff --git a/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-horizontal.svg b/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-horizontal.svg
index b2148f5..6a806b0 100644
--- a/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-horizontal.svg
+++ b/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-horizontal.svg
@@ -1,31 +1,29 @@
diff --git a/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-section.svg b/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-section.svg
new file mode 100644
index 0000000..9462c92
--- /dev/null
+++ b/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-section.svg
@@ -0,0 +1,32 @@
+
diff --git a/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-tag.svg b/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-tag.svg
index 873505c..6cc21ef 100644
--- a/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-tag.svg
+++ b/public/content/blog/avoiding-burnout-sustainability-in-the-ruins-tag.svg
@@ -1,18 +1,3 @@
-