diff --git a/components/context/ProductLandingContext.tsx b/components/context/ProductLandingContext.tsx index 8d77096f83..4c61a97ded 100644 --- a/components/context/ProductLandingContext.tsx +++ b/components/context/ProductLandingContext.tsx @@ -38,11 +38,7 @@ export type ProductLandingContextT = { intro: string beta_product: boolean product: Product - introLinks: { - quickstart?: string - reference?: string - overview?: string - } | null + introLinks: Record | null product_video?: string featuredLinks: Record> productCodeExamples: Array @@ -128,13 +124,7 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon }) ), - introLinks: page.introLinks - ? { - quickstart: page.introLinks.quickstart, - reference: page.introLinks.reference, - overview: page.introLinks.overview, - } - : null, + introLinks: page.introLinks || null, featuredLinks: getFeaturedLinksFromReq(req), diff --git a/components/landing/LandingHero.tsx b/components/landing/LandingHero.tsx index e1abac170f..a81e142474 100644 --- a/components/landing/LandingHero.tsx +++ b/components/landing/LandingHero.tsx @@ -1,8 +1,9 @@ import { useEffect, useState } from 'react' import cx from 'classnames' import { useRouter } from 'next/router' -import { useMainContext } from 'components/context/MainContext' +import { LinkExternalIcon } from '@primer/octicons-react' +import { useMainContext } from 'components/context/MainContext' import { Link } from 'components/Link' import { useProductLandingContext } from 'components/context/ProductLandingContext' import { useTranslation } from 'components/hooks/useTranslation' @@ -46,7 +47,7 @@ export const LandingHero = () => { href={link} className={cx('btn btn-large f4 mt-3 mr-3 ', i === 0 && 'btn-primary')} > - {t(key)} + {t(key) || key} ) })} @@ -72,7 +73,8 @@ export const LandingHero = () => { ) } -// Fully Qualified Link - it includes the version and locale in the path +// Fully Qualified Link - it includes the version and locale in the path if +// the href is not an external link. type Props = { href: string children: React.ReactNode @@ -81,13 +83,24 @@ type Props = { 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}` + + const isExternal = href.startsWith('https') + let linkHref = href + if (!isExternal) { + const locale = router.locale || 'en' + linkHref = `/${locale}${ + currentVersion !== 'free-pro-team@latest' ? `/${currentVersion}` : '' + }${href}` + } + return ( - - {children} + + {children}{' '} + {isExternal && ( + + + + )} ) } diff --git a/lib/frontmatter.js b/lib/frontmatter.js index 0d14fabc2f..a4e9fe1df2 100644 --- a/lib/frontmatter.js +++ b/lib/frontmatter.js @@ -77,11 +77,6 @@ export const schema = { }, introLinks: { type: 'object', - properties: { - quickstart: { type: 'string' }, - reference: { type: 'string' }, - overview: { type: 'string' }, - }, }, authors: { type: 'array', diff --git a/lib/page.js b/lib/page.js index 6e66b4f02e..eacb1ae968 100644 --- a/lib/page.js +++ b/lib/page.js @@ -90,12 +90,7 @@ class Page { this.rawLearningTracks = this.learningTracks this.rawIncludeGuides = this.includeGuides this.raw_product_video = this.product_video - - if (this.introLinks) { - this.introLinks.rawQuickstart = this.introLinks.quickstart - this.introLinks.rawReference = this.introLinks.reference - this.introLinks.rawOverview = this.introLinks.overview - } + this.rawIntroLinks = this.introLinks // Is this the Homepage or a Product, Category, Topic, or Article? this.documentType = getDocumentType(this.relativePath) @@ -209,18 +204,6 @@ class Page { this.product_video = await renderContent(this.raw_product_video, context, { textOnly: true }) - if (this.introLinks) { - this.introLinks.quickstart = await renderContent(this.introLinks.rawQuickstart, context, { - textOnly: true, - }) - this.introLinks.reference = await renderContent(this.introLinks.rawReference, context, { - textOnly: true, - }) - this.introLinks.overview = await renderContent(this.introLinks.rawOverview, context, { - textOnly: true, - }) - } - context.relativePath = this.relativePath const html = await renderContentCacheByContext('markdown')(this.markdown, context) @@ -260,6 +243,18 @@ class Page { this.learningTracks = learningTracks } + // introLinks may contain Liquid and need to have versioning processed. + if (this.rawIntroLinks) { + const introLinks = {} + for (const [rawKey, value] of Object.entries(this.rawIntroLinks)) { + introLinks[rawKey] = await renderContent(value, context, { + textOnly: true, + }) + } + + this.introLinks = introLinks + } + if (this.rawIncludeGuides) { this.allTopics = [] this.includeGuides = await getLinkData(this.rawIncludeGuides, context) diff --git a/tests/fixtures/article-with-introLinks.md b/tests/fixtures/article-with-introLinks.md new file mode 100644 index 0000000000..bfff0ffec3 --- /dev/null +++ b/tests/fixtures/article-with-introLinks.md @@ -0,0 +1,9 @@ +--- +title: Article with introLinks +versions: + ghec: '*' + ghes: '*' +introLinks: + overview: 'https://github.com' + custom link!: 'https://github.com/features' +--- diff --git a/tests/unit/page.js b/tests/unit/page.js index 6652e5b4c5..24dcc6d774 100644 --- a/tests/unit/page.js +++ b/tests/unit/page.js @@ -609,6 +609,21 @@ describe('Page class', () => { }) }) + describe('introLinks', () => { + it('includes the links specified in the introLinks frontmatter', async () => { + const page = await Page.init({ + relativePath: 'article-with-introLinks.md', + basePath: path.join(__dirname, '../fixtures'), + languageCode: 'en', + }) + + expect(page.introLinks).toStrictEqual({ + overview: 'https://github.com', + 'custom link!': 'https://github.com/features', + }) + }) + }) + describe('Page.parseFrontmatter()', () => { it('throws an error on bad input', () => { const markdown = null