Skip to content

Commit

Permalink
wip: add LandingHero, FeaturedArticles
Browse files Browse the repository at this point in the history
  • Loading branch information
mikesurowiec committed May 7, 2021
1 parent 03523a1 commit 8598b60
Show file tree
Hide file tree
Showing 8 changed files with 376 additions and 7 deletions.
25 changes: 25 additions & 0 deletions components/TruncateLines.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Component className={cx('root', props.className)}>
{props.children}
<style jsx>{`
.root {
display: -webkit-box;
-webkit-line-clamp: ${props.maxLines};
-webkit-box-orient: vertical;
overflow: hidden;
}
`}</style>
</Component>
)
}
99 changes: 99 additions & 0 deletions components/context/ProductLandingContext.tsx
Original file line number Diff line number Diff line change
@@ -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<string>
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<FeaturedLink>
// popular: Array<FeaturedLink>
// guideCards: Array<FeaturedLink>
// }
featuredArticles?: Array<{
translationKeyLabel: string // Guides
viewAllHref?: string // If provided, adds a "View All ->" to the header
articles: Array<FeaturedLink>
}>
changelog: { label: string; prefix: 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 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 || [],
}
}),
}
}),
}
}
98 changes: 98 additions & 0 deletions components/landing/FeaturedArticles.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="d-lg-flex gutter my-6 py-6">
{featuredArticles.map((section, i) => {
return (
<div className={cx('col-12 mb-4 mb-lg-0', changelog ? 'col-lg-4' : 'col-lg-6')}>
<ArticleList
title={t(section.translationKeyLabel)}
viewAllHref={section.viewAllHref}
articles={section.articles}
/>
</div>
)
})}

{/* {% if page.changelog %}
<div className="col-12 col-lg-4 mb-4 mb-lg-0">
<div className="featured-links-heading mb-4 d-flex flex-items-baseline">
<h3 className="f4 text-normal text-mono text-uppercase color-text-secondary">{data.ui.toc.whats_new}</h3>
<a href="{{ changelogUrl }}" className="ml-4">View all {% octicon "arrow-right" height="14" className="v-align-middle" %}</a>
</div>
<ul className="list-style-none">
{% for link in whatsNewChangelog %}
<li className="border-top">
<a href="{{ link.href }}" className="d-block color-text-primary Bump-link--hover py-3 no-underline capitalize">
<h4>{{ link.title }} <span className="Bump-link-symbol">→</span></h4>
<time
className="tooltipped tooltipped-n color-text-tertiary text-mono mt-1"
aria-label="{{ link.date | date: '%B %d, %Y' }}"
>{{ link.date | date: "%B %d" }}</time>
</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %} */}
</div>
)
}

type ArticleListProps = {
title: string
viewAllHref?: string
articles: Array<FeaturedLink>
}
const ArticleList = ({ title, viewAllHref, articles }: ArticleListProps) => {
return (
<>
<div className="featured-links-heading mb-4 d-flex flex-items-baseline">
<h3 className="f4 text-normal text-mono text-uppercase color-text-secondary">{title}</h3>
{viewAllHref && (
<Link href={viewAllHref}>
<a className="ml-4">
View all <ArrowRightIcon size={14} className="v-align-middle" />
</a>
</Link>
)}
</div>

<ul className="list-style-none">
{articles.map((link) => {
return (
<li key={link.href} className="border-top">
<Link href={link.href}>
<a className="link-with-intro Bump-link--hover no-underline d-block py-3">
<h4 className="link-with-intro-title">
{link.title}
<span className="Bump-link-symbol"></span>
</h4>
{!link.hideIntro && (
<TruncateLines
as="p"
maxLines={2}
className="link-with-intro-intro color-text-secondary mb-0 mt-1"
>
{link.intro}
</TruncateLines>
)}
</a>
</Link>
</li>
)
})}
</ul>
</>
)
}
108 changes: 108 additions & 0 deletions components/landing/LandingHero.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<header className="d-lg-flex gutter-lg mb-6">
<div className={cx(product_video && 'col-12 col-lg-6 mb-3 mb-lg-0')}>
<span className="text-mono color-text-secondary">Product</span>
<h1 className="mb-3 font-mktg">
{shortTitle}{' '}
{beta_product && <span className="Label Label--success v-align-middle">Beta</span>}
</h1>

<div
className="lead-mktg color-text-secondary"
dangerouslySetInnerHTML={{ __html: intro }}
/>

{heroLinks.map((link) => {
return (
<FullLink
href={link.href}
className={cx(
'btn-mktg btn-large f4 mt-3 mr-3',
link.secondary && 'btn-outline-mktg'
)}
>
{t(link.translationKeyLabel)}
</FullLink>
)
})}

{/* {introLinks?.quickstart && (
<FullLink href={introLinks.quickstart} className="btn-mktg btn-large f4 mt-3 mr-3">
{t('quick_start')}
</FullLink>
)}
{introLinks?.reference && (
<FullLink
href={introLinks.reference}
className="btn-mktg btn-outline-mktg btn-large f4 mt-3 mr-3"
>
{t('reference_guides')}
</FullLink>
)}
{introLinks?.overview && (
<FullLink
href={introLinks.overview}
className="btn-mktg btn-outline-mktg btn-large f4 mt-3 mr-3"
>
{t('overview')}
</FullLink>
)} */}
</div>

{product_video && (
<div className="col-12 col-lg-6">
<div className="position-relative" style={{ paddingBottom: '56.25%' }}>
{!airGap && (
<iframe
title={`${shortTitle} Video`}
className="top-0 left-0 position-absolute color-shadow-large rounded-1 width-full height-full"
src={product_video}
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
)}
</div>
</div>
)}
</header>
</div>
)
}

// 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 (
<Link href={fullyQualifiedHref}>
<a className={className}>{children}</a>
</Link>
)
}
2 changes: 1 addition & 1 deletion data/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion includes/featured-links.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ <h3 class="f5 text-normal text-mono underline-dashed color-text-secondary">{% da
<!-- Popular articles -->
<div class="col-12 col-lg-6 float-left">
<div class="featured-links-heading pb-4">
<h3 class="f5 text-normal text-mono underline-dashed color-text-secondary">{% data ui.toc.popular_articles %}</h3>
<h3 class="f5 text-normal text-mono underline-dashed color-text-secondary">{% data ui.toc.popular %}</h3>
</div>

{% for link in featuredLinks.popular %}
Expand Down
2 changes: 1 addition & 1 deletion layouts/product-landing.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ <h4 class="link-with-intro-title mb-1">{{ link.title }}<span class="Bump-link-sy
{% if featuredLinks.popular %}
<div class="col-12 col-lg-{% if page.changelog %}4{% else %}6{% endif %} mb-4 mb-lg-0">
<div class="featured-links-heading mb-4 d-flex flex-items-baseline">
<h3 class="f4 text-normal text-mono text-uppercase color-text-secondary" id="popular"><a href="#popular">{% if page.featuredLinks.popularHeading %}{{ page.featuredLinks.popularHeading }}{% else %}{% data ui.toc.popular_articles %}{% endif %}</a></h3>
<h3 class="f4 text-normal text-mono text-uppercase color-text-secondary" id="popular"><a href="#popular">{% if page.featuredLinks.popularHeading %}{{ page.featuredLinks.popularHeading }}{% else %}{% data ui.toc.popular %}{% endif %}</a></h3>
</div>
<ul class="list-style-none">
{% for link in featuredLinks.popular %}
Expand Down
Loading

0 comments on commit 8598b60

Please sign in to comment.