diff --git a/components/TruncateLines.tsx b/components/TruncateLines.tsx new file mode 100644 index 000000000000..7f29bdb707c8 --- /dev/null +++ b/components/TruncateLines.tsx @@ -0,0 +1,25 @@ +import React, { ReactNode, ReactHTML } from 'react' +import cx from 'classnames' + +type Props = { + as?: keyof ReactHTML + maxLines: number + children: ReactNode + className?: string +} +export const TruncateLines = (props: Props) => { + const Component = props.as || 'div' + return ( + + {props.children} + + + ) +} diff --git a/components/context/ProductLandingContext.tsx b/components/context/ProductLandingContext.tsx new file mode 100644 index 000000000000..cda6d1cd0ab2 --- /dev/null +++ b/components/context/ProductLandingContext.tsx @@ -0,0 +1,99 @@ +import { createContext, useContext } from 'react' +import pick from 'lodash/pick' + +export type FeaturedLink = { + title: string + intro: string + href: string + authors?: Array + hideIntro?: boolean +} + +export type ProductLandingContextT = { + title: string + introPlainText: string + shortTitle: string + intro: string + beta_product: boolean + // primaryAction: LinkButtonT + // secondaryAction?: LinkButtonT + heroLinks: Array<{ + translationKeyLabel: string + secondary: boolean + href: string + }> + product_video?: string + // featuredLinks?: { + // guides: Array + // popular: Array + // guideCards: Array + // } + featuredArticles?: Array<{ + translationKeyLabel: string // Guides + viewAllHref?: string // If provided, adds a "View All ->" to the header + articles: Array + }> + changelog: { label: string; prefix: string } +} + +export const ProductLandingContext = createContext(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 getProductLandingContextFromRequest = (req: any): ProductLandingContextT => { + const { currentCategory, currentPath, data } = req.context + return { + ...pick(req.context.page, [ + 'title', + 'shortTitle', + 'introPlainText', + 'beta_product', + 'intro', + 'product_video', + 'changelog', + ]), + + // TODO - these transformations should be temporary, we should alter the content file to roughly match this shape! + heroLinks: Object.entries(req.context.page.introLinks) + .filter(([key, val]) => { + return !!val && !key.startsWith('raw') + }) + .map(([key, val]) => { + return { + translationKeyLabel: key, + secondary: key === 'reference' || key === 'overview', // this parameter would just be set in yaml + href: val as string, + } + }), + + featuredArticles: Object.entries(req.context.featuredLinks) + .filter(([key]) => { + return key === 'guides' || key === 'popular' + }) + .map(([key, links]: any) => { + return { + translationKeyLabel: key, + viewAllHref: key === 'guides' && !currentCategory ? `${currentPath}/${key}` : '', + articles: links.map((link: any) => { + return { + hideIntro: key === 'popular', + href: link.href, + title: link.title, + intro: link.intro, + authors: link.page.authors || [], + } + }), + } + }), + } +} diff --git a/components/landing/FeaturedArticles.tsx b/components/landing/FeaturedArticles.tsx new file mode 100644 index 000000000000..85fc48fbe588 --- /dev/null +++ b/components/landing/FeaturedArticles.tsx @@ -0,0 +1,98 @@ +import cx from 'classnames' +import Link from 'next/link' + +import { ArrowRightIcon } from '@primer/octicons-react' +import { FeaturedLink, useProductLandingContext } from 'components/context/ProductLandingContext' +import { useTranslation } from 'components/hooks/useTranslation' +import { TruncateLines } from 'components/TruncateLines' + +export const FeaturedArticles = () => { + const { featuredArticles = [], changelog } = useProductLandingContext() + const { t } = useTranslation('toc') + + return ( +
+ {featuredArticles.map((section, i) => { + return ( +
+ +
+ ) + })} + + {/* {% if page.changelog %} +
+ + +
+ {% endif %} */} +
+ ) +} + +type ArticleListProps = { + title: string + viewAllHref?: string + articles: Array +} +const ArticleList = ({ title, viewAllHref, articles }: ArticleListProps) => { + return ( + <> +
+

{title}

+ {viewAllHref && ( + + + View all + + + )} +
+ + + + ) +} diff --git a/components/landing/LandingHero.tsx b/components/landing/LandingHero.tsx new file mode 100644 index 000000000000..db87dc665e94 --- /dev/null +++ b/components/landing/LandingHero.tsx @@ -0,0 +1,108 @@ +import cx from 'classnames' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { useMainContext } from 'components/context/MainContext' + +import { useProductLandingContext } from 'components/context/ProductLandingContext' +import { useTranslation } from 'components/hooks/useTranslation' +import { useVersion } from 'components/hooks/useVersion' + +export const LandingHero = () => { + const { airGap } = useMainContext() + const { product_video, shortTitle, beta_product, intro, heroLinks } = useProductLandingContext() + const { t } = useTranslation('product_landing') + + return ( +
+
+
+ Product +

+ {shortTitle}{' '} + {beta_product && Beta} +

+ +
+ + {heroLinks.map((link) => { + return ( + + {t(link.translationKeyLabel)} + + ) + })} + + {/* {introLinks?.quickstart && ( + + {t('quick_start')} + + )} + + {introLinks?.reference && ( + + {t('reference_guides')} + + )} + + {introLinks?.overview && ( + + {t('overview')} + + )} */} +
+ + {product_video && ( +
+
+ {!airGap && ( + + )} +
+
+ )} +
+
+ ) +} + +// Fully Qualified Link - it includes the version and locale in the path +type Props = { + href: string + children: React.ReactNode + className?: string +} +export const FullLink = ({ href, children, className }: Props) => { + const router = useRouter() + const { currentVersion } = useVersion() + const locale = router.locale || 'en' + const fullyQualifiedHref = `/${locale}${ + currentVersion !== 'free-pro-team@latest' ? `/${currentVersion}` : '' + }${href}` + return ( + + {children} + + ) +} diff --git a/data/ui.yml b/data/ui.yml index d09500f7047a..2a9dab417784 100644 --- a/data/ui.yml +++ b/data/ui.yml @@ -30,7 +30,7 @@ homepage: version_picker: Version toc: getting_started: Getting started - popular_articles: Popular + popular: Popular guides: Guides whats_new: What's new pages: diff --git a/includes/featured-links.html b/includes/featured-links.html index 8a0b55b6bba2..96766d3738f3 100644 --- a/includes/featured-links.html +++ b/includes/featured-links.html @@ -15,7 +15,7 @@

{% da
{% for link in featuredLinks.popular %} diff --git a/layouts/product-landing.html b/layouts/product-landing.html index f2a9f0019450..6b7a489779d5 100644 --- a/layouts/product-landing.html +++ b/layouts/product-landing.html @@ -74,7 +74,7 @@