зеркало из https://github.com/github/docs.git
feat: add alternate landing page layout (#19571)
This commit is contained in:
Родитель
170a3e9dca
Коммит
4661a36d5d
|
@ -0,0 +1,58 @@
|
|||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown } from '@primer/components'
|
||||
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
|
||||
export const ArticleVersionPicker = () => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
const { t } = useTranslation('pages')
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="d-none d-lg-flex flex-justify-end">
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2">
|
||||
<span className="d-md-none d-xl-inline-block">{t('article_version')}</span>{' '}
|
||||
{allVersions[currentVersion].versionTitle}
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
if (permalink.pageVersion === 'homepage') {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href}>
|
||||
<Link href={permalink.href}>
|
||||
<a>{permalink.pageVersionTitle}</a>
|
||||
</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<div className="pb-1">
|
||||
<Link href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}>
|
||||
<a className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap">
|
||||
See all Enterprise releases
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
import { createContext, useContext } from 'react'
|
||||
import pick from 'lodash/pick'
|
||||
|
||||
export type TocItem = {
|
||||
fullPath: string
|
||||
title: string
|
||||
intro?: string
|
||||
}
|
||||
export type FeaturedLink = {
|
||||
title: string
|
||||
href: string
|
||||
|
@ -28,19 +33,12 @@ export type ProductLandingContextT = {
|
|||
intro: string
|
||||
beta_product: boolean
|
||||
product: Product
|
||||
// primaryAction: LinkButtonT
|
||||
// secondaryAction?: LinkButtonT
|
||||
introLinks: {
|
||||
quickstart?: string
|
||||
reference?: string
|
||||
overview?: string
|
||||
}
|
||||
} | null
|
||||
product_video?: string
|
||||
// featuredLinks?: {
|
||||
// guides: Array<FeaturedLink>
|
||||
// popular: Array<FeaturedLink>
|
||||
// guideCards: Array<FeaturedLink>
|
||||
// }
|
||||
guideCards: Array<FeaturedLink>
|
||||
productCodeExamples: Array<CodeExample>
|
||||
productUserExamples: Array<{ username: string; description: string }>
|
||||
|
@ -53,6 +51,7 @@ export type ProductLandingContextT = {
|
|||
changelog: { label: string; prefix: string }
|
||||
changelogUrl?: string
|
||||
whatsNewChangelog?: Array<{ href: string; title: string; date: string }>
|
||||
tocItems: Array<TocItem>
|
||||
}
|
||||
|
||||
export const ProductLandingContext = createContext<ProductLandingContextT | null>(null)
|
||||
|
@ -97,20 +96,26 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
|
|||
})
|
||||
),
|
||||
|
||||
introLinks: {
|
||||
quickstart: productTree.page.introLinks.quickstart,
|
||||
reference: productTree.page.introLinks.reference,
|
||||
overview: productTree.page.introLinks.overview,
|
||||
},
|
||||
introLinks: productTree.page.introLinks
|
||||
? {
|
||||
quickstart: productTree.page.introLinks.quickstart,
|
||||
reference: productTree.page.introLinks.reference,
|
||||
overview: productTree.page.introLinks.overview,
|
||||
}
|
||||
: null,
|
||||
|
||||
guideCards: (req.context.featuredLinks ? (req.context.featuredLinks.guideCards || []) : []).map((link: any) => {
|
||||
return {
|
||||
href: link.href,
|
||||
title: link.title,
|
||||
intro: link.intro,
|
||||
authors: link.page.authors || [],
|
||||
guideCards: (req.context.featuredLinks ? req.context.featuredLinks.guideCards || [] : []).map(
|
||||
(link: any) => {
|
||||
return {
|
||||
href: link.href,
|
||||
title: link.title,
|
||||
intro: link.intro,
|
||||
authors: link.page.authors || [],
|
||||
}
|
||||
}
|
||||
}),
|
||||
),
|
||||
|
||||
tocItems: req.context.tocItems || [],
|
||||
|
||||
featuredArticles: Object.entries(req.context.featuredLinks || [])
|
||||
.filter(([key]) => {
|
||||
|
@ -119,7 +124,10 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
|
|||
.map(([key, links]: any) => {
|
||||
return {
|
||||
label: req.context.site.data.ui.toc[key],
|
||||
viewAllHref: key === 'guides' && !req.context.currentCategory ? `${req.context.currentPath}/${key}` : '',
|
||||
viewAllHref:
|
||||
key === 'guides' && !req.context.currentCategory
|
||||
? `${req.context.currentPath}/${key}`
|
||||
: '',
|
||||
articles: links.map((link: any) => {
|
||||
return {
|
||||
hideIntro: key === 'popular',
|
||||
|
@ -130,7 +138,6 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
|
|||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,9 +50,10 @@ const ArticleList = ({ page }: { page: CurrentProductTree }) => {
|
|||
<a>{grandchildPage.page.title}</a>
|
||||
</Link>
|
||||
{grandchildPage.page.documentType === 'mapTopic' ? (
|
||||
<small className="color-text-secondary d-inline-block">
|
||||
• {page.childPages.length} articles
|
||||
</small>) : null}
|
||||
<small className="color-text-secondary d-inline-block">
|
||||
• {page.childPages.length} articles
|
||||
</small>
|
||||
) : null}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import cx from 'classnames'
|
||||
|
||||
import type { TocItem } from '../context/ProductLandingContext'
|
||||
|
||||
export const TableOfContents = (props: { items?: Array<TocItem> }) => {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{(props.items || []).map(({ fullPath: href, title, intro }) => {
|
||||
const isActive = router.pathname === href
|
||||
return (
|
||||
<div key={href} className={cx('mb-5', isActive && 'color-auto-gray-4')}>
|
||||
<Link href={href}>
|
||||
<a className="Bump-link--hover no-underline d-block py-1 border-bottom color-border-primary">
|
||||
<h4>
|
||||
{title}
|
||||
<span className="Bump-link-symbol">→</span>
|
||||
</h4>
|
||||
</a>
|
||||
</Link>
|
||||
{intro && <p className="f4 mt-3" dangerouslySetInnerHTML={{ __html: intro }} />}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { GetServerSideProps } from 'next'
|
||||
import { Grid } from '@primer/components'
|
||||
|
||||
import {
|
||||
MainContextT,
|
||||
|
@ -22,6 +23,8 @@ import { CodeExamples } from 'components/landing/CodeExamples'
|
|||
import { LandingSection } from 'components/landing/LandingSection'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
|
||||
import { TableOfContents } from 'components/landing/TableOfContents'
|
||||
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
|
||||
|
||||
type Props = {
|
||||
mainContext: MainContextT
|
||||
|
@ -31,13 +34,17 @@ const ProductPage = ({ mainContext, productLandingContext }: Props) => {
|
|||
return (
|
||||
<MainContext.Provider value={mainContext}>
|
||||
<ProductLandingContext.Provider value={productLandingContext}>
|
||||
<ProductPageInner />
|
||||
{mainContext.currentLayoutName === 'product-landing' ? (
|
||||
<ProductLanding />
|
||||
) : (
|
||||
<TocProductLanding />
|
||||
)}
|
||||
</ProductLandingContext.Provider>
|
||||
</MainContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const ProductPageInner = () => {
|
||||
const ProductLanding = () => {
|
||||
const { title, guideCards, productUserExamples, productCommunityExamples, productCodeExamples } =
|
||||
useProductLandingContext()
|
||||
const { t } = useTranslation('product_landing')
|
||||
|
@ -85,6 +92,34 @@ const ProductPageInner = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const TocProductLanding = () => {
|
||||
const { title, introPlainText, tocItems } = useProductLandingContext()
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<Grid
|
||||
className="container-xl px-3 px-md-6 my-4 my-lg-4 container-xl "
|
||||
gridTemplateColumns="minmax(500px, 720px) minmax(220px, 1fr)"
|
||||
gridTemplateRows="auto 1fr"
|
||||
gridGap={16}
|
||||
>
|
||||
<div>
|
||||
<h1 className="my-4">{title}</h1>
|
||||
<div className="lead-mktg">
|
||||
<p>{introPlainText}</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-7">
|
||||
<TableOfContents items={tocItems} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ArticleVersionPicker />
|
||||
</div>
|
||||
</Grid>
|
||||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProductPage
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче