From 8a8b01c1d57c15927af6b99f0ddaf437f6757d03 Mon Sep 17 00:00:00 2001 From: richardblack-Harness Date: Wed, 10 Sep 2025 20:24:47 +0100 Subject: [PATCH 1/4] Draft landing page update --- src/components/LearnAboutPlatform/index.tsx | 4 - .../home/components/CategoryGrid.module.scss | 163 ++++++++++++++ src/pages/home/components/CategoryGrid.tsx | 205 ++++++++++++++++++ src/pages/home/components/categories.data.ts | 61 ++++++ src/pages/index.module.scss | 46 ++-- src/pages/index.tsx | 33 +-- static/img/icon-ar.svg | 9 + static/img/icon-database-devops.svg | 9 + 8 files changed, 494 insertions(+), 36 deletions(-) create mode 100644 src/pages/home/components/CategoryGrid.module.scss create mode 100644 src/pages/home/components/CategoryGrid.tsx create mode 100644 src/pages/home/components/categories.data.ts create mode 100644 static/img/icon-ar.svg create mode 100644 static/img/icon-database-devops.svg diff --git a/src/components/LearnAboutPlatform/index.tsx b/src/components/LearnAboutPlatform/index.tsx index 3d8bf309826..3bc1430a604 100644 --- a/src/components/LearnAboutPlatform/index.tsx +++ b/src/components/LearnAboutPlatform/index.tsx @@ -20,10 +20,6 @@ export default function LearnAboutPlatform(): JSX.Element {

Learn More

-
-

Modules

-
-
diff --git a/src/pages/home/components/CategoryGrid.module.scss b/src/pages/home/components/CategoryGrid.module.scss new file mode 100644 index 00000000000..72056fead8c --- /dev/null +++ b/src/pages/home/components/CategoryGrid.module.scss @@ -0,0 +1,163 @@ +/* spacing around the block */ +.wrapper { padding: 3rem 0; } + +/* ---------- Mobile (accordion) ---------- */ +.categoryDetails { + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 12px; + overflow: hidden; + background: var(--ifm-card-background-color); + & + & { margin-top: 1rem; } +} +.categorySummary { + display: flex; + flex-direction: column; + gap: .25rem; + padding: 1rem; + cursor: pointer; + position: relative; + summary::-webkit-details-marker { display: none; } +} +.categoryTitle { + margin: 0; + font-size: clamp(1.1rem, 1.2vw + 1rem, 1.35rem); +} +.categoryBlurb { margin: .25rem 0 0 0; opacity: .8; } + +/* simple vertical list on mobile */ +.tileList { list-style: none; margin: 0; padding: 0 1rem 1rem; } +.tileListItem + .tileListItem { margin-top: .5rem; } + +.tileRow { + display: flex; + align-items: flex-start; /* align top for multiline titles */ + gap: 12px; + background: var(--ifm-card-background-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 12px; + padding: .75rem .9rem; + text-decoration: none; + transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease; + &:hover, + &:focus-visible { + transform: translateY(-1px); + border-color: var(--ifm-color-primary); + box-shadow: 0 8px 24px rgba(0,0,0,.06); + outline: none; + } +} + +/* ---------- Desktop: expanding columns ---------- */ +.categoryColumns { + display: flex; + gap: 16px; +} + +/* base column look */ +.categoryCol { + --radius: 16px; + flex: 1 1 0px; + display: flex; + flex-direction: column; + background: var(--ifm-card-background-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: var(--radius); + padding: 14px; + transition: + flex-basis 220ms ease, + flex-grow 220ms ease, + transform 180ms ease, + box-shadow 180ms ease, + border-color 180ms ease, + background 180ms ease; + min-width: 0; +} + +/* Hover container effect: slightly compress others, expand hovered */ +.categoryColumns:hover .categoryCol { flex: .95 1 0px; } +.categoryCol:hover, +.categoryCol.isFocused { + flex: 1.35 1 0px; + transform: translateY(-2px); + border-color: var(--ifm-color-primary); + box-shadow: 0 12px 28px rgba(0,0,0,.06); +} + +/* column header */ +.colHeader { margin-bottom: .5rem; } +.colHeader .categoryTitle { font-size: 1.15rem; } +.colHeader .categoryBlurb { font-size: .95rem; opacity: .8; } + +/* vertical tiles inside each column */ +.colTiles { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 10px; +} + +.colTileItem { min-width: 0; } + +.colTile { + display: flex; + align-items: flex-start; /* align top for multiline titles */ + gap: 12px; + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 12px; + padding: 10px 12px; + text-decoration: none; + transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease, background 150ms ease; + &:hover, + &:focus-visible { + transform: translateY(-1px); + border-color: var(--ifm-color-primary); + box-shadow: 0 8px 24px rgba(0,0,0,.06); + outline: none; + background: var(--ifm-card-background-color); + } +} + +.iconWrap img.featureSvg { + width: 28px; + height: 28px; + object-fit: contain; +} + +.colTileText { + display: flex; /* allow title + badge */ + align-items: baseline; + gap: 8px; + min-width: 0; + flex: 1 1 auto; + flex-wrap: wrap; /* allow wrapping when tight */ +} + +.tileTitle { + font-weight: 600; + line-height: 1.25; + white-space: normal; /* allow wrapping */ + overflow: visible; + text-overflow: clip; + word-break: keep-all; +} + +/* badges */ +.badge { + font-size: 10px; + font-weight: 700; + padding: 2px 6px; + border-radius: 999px; + border: 1px solid currentColor; + opacity: .9; +} +.badge_NEW { color: var(--ifm-color-success); } +.badge_EA { color: var(--ifm-color-warning); } +.badge_GA { color: var(--ifm-color-primary); } + +/* responsive: fall back to mobile when narrow */ +@media (max-width: 900px) { + .categoryColumns { display: none; } +} \ No newline at end of file diff --git a/src/pages/home/components/CategoryGrid.tsx b/src/pages/home/components/CategoryGrid.tsx new file mode 100644 index 00000000000..76d4c60fbf2 --- /dev/null +++ b/src/pages/home/components/CategoryGrid.tsx @@ -0,0 +1,205 @@ +import React, { useEffect, useMemo, useState } from "react"; +import Link from "@docusaurus/Link"; +import clsx from "clsx"; +import styles from "./CategoryGrid.module.scss"; +import type { Category } from "./categories.data"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import { moduleList } from "@site/src/components/LearnAboutPlatform/data/moduleListData"; + +/* ----- utils ----- */ +const stripLeadingSlash = (p?: string) => (p && p.startsWith("/") ? p.slice(1) : p) || ""; +const joinBase = (baseUrl: string, rel: string) => + (baseUrl.endsWith("/") ? baseUrl : baseUrl + "/") + stripLeadingSlash(rel); + +/* Optional overrides for odd assets */ +const ICON_ALIASES: Record = { + // ar: "img/icon_artifact_registry.svg", +}; + +const kebab = (s: string) => + s.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, ""); +const snake = (s: string) => + s.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, ""); + +function useIsMobile(breakpoint = 900) { + const [isMobile, setIsMobile] = useState(false); + useEffect(() => { + const mq = window.matchMedia(`(max-width: ${breakpoint}px)`); + const onChange = () => setIsMobile(mq.matches); + onChange(); + mq.addEventListener?.("change", onChange); + return () => mq.removeEventListener?.("change", onChange); + }, [breakpoint]); + return isMobile; +} + +function useModuleIconMap() { + return useMemo(() => { + const map = new Map(); + moduleList.forEach((m: any) => { + if (!m?.module) return; + const rel = (m.icon && stripLeadingSlash(m.icon)) || `img/icon-${m.module}.svg`; + map.set(m.module, rel); + }); + return map; + }, []); +} + +function buildIconCandidates( + item: Category["items"][number], + moduleIconMap: Map +) { + const roots = ["img", "icons"]; + const list: string[] = []; + + if (item.icon) list.push(stripLeadingSlash(item.icon)); + if (item.module && ICON_ALIASES[item.module]) list.push(ICON_ALIASES[item.module]); + if (item.module && moduleIconMap.get(item.module)) list.push(moduleIconMap.get(item.module)!); + + if (item.module) { + const hy = `icon-${item.module}`; + const us = `icon_${item.module}`; + roots.forEach((r) => list.push(`${r}/${hy}.svg`, `${r}/${us}.svg`, `${r}/${hy}.png`, `${r}/${us}.png`)); + } + + const k = kebab(item.name); + const s = snake(item.name); + roots.forEach((r) => + list.push( + `${r}/icon-${k}.svg`, + `${r}/icon_${s}.svg`, + `${r}/${k}.svg`, + `${r}/${s}.svg`, + `${r}/icon-${k}.png`, + `${r}/icon_${s}.png`, + `${r}/${k}.png`, + `${r}/${s}.png` + ) + ); + + return Array.from(new Set(list)); +} + +function FallbackImg({ + baseUrl, + candidates, + className, + alt = "", +}: { + baseUrl: string; + candidates: string[]; + className?: string; + alt?: string; +}) { + const [idx, setIdx] = useState(0); + const src = candidates[idx] ? joinBase(baseUrl, candidates[idx]) : ""; + return ( + {alt} { + if (idx < candidates.length - 1) setIdx(idx + 1); + else if (process.env.NODE_ENV !== "production") { + // eslint-disable-next-line no-console + console.warn("Icon not found; tried:", candidates); + } + }} + /> + ); +} + +/* ----- main ----- */ +export default function CategoryGrid({ categories }: { categories: Category[] }) { + const isMobile = useIsMobile(); + const { siteConfig: { baseUrl = "/" } = {} } = useDocusaurusContext(); + const moduleIconMap = useModuleIconMap(); + + // Track which column is keyboard-focused so it expands like hover. + const [focusedCol, setFocusedCol] = useState(null); + + return ( +
+
+ {isMobile ? ( + // Mobile: collapsible accordions (unchanged) + <> + {categories.map((cat, i) => ( +
+ + {cat.title} + {cat.blurb && {cat.blurb}} + +
    + {cat.items.map((item) => ( +
  • + + + {item.name} + {item.badge && {item.badge}} + +
  • + ))} +
+
+ ))} + + ) : ( + // Desktop: columns that expand on hover/focus +
+ {categories.map((cat, idx) => ( +
setFocusedCol(idx)} + onBlurCapture={(e) => { + // collapse when focus leaves the column + if (!(e.currentTarget as HTMLElement).contains(e.relatedTarget as Node)) { + setFocusedCol(null); + } + }} + > +
+

{cat.title}

+ {cat.blurb &&

{cat.blurb}

} +
+ +
    + {cat.items.map((item) => ( +
  • + + +
    + {item.name} + {item.badge && ( + {item.badge} + )} +
    + +
  • + ))} +
+
+ ))} +
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/pages/home/components/categories.data.ts b/src/pages/home/components/categories.data.ts new file mode 100644 index 00000000000..20b5550fe1e --- /dev/null +++ b/src/pages/home/components/categories.data.ts @@ -0,0 +1,61 @@ +// src/pages/Home/components/categories.data.ts +export type ModuleLink = { + name: string; + href: string; + /** Optional explicit icon path (relative to site static dir, e.g. "img/icon-ci.svg") */ + icon?: string; + /** Module slug used for fallback icon: img/icon-{module}.svg */ + module: string; + badge?: 'NEW' | 'EA' | 'GA'; + }; + + export type Category = { + title: string; + blurb?: string; + items: ModuleLink[]; + }; + + export const categories: Category[] = [ + { + title: "CI/CD & DevOps", + blurb: "Ship faster with modern delivery pipelines.", + items: [ + { name: "Continuous Delivery & GitOps", href: "/docs/continuous-delivery", module: "cd" }, + { name: "Continuous Integration", href: "/docs/continuous-integration", module: "ci" }, + { name: "Internal Developer Portal", href: "/docs/internal-developer-portal", module: "idp" }, + { name: "Infrastructure as Code Management", href: "/docs/infra-as-code-management", module: "iacm", badge: "NEW" }, + { name: "Database DevOps", href: "/docs/database-devops", module: "dbd", badge: "NEW" }, + { name: "Artifact Registry", href: "/docs/artifact-registry", module: "ar", badge: "NEW" }, + { name: "Cloud Development Environments", href: "/docs/cloud-development-environments", module: "cde", badge: "NEW" }, + ], + }, + { + title: "AI for Testing & Resilience", + blurb: "Raise confidence with intelligent quality gates.", + items: [ + { name: "Feature Management & Experimentation", href: "/docs/feature-management-experimentation", module: "fme" }, + { name: "Chaos Engineering", href: "/docs/chaos-engineering", module: "ce" }, + { name: "AI Test Automation", href: "/docs/ai-test-automation", module: "aita", badge: "NEW" }, + { name: "AI SRE", href: "/docs/ai-sre", module: "aisre", badge: "NEW" }, + ], + }, + { + title: "AI for Security & Compliance", + blurb: "Protect apps from design to runtime.", + items: [ + { name: "Security Testing Orchestration", href: "/docs/security-testing-orchestration", module: "sto" }, + { name: "Application & API Posture Management", href: "/docs/aapm", module: "aapm" }, + { name: "Application & API Security Testing", href: "/docs/aast", module: "aast" }, + { name: "Supply Chain Security", href: "/docs/supply-chain-security", module: "ssca" }, + { name: "Application & API Protection", href: "/docs/aap", module: "aap" }, + ], + }, + { + title: "AI for Cost & Optimization", + blurb: "Optimize spend and developer time.", + items: [ + { name: "Cloud Cost Management", href: "/docs/cloud-cost-management", module: "ccm" }, + { name: "Software Engineering Insights", href: "/docs/software-engineering-insights", module: "sei" }, + ], + }, + ]; \ No newline at end of file diff --git a/src/pages/index.module.scss b/src/pages/index.module.scss index 643ae6dc03b..e41435c99f3 100644 --- a/src/pages/index.module.scss +++ b/src/pages/index.module.scss @@ -22,16 +22,31 @@ } } .heroBanner { - padding-top: 7rem; - padding-bottom: 7rem; - /* text-align: center; */ + display: flex; + align-items: center; + justify-content: center; + text-align: center; + padding: 6rem 1rem 4rem; + border-bottom: 1px solid var(--ifm-color-emphasis-200); position: relative; overflow: hidden; - display: flex; - // background: url(img/hero.svg) no-repeat bottom right; - min-height: 400px; - background-size: 61%; } + +.heroInner { + max-width: 800px; + margin: 0 auto; +} + +.heroTitle { + font-size: clamp(2.5rem, 6vw, 4rem); + font-weight: 700; + line-height: 1.2; + background: #39ABE4; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-bottom: 1rem; +} + .heroContainer { // flex-basis: 42%; z-index: 9; @@ -54,17 +69,14 @@ width: 101%; } } -.heroTitle { - font-size: 48px; - text-align: left; - margin-bottom: 24px; - letter-spacing: -0.5px; -} + .heroSubTitle { - font-size: 18px; - line-height: 26px; - padding-right: 1em; - width: 42%; + font-size: clamp(1.125rem, 2.5vw, 1.5rem); + font-weight: 400; + color: var(--ifm-font-color-secondary); + margin: 0 auto; + max-width: 640px; + line-height: 1.6; } .buttons { display: flex; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 088ac14212a..ecfd60b45af 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -6,13 +6,16 @@ import clsx from 'clsx'; import React from 'react'; import allModuleAnimationDark from './assets/hdh_hero-dark.json'; import allModuleAnimation from './assets/hdh_hero.json'; -import HomepageFeatures from '@site/src/components/HomepageFeatures'; import LearnAboutPlatform from '@site/src/components/LearnAboutPlatform'; import HomepageUniversity from '@site/src/components/HomepageUniversity'; import Feedback from '@site/src/components/Feedback'; import styles from './index.module.scss'; import { useColorMode } from '@docusaurus/theme-common'; +// NEW: category layout replacing the old "Get Started / Learn More" surface +import CategoryGrid from '@site/src/pages/home/components/CategoryGrid'; +import { categories } from '@site/src/pages/home/components/categories.data'; + function HomePageAnimation() { const { colorMode } = useColorMode(); return ( @@ -32,20 +35,16 @@ function HomePageAnimation() { ); } + function HomepageHeader() { const { siteConfig } = useDocusaurusContext(); return ( -
-
-
-

{siteConfig.title}

-

{siteConfig.tagline}

-
-
-
- +
+
+

{siteConfig.title}

+

{siteConfig.tagline}

-
+ ); } @@ -59,17 +58,21 @@ export default function Home(): JSX.Element {
-
- -
+ {/* NEW: Category grid (desktop: hover-expand; mobile: collapsible) */} + + + {/* Keep Platform section as-is */}
+ + {/* Keep Feedback widget as-is */}
+ {/* Keep University carousel + footer as-is */}
); -} +} \ No newline at end of file diff --git a/static/img/icon-ar.svg b/static/img/icon-ar.svg new file mode 100644 index 00000000000..bc295cdfe79 --- /dev/null +++ b/static/img/icon-ar.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/static/img/icon-database-devops.svg b/static/img/icon-database-devops.svg new file mode 100644 index 00000000000..e92c605fe25 --- /dev/null +++ b/static/img/icon-database-devops.svg @@ -0,0 +1,9 @@ + + + + + + + + + From 8715678f096c8ae44bd63679fb1e3d15e0a046c5 Mon Sep 17 00:00:00 2001 From: richardblack-Harness Date: Thu, 11 Sep 2025 10:42:27 +0100 Subject: [PATCH 2/4] Update landing page styling --- .../CategoryGrid}/CategoryGrid.module.scss | 79 ++++++++----------- .../CategoryGrid}/CategoryGrid.tsx | 0 .../CategoryGrid}/categories.data.ts | 12 +-- src/pages/index.tsx | 4 +- 4 files changed, 42 insertions(+), 53 deletions(-) rename src/{pages/home/components => components/CategoryGrid}/CategoryGrid.module.scss (67%) rename src/{pages/home/components => components/CategoryGrid}/CategoryGrid.tsx (100%) rename src/{pages/home/components => components/CategoryGrid}/categories.data.ts (79%) diff --git a/src/pages/home/components/CategoryGrid.module.scss b/src/components/CategoryGrid/CategoryGrid.module.scss similarity index 67% rename from src/pages/home/components/CategoryGrid.module.scss rename to src/components/CategoryGrid/CategoryGrid.module.scss index 72056fead8c..db0e2c7bdf7 100644 --- a/src/pages/home/components/CategoryGrid.module.scss +++ b/src/components/CategoryGrid/CategoryGrid.module.scss @@ -59,28 +59,19 @@ flex: 1 1 0px; display: flex; flex-direction: column; - background: var(--ifm-card-background-color); - border: 1px solid var(--ifm-color-emphasis-200); + background: var(--ifm-background-surface-color); border-radius: var(--radius); - padding: 14px; - transition: - flex-basis 220ms ease, - flex-grow 220ms ease, - transform 180ms ease, - box-shadow 180ms ease, - border-color 180ms ease, - background 180ms ease; - min-width: 0; + padding: 16px; + transition: transform 180ms ease, box-shadow 180ms ease; + box-shadow: 0 2px 6px rgba(0,0,0,.08); /* subtle shadow */ } /* Hover container effect: slightly compress others, expand hovered */ -.categoryColumns:hover .categoryCol { flex: .95 1 0px; } +//.categoryColumns:hover .categoryCol { flex: .95 1 0px; } .categoryCol:hover, .categoryCol.isFocused { - flex: 1.35 1 0px; transform: translateY(-2px); - border-color: var(--ifm-color-primary); - box-shadow: 0 12px 28px rgba(0,0,0,.06); + box-shadow: 0 8px 20px rgba(0,0,0,.12); } /* column header */ @@ -102,56 +93,54 @@ .colTile { display: flex; - align-items: flex-start; /* align top for multiline titles */ + align-items: center; gap: 12px; - background: var(--ifm-background-surface-color); - border: 1px solid var(--ifm-color-emphasis-200); - border-radius: 12px; - padding: 10px 12px; + padding: 8px 0; + border-radius: 8px; text-decoration: none; - transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease, background 150ms ease; - &:hover, - &:focus-visible { - transform: translateY(-1px); - border-color: var(--ifm-color-primary); - box-shadow: 0 8px 24px rgba(0,0,0,.06); - outline: none; - background: var(--ifm-card-background-color); - } + transition: background 150ms ease; +} + +.colTile:hover, +.colTile:focus-visible { + background: rgba(0,0,0,0.04); /* subtle hover bg */ + outline: none; } .iconWrap img.featureSvg { - width: 28px; - height: 28px; + width: 22px; + height: 22px; object-fit: contain; + flex-shrink: 0; } +/* Column tile text container */ .colTileText { - display: flex; /* allow title + badge */ - align-items: baseline; - gap: 8px; - min-width: 0; + display: flex; + align-items: center; + gap: 6px; flex: 1 1 auto; - flex-wrap: wrap; /* allow wrapping when tight */ + min-width: 0; + flex-wrap: wrap; } .tileTitle { - font-weight: 600; - line-height: 1.25; - white-space: normal; /* allow wrapping */ + font-size: 0.9rem; + font-weight: 500; + line-height: 1.3; + white-space: normal; overflow: visible; - text-overflow: clip; - word-break: keep-all; + text-overflow: unset; } /* badges */ .badge { - font-size: 10px; - font-weight: 700; - padding: 2px 6px; + font-size: 0.7rem; + font-weight: 600; + padding: 1px 5px; border-radius: 999px; border: 1px solid currentColor; - opacity: .9; + line-height: 1; } .badge_NEW { color: var(--ifm-color-success); } .badge_EA { color: var(--ifm-color-warning); } diff --git a/src/pages/home/components/CategoryGrid.tsx b/src/components/CategoryGrid/CategoryGrid.tsx similarity index 100% rename from src/pages/home/components/CategoryGrid.tsx rename to src/components/CategoryGrid/CategoryGrid.tsx diff --git a/src/pages/home/components/categories.data.ts b/src/components/CategoryGrid/categories.data.ts similarity index 79% rename from src/pages/home/components/categories.data.ts rename to src/components/CategoryGrid/categories.data.ts index 20b5550fe1e..4ef0030f4d4 100644 --- a/src/pages/home/components/categories.data.ts +++ b/src/components/CategoryGrid/categories.data.ts @@ -17,13 +17,13 @@ export type ModuleLink = { export const categories: Category[] = [ { - title: "CI/CD & DevOps", + title: "AI for DevOps & Automation", blurb: "Ship faster with modern delivery pipelines.", items: [ { name: "Continuous Delivery & GitOps", href: "/docs/continuous-delivery", module: "cd" }, { name: "Continuous Integration", href: "/docs/continuous-integration", module: "ci" }, { name: "Internal Developer Portal", href: "/docs/internal-developer-portal", module: "idp" }, - { name: "Infrastructure as Code Management", href: "/docs/infra-as-code-management", module: "iacm", badge: "NEW" }, + { name: "Infrastructure as Code Management", href: "/docs/infrastructure-as-code-management", module: "iacm" }, { name: "Database DevOps", href: "/docs/database-devops", module: "dbd", badge: "NEW" }, { name: "Artifact Registry", href: "/docs/artifact-registry", module: "ar", badge: "NEW" }, { name: "Cloud Development Environments", href: "/docs/cloud-development-environments", module: "cde", badge: "NEW" }, @@ -44,10 +44,10 @@ export type ModuleLink = { blurb: "Protect apps from design to runtime.", items: [ { name: "Security Testing Orchestration", href: "/docs/security-testing-orchestration", module: "sto" }, - { name: "Application & API Posture Management", href: "/docs/aapm", module: "aapm" }, - { name: "Application & API Security Testing", href: "/docs/aast", module: "aast" }, - { name: "Supply Chain Security", href: "/docs/supply-chain-security", module: "ssca" }, - { name: "Application & API Protection", href: "/docs/aap", module: "aap" }, + { name: "Application & API Posture Management", href: "https://www.traceable.ai/application-discovery-and-risk-assessment", module: "adra" }, + { name: "Application & API Security Testing", href: "https://www.traceable.ai/application-security-testing", module: "ast" }, + { name: "Supply Chain Security", href: "/docs/software-supply-chain-assurance", module: "ssca" }, + { name: "Application & API Protection", href: "https://www.traceable.ai/application-runtime-protection", module: "arp" }, ], }, { diff --git a/src/pages/index.tsx b/src/pages/index.tsx index ecfd60b45af..865176a2f10 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -13,8 +13,8 @@ import styles from './index.module.scss'; import { useColorMode } from '@docusaurus/theme-common'; // NEW: category layout replacing the old "Get Started / Learn More" surface -import CategoryGrid from '@site/src/pages/home/components/CategoryGrid'; -import { categories } from '@site/src/pages/home/components/categories.data'; +import CategoryGrid from '@site/src/components/CategoryGrid/CategoryGrid'; +import { categories } from '@site/src/components/CategoryGrid/categories.data'; function HomePageAnimation() { const { colorMode } = useColorMode(); From 4b41321503a716c8cb7b2b4267399161c2ad8458 Mon Sep 17 00:00:00 2001 From: richardblack-Harness Date: Thu, 11 Sep 2025 10:47:38 +0100 Subject: [PATCH 3/4] Update landing page styling --- src/components/CategoryGrid/CategoryGrid.module.scss | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/CategoryGrid/CategoryGrid.module.scss b/src/components/CategoryGrid/CategoryGrid.module.scss index db0e2c7bdf7..e02a7e11dec 100644 --- a/src/components/CategoryGrid/CategoryGrid.module.scss +++ b/src/components/CategoryGrid/CategoryGrid.module.scss @@ -95,15 +95,18 @@ display: flex; align-items: center; gap: 12px; - padding: 8px 0; + padding: 8px 10px; border-radius: 8px; text-decoration: none; - transition: background 150ms ease; + transition: background 150ms ease, border-color 150ms ease, box-shadow 150ms ease; + border: 1px solid transparent; /* invisible by default */ } .colTile:hover, .colTile:focus-visible { - background: rgba(0,0,0,0.04); /* subtle hover bg */ + background: var(--ifm-hover-overlay); /* theme-aware subtle bg */ + border-color: var(--ifm-color-primary); + box-shadow: 0 2px 6px rgba(0,0,0,.05); outline: none; } From 7f4c8033a81e5cc37884004644bb76b4951f05b7 Mon Sep 17 00:00:00 2001 From: richardblack-Harness Date: Thu, 11 Sep 2025 11:28:20 +0100 Subject: [PATCH 4/4] Update landing page styling --- .../CategoryGrid/CategoryGrid.module.scss | 66 ++++++++++++++----- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/components/CategoryGrid/CategoryGrid.module.scss b/src/components/CategoryGrid/CategoryGrid.module.scss index e02a7e11dec..a61ce90ee28 100644 --- a/src/components/CategoryGrid/CategoryGrid.module.scss +++ b/src/components/CategoryGrid/CategoryGrid.module.scss @@ -1,3 +1,8 @@ +:root { + /* tweak this if needed after a quick eyeball check */ + --col-header-min: 96px; /* works well for title + up to 2 blurb lines */ +} + /* spacing around the block */ .wrapper { padding: 3rem 0; } @@ -75,9 +80,28 @@ } /* column header */ -.colHeader { margin-bottom: .5rem; } -.colHeader .categoryTitle { font-size: 1.15rem; } -.colHeader .categoryBlurb { font-size: .95rem; opacity: .8; } +.colHeader { + /* reserve consistent space for title + blurb across all columns */ + min-height: var(--col-header-min); + display: flex; + flex-direction: column; + justify-content: flex-start; + margin-bottom: 4px; /* keep your existing spacing */ +} + +.colHeader .categoryTitle { + font-size: 1rem; + font-weight: 600; + line-height: 1.3; + margin: 0 0 0.25rem 0; +} +.colHeader .categoryBlurb { + font-size: 0.95rem; + line-height: 1.4; + opacity: 0.8; + margin: 0; + max-width: 90%; +} /* vertical tiles inside each column */ .colTiles { @@ -95,26 +119,36 @@ display: flex; align-items: center; gap: 12px; - padding: 8px 10px; + padding: 8px 0; border-radius: 8px; text-decoration: none; - transition: background 150ms ease, border-color 150ms ease, box-shadow 150ms ease; - border: 1px solid transparent; /* invisible by default */ + transition: background 150ms ease; } .colTile:hover, .colTile:focus-visible { - background: var(--ifm-hover-overlay); /* theme-aware subtle bg */ - border-color: var(--ifm-color-primary); - box-shadow: 0 2px 6px rgba(0,0,0,.05); + background: rgba(0,0,0,0.04); /* subtle hover bg */ outline: none; } +.colTile, +.tileRow { + align-items: center; /* ensure icon + text share the same vertical center */ +} + +.iconWrap { + display: inline-flex; + align-items: center; + justify-content: center; + align-self: center; /* keep the icon centered even if text wraps */ + height: 22px; /* = icon size */ +} + .iconWrap img.featureSvg { - width: 22px; - height: 22px; + width: 20px; + height: 20px; object-fit: contain; - flex-shrink: 0; + display: block; } /* Column tile text container */ @@ -128,12 +162,10 @@ } .tileTitle { - font-size: 0.9rem; + font-size: 0.85rem; font-weight: 500; - line-height: 1.3; - white-space: normal; - overflow: visible; - text-overflow: unset; + line-height: 1.3; + white-space: normal; } /* badges */