1
0
mirror of synced 2025-12-19 18:10:59 -05:00

Add new landing hero and assets (#57450)

This commit is contained in:
Evan Bonsignori
2025-09-11 13:27:50 -07:00
committed by GitHub
parent 060ccbaf60
commit 0b0b3083dd
18 changed files with 353 additions and 206 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

View File

@@ -202,6 +202,10 @@ export const schema = {
product_video_transcript: { product_video_transcript: {
type: 'string', type: 'string',
}, },
// Hero image for landing pages
heroImage: {
type: 'string',
},
interactive: { interactive: {
type: 'boolean', type: 'boolean',
}, },

View File

@@ -39,6 +39,7 @@ export type ProductLandingContextT = {
introLinks: Record<string, string> | null introLinks: Record<string, string> | null
productVideo: string productVideo: string
productVideoTranscript: string productVideoTranscript: string
heroImage?: string
featuredLinks: Record<string, Array<FeaturedLink>> featuredLinks: Record<string, Array<FeaturedLink>>
productUserExamples: Array<{ username: string; description: string }> productUserExamples: Array<{ username: string; description: string }>
productCommunityExamples: Array<{ repo: string; description: string }> productCommunityExamples: Array<{ repo: string; description: string }>
@@ -113,6 +114,7 @@ export const getProductLandingContextFromRequest = async (
...pick(page, ['introPlainText', 'beta_product', 'intro']), ...pick(page, ['introPlainText', 'beta_product', 'intro']),
productVideo, productVideo,
productVideoTranscript: page.product_video_transcript || null, productVideoTranscript: page.product_video_transcript || null,
heroImage: page.heroImage || null,
hasGuidesPage, hasGuidesPage,
product: { product: {
href: productTree.href, href: productTree.href,

View File

@@ -1,14 +1,14 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { DefaultLayout } from '@/frame/components/DefaultLayout' import { DefaultLayout } from '@/frame/components/DefaultLayout'
import { useBespokeContext } from '@/landings/context/BespokeContext' import { useLandingContext } from '@/landings/context/LandingContext'
import { LandingHero } from '@/landings/components/shared/LandingHero' import { LandingHero } from '@/landings/components/shared/LandingHero'
import { ArticleGrid } from '@/landings/components/shared/LandingArticleGridWithFilter' import { ArticleGrid } from '@/landings/components/shared/LandingArticleGridWithFilter'
import type { ArticleCardItems } from '@/landings/types' import type { ArticleCardItems } from '@/landings/types'
export const BespokeLanding = () => { export const BespokeLanding = () => {
const { title, intro, tocItems } = useBespokeContext() const { title, intro, heroImage, introLinks, tocItems } = useLandingContext()
const flatArticles: ArticleCardItems = useMemo( const flatArticles: ArticleCardItems = useMemo(
() => tocItems.flatMap((item) => item.childTocItems || []), () => tocItems.flatMap((item) => item.childTocItems || []),
@@ -18,7 +18,7 @@ export const BespokeLanding = () => {
return ( return (
<DefaultLayout> <DefaultLayout>
<div data-search="article-body"> <div data-search="article-body">
<LandingHero title={title} intro={intro} /> <LandingHero title={title} intro={intro} heroImage={heroImage} introLinks={introLinks} />
<div data-search="hide"> <div data-search="hide">
<ArticleGrid flatArticles={flatArticles} /> <ArticleGrid flatArticles={flatArticles} />

View File

@@ -1,7 +1,7 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { DefaultLayout } from '@/frame/components/DefaultLayout' import { DefaultLayout } from '@/frame/components/DefaultLayout'
import { useDiscoveryContext } from '@/landings/context/DiscoveryContext' import { useLandingContext } from '@/landings/context/LandingContext'
import { LandingHero } from '@/landings/components/shared/LandingHero' import { LandingHero } from '@/landings/components/shared/LandingHero'
import { ArticleGrid } from '@/landings/components/shared/LandingArticleGridWithFilter' import { ArticleGrid } from '@/landings/components/shared/LandingArticleGridWithFilter'
import { LandingCarousel } from '@/landings/components/shared/LandingCarousel' import { LandingCarousel } from '@/landings/components/shared/LandingCarousel'
@@ -9,7 +9,7 @@ import { LandingCarousel } from '@/landings/components/shared/LandingCarousel'
import type { ArticleCardItems } from '@/landings/types' import type { ArticleCardItems } from '@/landings/types'
export const DiscoveryLanding = () => { export const DiscoveryLanding = () => {
const { title, intro, tocItems, recommended } = useDiscoveryContext() const { title, intro, heroImage, introLinks, tocItems, recommended } = useLandingContext()
const flatArticles: ArticleCardItems = useMemo( const flatArticles: ArticleCardItems = useMemo(
() => tocItems.flatMap((item) => item.childTocItems || []), () => tocItems.flatMap((item) => item.childTocItems || []),
@@ -19,7 +19,7 @@ export const DiscoveryLanding = () => {
return ( return (
<DefaultLayout> <DefaultLayout>
<div> <div>
<LandingHero title={title} intro={intro} /> <LandingHero title={title} intro={intro} heroImage={heroImage} introLinks={introLinks} />
<LandingCarousel flatArticles={flatArticles} recommended={recommended} /> <LandingCarousel flatArticles={flatArticles} recommended={recommended} />
<ArticleGrid flatArticles={flatArticles} /> <ArticleGrid flatArticles={flatArticles} />
</div> </div>

View File

@@ -1,14 +1,14 @@
import { DefaultLayout } from '@/frame/components/DefaultLayout' import { DefaultLayout } from '@/frame/components/DefaultLayout'
import { useJourneyContext } from '@/landings/context/JourneyContext' import { useLandingContext } from '@/landings/context/LandingContext'
import { LandingHero } from '@/landings/components/shared/LandingHero' import { LandingHero } from '@/landings/components/shared/LandingHero'
export const JourneyLanding = () => { export const JourneyLanding = () => {
const { title, intro } = useJourneyContext() const { title, intro, heroImage, introLinks } = useLandingContext()
return ( return (
<DefaultLayout> <DefaultLayout>
<div> <div>
<LandingHero title={title} intro={intro} /> <LandingHero title={title} intro={intro} heroImage={heroImage} introLinks={introLinks} />
<div>TODO</div> <div>TODO</div>
</div> </div>

View File

@@ -0,0 +1,191 @@
.landingHero {
position: relative;
display: flex;
align-items: center;
padding: 4rem 0;
background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f6f8fa));
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
overflow: hidden;
height: 28rem;
width: 100%;
}
.heroContent {
position: relative;
width: 50rem;
max-width: 50rem;
padding: 0 7rem;
display: flex;
align-items: center;
}
.heroText {
text-align: left;
width: 100%;
}
.heroHeading {
font-size: 4rem;
font-weight: 600;
line-height: 1.2;
margin: 0 0 1rem 0;
color: var(--fgColor-default, var(--color-fg-default, #1f2328));
max-width: 48rem;
}
.heroDescription {
font-size: 1.25rem;
line-height: 1.5;
color: var(--fgColor-muted, var(--color-fg-muted, #656d76));
margin: 0 0 2rem 0;
max-width: 36rem;
}
.heroActions {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.heroAction {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.5rem;
border-radius: 6px;
font-weight: 500;
text-decoration: none;
transition: all 0.2s ease;
min-height: 2.75rem;
border: 1px solid transparent;
}
.heroPrimaryAction {
background-color: var(
--bgColor-success-emphasis,
var(--color-btn-primary-bg, #1f883d)
);
color: var(--fgColor-onEmphasis, var(--color-btn-primary-text, #ffffff));
border-color: var(
--borderColor-success-emphasis,
var(--color-btn-primary-border, #1f883d)
);
&:hover {
background-color: var(
--bgColor-success-emphasis,
var(--color-btn-primary-hover-bg, #1a7f37)
);
border-color: var(
--borderColor-success-emphasis,
var(--color-btn-primary-hover-border, #1a7f37)
);
text-decoration: none;
}
&:focus {
outline: 2px solid
var(
--borderColor-success-emphasis,
var(--color-btn-primary-focus, #1f883d)
);
outline-offset: 2px;
}
}
.heroSecondaryAction {
background-color: transparent;
color: var(--fgColor-default, var(--color-fg-default, #1f2328));
border-color: var(
--borderColor-default,
var(--color-border-default, #d1d9e0)
);
&:hover {
background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f3f4f6));
border-color: var(
--borderColor-default,
var(--color-border-default, #d1d9e0)
);
text-decoration: none;
}
&:focus {
outline: 2px solid
var(--borderColor-accent-emphasis, var(--color-accent-emphasis, #0969da));
outline-offset: 2px;
}
}
@media (max-width: 865px) {
.landingHero {
height: 24rem;
background-image: none !important;
flex-direction: column;
text-align: center;
justify-content: center;
background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f6f8fa));
}
.heroContent {
width: 100%;
order: 2;
padding: 0 1rem;
}
.heroHeading {
font-size: 3rem;
}
.heroDescription {
font-size: 1.1rem;
}
.heroActions {
justify-content: center;
}
.heroAction {
width: auto;
min-width: 12rem;
}
.heroText {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
}
@media (max-width: 480px) {
.landingHero {
height: 32rem;
background-image: none !important;
background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f6f8fa));
flex-direction: column;
text-align: center;
padding: 2rem 0 1rem;
justify-content: center;
}
.heroContent {
width: 100%;
order: 2;
padding: 1rem;
}
.heroText {
display: flex;
flex-direction: column;
text-align: center;
align-items: center;
}
.heroActions {
justify-content: center;
align-items: center;
}
}

View File

@@ -1,18 +1,61 @@
import { Lead } from '@/frame/components/ui/Lead/Lead' import styles from './LandingHero.module.scss'
import { useTranslation } from '@/languages/components/useTranslation'
type LandingHeroProps = { type LandingHeroProps = {
title: string title: string
intro?: string intro?: string
heroImage?: string
introLinks?: Record<string, string> | null
} }
export const LandingHero = ({ title, intro }: LandingHeroProps) => { export const LandingHero = ({ title, intro, heroImage, introLinks }: LandingHeroProps) => {
const { t } = useTranslation(['product_landing'])
const linkEntries = introLinks ? Object.entries(introLinks) : []
const primaryAction = linkEntries[0]
const secondaryAction = linkEntries[1]
return ( return (
<header> <div
<div> className={styles.landingHero}
<h1>TODO: Landing hero placeholder</h1> style={
<h2>{title}</h2> heroImage
{intro && <Lead>{intro}</Lead>} ? {
backgroundImage: `url("${heroImage}")`,
}
: undefined
}
>
<div className={styles.heroContent}>
<div className={styles.heroText}>
<h1 className={styles.heroHeading}>{title}</h1>
{intro && (
<div className={styles.heroDescription}>
<div dangerouslySetInnerHTML={{ __html: intro }} />
</div>
)}
{(primaryAction || secondaryAction) && (
<div className={styles.heroActions}>
{primaryAction && (
<a
href={primaryAction[1]}
className={`${styles.heroAction} ${styles.heroPrimaryAction}`}
>
{t(primaryAction[0])}
</a>
)}
{secondaryAction && (
<a
href={secondaryAction[1]}
className={`${styles.heroAction} ${styles.heroSecondaryAction}`}
>
{t(secondaryAction[0])}
</a>
)}
</div>
)}
</div>
</div> </div>
</header> </div>
) )
} }

View File

@@ -1,49 +0,0 @@
import { createContext, useContext } from 'react'
import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext'
import { mapRawTocItemToTocItem } from '@/landings/types'
import type { TocItem } from '@/landings/types'
import type { LearningTrack } from '@/types'
export type BespokeContextT = {
title: string
intro: string
productCallout: string
permissions: string
tocItems: Array<TocItem>
variant?: 'compact' | 'expanded'
featuredLinks: Record<string, Array<FeaturedLink>>
renderedPage: string
currentLearningTrack?: LearningTrack
currentLayout: string
}
export const BespokeContext = createContext<BespokeContextT | null>(null)
export const useBespokeContext = (): BespokeContextT => {
const context = useContext(BespokeContext)
if (!context) {
throw new Error('"useBespokeContext" may only be used inside "BespokeContext.Provider"')
}
return context
}
export const getBespokeContextFromRequest = async (req: any): Promise<BespokeContextT> => {
const page = req.context.page
return {
title: page.title,
productCallout: page.product || '',
permissions: page.permissions || '',
intro: page.intro,
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map(
mapRawTocItemToTocItem,
),
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
featuredLinks: getFeaturedLinksFromReq(req),
renderedPage: req.context.renderedPage,
currentLearningTrack: req.context.currentLearningTrack,
currentLayout: req.context.currentLayoutName,
}
}

View File

@@ -1,61 +0,0 @@
import { createContext, useContext } from 'react'
import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext'
import { mapRawTocItemToTocItem } from '@/landings/types'
import type { TocItem } from '@/landings/types'
import type { LearningTrack } from '@/types'
export type DiscoveryContextT = {
title: string
intro: string
productCallout: string
permissions: string
tocItems: Array<TocItem>
variant?: 'compact' | 'expanded'
featuredLinks: Record<string, Array<FeaturedLink>>
renderedPage: string
currentLearningTrack?: LearningTrack
currentLayout: string
recommended?: string[] // Array of article paths
}
export const DiscoveryContext = createContext<DiscoveryContextT | null>(null)
export const useDiscoveryContext = (): DiscoveryContextT => {
const context = useContext(DiscoveryContext)
if (!context) {
throw new Error('"useDiscoveryContext" may only be used inside "DiscoveryContext.Provider"')
}
return context
}
export const getDiscoveryContextFromRequest = async (req: any): Promise<DiscoveryContextT> => {
const page = req.context.page
// Support legacy `spotlight` property as `recommended` for pages like Copilot Cookbook
// However, `spotlight` will have lower priority than the `recommended` property
let recommended: string[] = []
if (page.recommended && page.recommended.length > 0) {
recommended = page.recommended
} else if (page.spotlight && page.spotlight.length > 0) {
// Remove the `image` property from spotlight items, since we don't use those for the carousel
recommended = page.spotlight.map((item: any) => item.article)
}
return {
title: page.title,
productCallout: page.product || '',
permissions: page.permissions || '',
intro: page.intro,
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map(
mapRawTocItemToTocItem,
),
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
featuredLinks: getFeaturedLinksFromReq(req),
renderedPage: req.context.renderedPage,
currentLearningTrack: req.context.currentLearningTrack,
currentLayout: req.context.currentLayoutName,
recommended,
}
}

View File

@@ -1,49 +0,0 @@
import { createContext, useContext } from 'react'
import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext'
import { mapRawTocItemToTocItem } from '@/landings/types'
import type { TocItem } from '@/landings/types'
import type { LearningTrack } from '@/types'
export type JourneyContextT = {
title: string
intro: string
productCallout: string
permissions: string
tocItems: Array<TocItem>
variant?: 'compact' | 'expanded'
featuredLinks: Record<string, Array<FeaturedLink>>
renderedPage: string
currentLearningTrack?: LearningTrack
currentLayout: string
}
export const JourneyContext = createContext<JourneyContextT | null>(null)
export const useJourneyContext = (): JourneyContextT => {
const context = useContext(JourneyContext)
if (!context) {
throw new Error('"useJourneyContext" may only be used inside "JourneyContext.Provider"')
}
return context
}
export const getJourneyContextFromRequest = async (req: any): Promise<JourneyContextT> => {
const page = req.context.page
return {
title: page.title,
productCallout: page.product || '',
permissions: page.permissions || '',
intro: page.intro,
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map(
mapRawTocItemToTocItem,
),
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
featuredLinks: getFeaturedLinksFromReq(req),
renderedPage: req.context.renderedPage,
currentLearningTrack: req.context.currentLearningTrack,
currentLayout: req.context.currentLayoutName,
}
}

View File

@@ -0,0 +1,76 @@
import { createContext, useContext } from 'react'
import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext'
import { mapRawTocItemToTocItem } from '@/landings/types'
import type { TocItem } from '@/landings/types'
import type { LearningTrack } from '@/types'
export type LandingType = 'bespoke' | 'discovery' | 'journey'
export type LandingContextT = {
landingType: LandingType
title: string
intro: string
productCallout: string
permissions: string
tocItems: Array<TocItem>
variant?: 'compact' | 'expanded'
featuredLinks: Record<string, Array<FeaturedLink>>
renderedPage: string
currentLearningTrack?: LearningTrack
currentLayout: string
heroImage?: string
// For discovery landing pages
recommended?: string[] // Array of article paths
// For discovery landing pages
introLinks?: Record<string, string>
}
export const LandingContext = createContext<LandingContextT | null>(null)
export const useLandingContext = (): LandingContextT => {
const context = useContext(LandingContext)
if (!context) {
throw new Error('"useLandingContext" may only be used inside "LandingContext.Provider"')
}
return context
}
export const getLandingContextFromRequest = async (
req: any,
landingType: LandingType,
): Promise<LandingContextT> => {
const page = req.context.page
let recommended: string[] = []
if (landingType === 'discovery') {
// Support legacy `spotlight` property as `recommended` for pages like Copilot Cookbook
// However, `spotlight` will have lower priority than the `recommended` property
if (page.recommended && page.recommended.length > 0) {
recommended = page.recommended
} else if (page.spotlight && page.spotlight.length > 0) {
// Remove the `image` property from spotlight items, since we don't use those for the carousel
recommended = page.spotlight.map((item: any) => item.article)
}
}
return {
landingType,
title: page.title,
productCallout: page.product || '',
permissions: page.permissions || '',
intro: page.intro,
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map(
mapRawTocItemToTocItem,
),
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
featuredLinks: getFeaturedLinksFromReq(req),
renderedPage: req.context.renderedPage,
currentLearningTrack: req.context.currentLearningTrack,
currentLayout: req.context.currentLayoutName,
heroImage: page.heroImage || '/assets/images/banner-images/hero-1.png',
introLinks: page.introLinks || null,
recommended,
}
}

View File

@@ -49,22 +49,12 @@ import {
} from '@/frame/components/context/CategoryLandingContext' } from '@/frame/components/context/CategoryLandingContext'
import { BespokeLanding } from '@/landings/components/bespoke/BespokeLanding' import { BespokeLanding } from '@/landings/components/bespoke/BespokeLanding'
import { import {
BespokeContext, LandingContext,
getBespokeContextFromRequest, getLandingContextFromRequest,
BespokeContextT, LandingContextT,
} from '@/landings/context/BespokeContext' } from '@/landings/context/LandingContext'
import { DiscoveryLanding } from '@/landings/components/discovery/DiscoveryLanding' import { DiscoveryLanding } from '@/landings/components/discovery/DiscoveryLanding'
import {
DiscoveryContext,
DiscoveryContextT,
getDiscoveryContextFromRequest,
} from '@/landings/context/DiscoveryContext'
import { JourneyLanding } from '@/landings/components/journey/JourneyLanding' import { JourneyLanding } from '@/landings/components/journey/JourneyLanding'
import {
getJourneyContextFromRequest,
JourneyContext,
JourneyContextT,
} from '@/landings/context/JourneyContext'
function initiateArticleScripts() { function initiateArticleScripts() {
copyCode() copyCode()
@@ -79,9 +69,9 @@ type Props = {
tocLandingContext?: TocLandingContextT tocLandingContext?: TocLandingContextT
articleContext?: ArticleContextT articleContext?: ArticleContextT
categoryLandingContext?: CategoryLandingContextT categoryLandingContext?: CategoryLandingContextT
bespokeContext?: BespokeContextT bespokeContext?: LandingContextT
discoveryContext?: DiscoveryContextT discoveryContext?: LandingContextT
journeyContext?: JourneyContextT journeyContext?: LandingContextT
} }
const GlobalPage = ({ const GlobalPage = ({
mainContext, mainContext,
@@ -108,21 +98,21 @@ const GlobalPage = ({
let content let content
if (bespokeContext) { if (bespokeContext) {
content = ( content = (
<BespokeContext.Provider value={bespokeContext}> <LandingContext.Provider value={bespokeContext}>
<BespokeLanding /> <BespokeLanding />
</BespokeContext.Provider> </LandingContext.Provider>
) )
} else if (discoveryContext) { } else if (discoveryContext) {
content = ( content = (
<DiscoveryContext.Provider value={discoveryContext}> <LandingContext.Provider value={discoveryContext}>
<DiscoveryLanding /> <DiscoveryLanding />
</DiscoveryContext.Provider> </LandingContext.Provider>
) )
} else if (journeyContext) { } else if (journeyContext) {
content = ( content = (
<JourneyContext.Provider value={journeyContext}> <LandingContext.Provider value={journeyContext}>
<JourneyLanding /> <JourneyLanding />
</JourneyContext.Provider> </LandingContext.Provider>
) )
} else if (productLandingContext) { } else if (productLandingContext) {
content = ( content = (
@@ -184,23 +174,23 @@ export const getServerSideProps: GetServerSideProps<Props> = async (context) =>
// This looks a little funky, but it's so we only send one context's data to the client // This looks a little funky, but it's so we only send one context's data to the client
// TODO: TEMP: This is a temporary solution to turn off/on new landing pages while we develop them // TODO: TEMP: This is a temporary solution to turn off/on new landing pages while we develop them
if (currentLayoutName === 'bespoke-landing' || req.query?.feature === 'bespoke-landing') { if (currentLayoutName === 'bespoke-landing' || req.query?.feature === 'bespoke-landing') {
props.bespokeContext = await getBespokeContextFromRequest(req) props.bespokeContext = await getLandingContextFromRequest(req, 'bespoke')
additionalUINamespaces.push('bespoke_landing') additionalUINamespaces.push('bespoke_landing', 'product_landing')
} else if (currentLayoutName === 'journey-landing' || req.query?.feature === 'journey-landing') { } else if (currentLayoutName === 'journey-landing' || req.query?.feature === 'journey-landing') {
props.journeyContext = await getJourneyContextFromRequest(req) props.journeyContext = await getLandingContextFromRequest(req, 'journey')
additionalUINamespaces.push('journey_landing') additionalUINamespaces.push('journey_landing', 'product_landing')
} else if ( } else if (
currentLayoutName === 'discovery-landing' || currentLayoutName === 'discovery-landing' ||
req?.query?.feature === 'discovery-landing' req?.query?.feature === 'discovery-landing'
) { ) {
props.discoveryContext = await getDiscoveryContextFromRequest(req) props.discoveryContext = await getLandingContextFromRequest(req, 'discovery')
additionalUINamespaces.push('discovery_landing') additionalUINamespaces.push('discovery_landing', 'product_landing')
} else if (currentLayoutName === 'product-landing') { } else if (currentLayoutName === 'product-landing') {
props.productLandingContext = await getProductLandingContextFromRequest(req) props.productLandingContext = await getProductLandingContextFromRequest(req)
additionalUINamespaces.push('product_landing') additionalUINamespaces.push('product_landing')
} else if (currentLayoutName === 'product-guides') { } else if (currentLayoutName === 'product-guides') {
props.productGuidesContext = getProductGuidesContextFromRequest(req) props.productGuidesContext = getProductGuidesContextFromRequest(req)
additionalUINamespaces.push('product_guides') additionalUINamespaces.push('product_guides', 'product_landing')
} else if (relativePath?.endsWith('index.md')) { } else if (relativePath?.endsWith('index.md')) {
if (currentLayoutName === 'category-landing') { if (currentLayoutName === 'category-landing') {
props.categoryLandingContext = getCategoryLandingContextFromRequest(req) props.categoryLandingContext = getCategoryLandingContextFromRequest(req)