164 lines
4.8 KiB
TypeScript
164 lines
4.8 KiB
TypeScript
import { createContext, useContext } from 'react'
|
|
import pick from 'lodash/pick'
|
|
|
|
export type TocItem = {
|
|
fullPath: string
|
|
title: string
|
|
intro?: string
|
|
childTocItems?: Array<{
|
|
fullPath: string
|
|
title: string
|
|
}>
|
|
}
|
|
export type FeaturedLink = {
|
|
title: string
|
|
href: string
|
|
intro?: string
|
|
authors?: Array<string>
|
|
hideIntro?: boolean
|
|
date?: string
|
|
fullTitle?: string
|
|
}
|
|
export type CodeExample = {
|
|
title: string
|
|
description: string
|
|
languages: string // single comma separated string
|
|
href: string
|
|
tags: Array<string>
|
|
}
|
|
export type Product = {
|
|
title: string
|
|
href: string
|
|
}
|
|
|
|
export type ProductLandingContextT = {
|
|
title: string
|
|
introPlainText: string
|
|
shortTitle: string
|
|
intro: string
|
|
beta_product: boolean
|
|
product: Product
|
|
introLinks: Record<string, string> | null
|
|
productVideo: string
|
|
productVideoTranscript: string
|
|
featuredLinks: Record<string, Array<FeaturedLink>>
|
|
productUserExamples: Array<{ username: string; description: string }>
|
|
productCommunityExamples: Array<{ repo: string; description: string }>
|
|
featuredArticles: Array<{
|
|
key: string // Featured article section key (startHere, popular, etc.)
|
|
label: string // Start here, Popular, etc.
|
|
viewAllHref?: string // If provided, adds a "View All ->" to the header
|
|
viewAllTitleText?: string // Adds 'title' attribute text for the "View All" href
|
|
articles: Array<FeaturedLink>
|
|
}>
|
|
changelogUrl?: string
|
|
whatsNewChangelog?: Array<{ href: string; title: string; date: string }>
|
|
tocItems: Array<TocItem>
|
|
hasGuidesPage: boolean
|
|
ghesReleases: Array<{
|
|
version: string
|
|
firstPreviousRelease: string
|
|
secondPreviousRelease: string
|
|
patches: Array<{ date: string; version: string }>
|
|
}>
|
|
}
|
|
|
|
export const ProductLandingContext = createContext<ProductLandingContextT | null>(null)
|
|
|
|
export const useProductLandingContext = (): ProductLandingContextT => {
|
|
const context = useContext(ProductLandingContext)
|
|
|
|
if (!context) {
|
|
throw new Error(
|
|
'"useProductLandingContext" may only be used inside "ProductLandingContext.Provider"'
|
|
)
|
|
}
|
|
|
|
return context
|
|
}
|
|
|
|
export const getFeaturedLinksFromReq = (req: any): Record<string, Array<FeaturedLink>> => {
|
|
return Object.fromEntries(
|
|
Object.entries(req.context.featuredLinks || {}).map(([key, entries]) => {
|
|
return [
|
|
key,
|
|
((entries as Array<any>) || []).map((entry: any) => ({
|
|
href: entry.href,
|
|
title: entry.title,
|
|
intro: entry.intro || null,
|
|
authors: entry.page?.authors || [],
|
|
fullTitle: entry.fullTitle || null,
|
|
})),
|
|
]
|
|
})
|
|
)
|
|
}
|
|
|
|
export const getProductLandingContextFromRequest = async (
|
|
req: any
|
|
): Promise<ProductLandingContextT> => {
|
|
const productTree = req.context.currentProductTree
|
|
const page = req.context.page
|
|
const hasGuidesPage = (page.children || []).includes('/guides')
|
|
|
|
const productVideo = page.product_video
|
|
? await page.renderProp('product_video', req.context, { textOnly: true })
|
|
: ''
|
|
|
|
return {
|
|
...pick(page, ['title', 'shortTitle', 'introPlainText', 'beta_product', 'intro']),
|
|
productVideo,
|
|
productVideoTranscript: page.product_video_transcript || null,
|
|
hasGuidesPage,
|
|
product: {
|
|
href: productTree.href,
|
|
title: productTree.page.shortTitle || productTree.page.title,
|
|
},
|
|
whatsNewChangelog: req.context.whatsNewChangelog || [],
|
|
changelogUrl: req.context.changelogUrl || [],
|
|
productCommunityExamples: req.context.productCommunityExamples || [],
|
|
ghesReleases: req.context.ghesReleases || [],
|
|
|
|
productUserExamples: (req.context.productUserExamples || []).map(
|
|
({ user, description }: any) => ({
|
|
username: user,
|
|
description,
|
|
})
|
|
),
|
|
|
|
introLinks: page.introLinks || null,
|
|
|
|
featuredLinks: getFeaturedLinksFromReq(req),
|
|
|
|
tocItems: req.context.tocItems || [],
|
|
|
|
featuredArticles: Object.entries(req.context.featuredLinks || [])
|
|
.filter(([key]) => {
|
|
return key === 'startHere' || key === 'popular' || key === 'videos'
|
|
})
|
|
.map(([key, links]: any) => {
|
|
return {
|
|
key,
|
|
label:
|
|
key === 'popular' || key === 'videos'
|
|
? req.context.page.featuredLinks[key + 'Heading'] || req.context.site.data.ui.toc[key]
|
|
: req.context.site.data.ui.toc[key],
|
|
viewAllHref:
|
|
key === 'startHere' && !req.context.currentCategory && hasGuidesPage
|
|
? `${req.context.currentPath}/guides`
|
|
: '',
|
|
articles: links.map((link: any) => {
|
|
return {
|
|
hideIntro: key === 'popular',
|
|
href: link.href,
|
|
title: link.title,
|
|
intro: link.intro || null,
|
|
authors: link.page?.authors || [],
|
|
fullTitle: link.fullTitle || null,
|
|
}
|
|
}),
|
|
}
|
|
}),
|
|
}
|
|
}
|