Merge branch 'main' into repo-sync
This commit is contained in:
@@ -45,10 +45,7 @@ export const ArticleList = ({
|
||||
{articles.map((link) => {
|
||||
return (
|
||||
<li key={link.href} className={cx(variant === 'compact' && 'border-top')}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="link-with-intro Bump-link--hover no-underline d-block py-3"
|
||||
>
|
||||
<Link href={link.href} className="Bump-link--hover no-underline d-block py-3">
|
||||
<h4 className="link-with-intro-title">
|
||||
<span dangerouslySetInnerHTML={{ __html: link.title }} />
|
||||
<span className="Bump-link-symbol">→</span>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<div class="d-flex col-12 col-md-4 pr-0 pr-md-6 pr-lg-8 <display condition> js-filter-card" data-type="{{ type.key }}" data-topics="{{ topics | join: ',' }}">
|
||||
<a class="no-underline d-flex flex-column py-3 border-bottom" href="{{ fullPath }}">
|
||||
<h4 class="h4 color-text-primary mb-1">{{ title }}</h4>
|
||||
<div class="h6 text-uppercase">{{ type.value }}</div>
|
||||
<p class="color-text-secondary my-3">{{ intro }}</p>
|
||||
{% if topics.length %}
|
||||
<div>
|
||||
{% for topic in topics %}
|
||||
<span class="IssueLabel bg-gradient--pink-blue color-text-inverse mr-1">{{ topic }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
- <a class="article-link link Bump-link--hover no-underline" href="{{ fullPath }}">{{ title }}</a>
|
||||
@@ -1,4 +0,0 @@
|
||||
<a class="link-with-intro Bump-link--hover no-underline" href="{{ fullPath }}">
|
||||
<h2 class="link-with-intro-title f4">{{ title }}<span class="Bump-link-symbol">→</span></h2>
|
||||
</a>
|
||||
{% if intro %}<p class="link-with-intro-intro">{{ intro }}</p>{% endif %}
|
||||
@@ -1 +0,0 @@
|
||||
<a class="link-title Bump-link--hover no-underline" href="{{ fullPath }}">{{ title }}</a>
|
||||
@@ -1 +0,0 @@
|
||||
- <a class="topic-link link Bump-link--hover no-underline" href="{{ fullPath }}">{{ title }}</a>
|
||||
@@ -5,7 +5,6 @@ See also [contributing/liquid-helpers.md](../../contributing/liquid-helpers.md)
|
||||
This directory contains custom Liquid tags for outputting dynamic content. These custom tags exist for a few reasons:
|
||||
|
||||
- Content and styling should be separated. Writers should not be concerned with writing or maintaining stylistic markup.
|
||||
- Writers should be able to create links by specifying the minimum amount of identifying information (an article href) and leave it to the site to dynamically inject that page's metadata like `title`, `intro`, etc.
|
||||
- Content should be localized to match the current language.
|
||||
- Styling and markup should be DRY and reusable.
|
||||
|
||||
@@ -19,49 +18,13 @@ Tags can be used in:
|
||||
Tags always expect a single argument, a language agnostic href:
|
||||
|
||||
```html
|
||||
{% link_with_intro /getting-started-with-github-desktop %}
|
||||
{% data variables.product.product_name %}
|
||||
```
|
||||
|
||||
where the reference must be in the parent file, `content/desktop/index.md`, as it points to `content/desktop/getting-started-with-github-desktop`.
|
||||
|
||||
The href can also be an absolute path:
|
||||
|
||||
```html
|
||||
{% link_with_intro /desktop/getting-started-with-github-desktop %}
|
||||
```
|
||||
|
||||
where the reference can be in any file.
|
||||
|
||||
**Note:** Every href, whether relative or absolute, must start with a slash (`/`). Do not include `content` in the href.
|
||||
|
||||
The tag above will output this HTML for English pages:
|
||||
|
||||
```html
|
||||
<a class="link-with-intro Bump-link--hover no-underline" href="/en/desktop/getting-started-with-github-desktop">
|
||||
<h4 class="link-with-intro-title">Getting started with GitHub Desktop<span class="Bump-link-symbol">→</span></h4>
|
||||
</a>
|
||||
<p class="link-with-intro-intro">Get GitHub Desktop set up to manage your project work. Authenticate to GitHub.com or GitHub Enterprise Server, keep the app up-to-date, and review your preferred settings.</p>
|
||||
```
|
||||
|
||||
and this HTML for Spanish pages:
|
||||
|
||||
```html
|
||||
<a class="link-with-intro Bump-link--hover no-underline" href="/es/desktop/getting-started-with-github-desktop">
|
||||
<h4 class="link-with-intro-title">Comenzar con GitHub Desktop<span class="Bump-link-symbol">→</span></h4></a>
|
||||
<p class="link-with-intro-intro">Configura GitHub Desktop para administrar tu proyecto de trabajo. Autentícate en GitHub.com o en el Servidor de GitHub Enterprise, mantén la app actualizada y revisa tu configuración preferida.</p>
|
||||
```
|
||||
|
||||
Note that link tags will only render links that are available in the current page version (i.e. GitHub.com vs Enterprise), so it's not necessary to add Liquid conditionals around them.
|
||||
|
||||
## Supported tags
|
||||
|
||||
| Markup | Renders |
|
||||
| -- | -- |
|
||||
| `{% link /href %}` | The linked page's title, with no special styling.
|
||||
| `{% link_with_intro /href %}` | The linked page's title and intro.
|
||||
| `{% homepage_link_with_intro /href %}` | The linked page's title and intro, with homepage-specific styling.
|
||||
| `{% link_in_list /href %}` | The linked page's title in a list item.
|
||||
| `{% topic_link_in_list /href %}` | The linked map topic's title in a list item (used in category TOCs).
|
||||
| `{% indented_data_reference foo.bar spaces=NUMBER %}` | A data reference with the specified number of spaces prepended to each line. Defaults to 2 spaces if no spaces included. For example: `{% indented_data_reference reusables.pages.wildcard-dns-warning spaces=3 %}`
|
||||
|
||||
## Creating tags
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import link from './link.js'
|
||||
// For details, see class method in lib/liquid-tags/link.js
|
||||
export default link('homepage-link-with-intro')
|
||||
@@ -1,16 +0,0 @@
|
||||
import link from './link.js'
|
||||
const linkAsArticleCard = link('link-as-article-card')
|
||||
|
||||
// For details, see class method in lib/liquid-tags/link.js
|
||||
linkAsArticleCard.renderPageProps = async function renderPageProps(page, ctx, props) {
|
||||
const renderedProps = await link().renderPageProps(page, ctx, props)
|
||||
const { type: typeKey, topics = [] } = page
|
||||
const typeVal = typeKey ? ctx.site.data.ui.product_sublanding.guide_types[typeKey] : null
|
||||
return {
|
||||
...renderedProps,
|
||||
type: { key: typeKey, value: typeVal },
|
||||
topics,
|
||||
}
|
||||
}
|
||||
|
||||
export default linkAsArticleCard
|
||||
@@ -1,2 +0,0 @@
|
||||
import link from './link.js'
|
||||
export default link('link-in-list')
|
||||
@@ -1,3 +0,0 @@
|
||||
import link from './link.js'
|
||||
// For details, see class method in lib/liquid-tags/link.js
|
||||
export default link('link-with-intro')
|
||||
@@ -1,113 +0,0 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
import assert from 'assert'
|
||||
import readFileAsync from '../readfile-async.js'
|
||||
import findPage from '../find-page.js'
|
||||
import { getPathWithoutLanguage, getPathWithoutVersion } from '../path-utils.js'
|
||||
import getApplicableVersions from '../get-applicable-versions.js'
|
||||
import removeFPTFromPath from '../remove-fpt-from-path.js'
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const liquidVariableSyntax = /^{{\s*(.*)\s*}}/
|
||||
|
||||
// This class supports a set of link tags. Each tag expects one parameter, a language-agnostic href:
|
||||
//
|
||||
// {% link /articles/set-up-git %}
|
||||
//
|
||||
// {% link_in_list /articles/set-up-git %}
|
||||
//
|
||||
// {% link_with_intro /articles/set-up-git %}
|
||||
//
|
||||
// {% homepage_link_with_intro /articles/set-up-git %}
|
||||
//
|
||||
// Each tag renders a link to the given article using the article's `title`
|
||||
// frontmatter data. The href and title are all dynamic based on the
|
||||
// current language (English, Japanese, etc..)
|
||||
//
|
||||
// Liquid Docs: https://github.com/liquid-lang/liquid-node#registering-new-tags
|
||||
|
||||
export default (name) => ({
|
||||
parse(tagToken) {
|
||||
this.param = tagToken.args.trim()
|
||||
},
|
||||
|
||||
async getTemplate() {
|
||||
const pathToTemplate = path.join(__dirname, '../../includes/liquid-tags', `${name}.html`)
|
||||
const template = await readFileAsync(pathToTemplate, 'utf8')
|
||||
return template.replace(/\r/g, '')
|
||||
},
|
||||
|
||||
async renderPageProps(page, ctx, props) {
|
||||
const renderedProps = {}
|
||||
|
||||
for (const propName in props) {
|
||||
const { opt } = props[propName] || {}
|
||||
renderedProps[propName] = await page.renderProp(propName, ctx, opt)
|
||||
}
|
||||
|
||||
return renderedProps
|
||||
},
|
||||
|
||||
async render(scope) {
|
||||
const template = await this.getTemplate()
|
||||
|
||||
const ctx = scope.environments
|
||||
|
||||
assert(ctx.page, 'context.page is required')
|
||||
assert(ctx.page.relativePath, 'context.page.relativePath is required')
|
||||
assert(ctx.pages, 'context.pages is required')
|
||||
assert(ctx.currentLanguage, 'context.currentLanguage is required')
|
||||
|
||||
// process any liquid in hrefs (e.g., /enterprise/{{ page.version }})
|
||||
let href = await this.liquid.parseAndRender(this.param, ctx)
|
||||
if (href === '') {
|
||||
const match = liquidVariableSyntax.exec(this.param)
|
||||
if (match) {
|
||||
href = await this.liquid.evalValue(match[1], scope)
|
||||
}
|
||||
}
|
||||
|
||||
let fullPath = href
|
||||
const dirName = path.dirname(ctx.page.relativePath)
|
||||
|
||||
// if href contains one slash, assume it's a relative path and infer the full path
|
||||
// example: /site-policy (linked to from /github/index.md)
|
||||
// becomes: /github/site-policy
|
||||
// otherwise, assume it's already a full path and needs nothing further
|
||||
const hrefMatch = href.match(/\//g)
|
||||
if (hrefMatch && hrefMatch.length < 2) {
|
||||
fullPath = path.join(dirName, href)
|
||||
}
|
||||
|
||||
// add language code and version
|
||||
fullPath = removeFPTFromPath(
|
||||
path.posix.join(
|
||||
'/',
|
||||
ctx.currentLanguage,
|
||||
ctx.currentVersion,
|
||||
getPathWithoutLanguage(getPathWithoutVersion(fullPath))
|
||||
)
|
||||
)
|
||||
|
||||
// find the page based on the full path
|
||||
const page = findPage(fullPath, ctx.pages, ctx.redirects)
|
||||
|
||||
// return an empty string if it's a hidden link on a non-hidden page (hidden links on hidden pages are OK)
|
||||
if (!page || (page.hidden && !ctx.page.hidden)) {
|
||||
return ''
|
||||
}
|
||||
// also return early if the found page should not render in current version
|
||||
if (!getApplicableVersions(page.versions).includes(ctx.currentVersion)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
// find and render the props
|
||||
const renderedProps = await this.renderPageProps(page, ctx, {
|
||||
title: { opt: { textOnly: true, encodeEntities: true } },
|
||||
intro: { opt: { unwrap: true } },
|
||||
})
|
||||
|
||||
const parsed = await this.liquid.parseAndRender(template, { fullPath, ...renderedProps })
|
||||
|
||||
return parsed.trim()
|
||||
},
|
||||
})
|
||||
@@ -1,2 +0,0 @@
|
||||
import link from './link.js'
|
||||
export default link('topic-link-in-list')
|
||||
@@ -1,25 +1,14 @@
|
||||
import GithubSlugger from 'github-slugger'
|
||||
import renderContent from './renderContent.js'
|
||||
import { ExtendedMarkdown, tags } from '../liquid-tags/extended-markdown.js'
|
||||
import Link from '../liquid-tags/link.js'
|
||||
import LinkWithIntro from '../liquid-tags/link-with-intro.js'
|
||||
import LinkInList from '../liquid-tags/link-in-list.js'
|
||||
import TopicLinkInList from '../liquid-tags/topic-link-in-list.js'
|
||||
import IndentedDataReference from '../liquid-tags/indented-data-reference.js'
|
||||
import Data from '../liquid-tags/data.js'
|
||||
import Octicon from '../liquid-tags/octicon.js'
|
||||
import LinkAsArticleCard from '../liquid-tags/link-as-article-card.js'
|
||||
import Ifversion from '../liquid-tags/ifversion.js'
|
||||
|
||||
// Include custom tags like {% link_with_intro /article/foo %}
|
||||
renderContent.liquid.registerTag('link', Link('link'))
|
||||
renderContent.liquid.registerTag('link_with_intro', LinkWithIntro)
|
||||
renderContent.liquid.registerTag('link_in_list', LinkInList)
|
||||
renderContent.liquid.registerTag('topic_link_in_list', TopicLinkInList)
|
||||
renderContent.liquid.registerTag('indented_data_reference', IndentedDataReference)
|
||||
renderContent.liquid.registerTag('data', Data)
|
||||
renderContent.liquid.registerTag('octicon', Octicon)
|
||||
renderContent.liquid.registerTag('link_as_article_card', LinkAsArticleCard)
|
||||
renderContent.liquid.registerTag('ifversion', Ifversion)
|
||||
|
||||
for (const tag in tags) {
|
||||
|
||||
@@ -6,7 +6,7 @@ describe('curated homepage links', () => {
|
||||
|
||||
test('English', async () => {
|
||||
const $ = await getDOM('/en')
|
||||
const $links = $('a.link-with-intro')
|
||||
const $links = $('a.Bump-link--hover')
|
||||
expect($links.length).toBeGreaterThanOrEqual(8)
|
||||
|
||||
// Check that each link is localized and includes a title and intro
|
||||
@@ -32,7 +32,7 @@ describe('curated homepage links', () => {
|
||||
|
||||
test('Japanese', async () => {
|
||||
const $ = await getDOM('/ja')
|
||||
const $links = $('a.link-with-intro')
|
||||
const $links = $('a.Bump-link--hover')
|
||||
expect($links.length).toBeGreaterThanOrEqual(8)
|
||||
|
||||
// Check that each link is localized and includes a title and intro
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { jest } from '@jest/globals'
|
||||
import { liquid } from '../../lib/render-content/index.js'
|
||||
import { loadPageMap } from '../../lib/page-data.js'
|
||||
import htmlEntities from 'html-entities'
|
||||
import nonEnterpriseDefaultVersion from '../../lib/non-enterprise-default-version.js'
|
||||
const entities = new htmlEntities.XmlEntities()
|
||||
|
||||
describe('liquid helper tags', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
@@ -33,75 +31,6 @@ describe('liquid helper tags', () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('link tag with relative path (English)', async () => {
|
||||
const template = '{% link /contributing-and-collaborating-using-github-desktop %}'
|
||||
const expected =
|
||||
'<a class="link-title Bump-link--hover no-underline" href="/en/desktop/contributing-and-collaborating-using-github-desktop">Contributing and collaborating using GitHub Desktop</a>'
|
||||
const output = await liquid.parseAndRender(template, context)
|
||||
expect(output).toBe(expected)
|
||||
})
|
||||
|
||||
test('link tag with relative path (translated)', async () => {
|
||||
context.currentLanguage = 'ja'
|
||||
const template = '{% link /contributing-and-collaborating-using-github-desktop %}'
|
||||
const expected =
|
||||
'<a class="link-title Bump-link--hover no-underline" href="/ja/desktop/contributing-and-collaborating-using-github-desktop">'
|
||||
const output = await liquid.parseAndRender(template, context)
|
||||
expect(output.includes(expected)).toBe(true)
|
||||
// set this back to english
|
||||
context.currentLanguage = 'en'
|
||||
})
|
||||
|
||||
test('link tag with local variable', async () => {
|
||||
const template = `{% assign href = "/contributing-and-collaborating-using-github-desktop" %}
|
||||
{% link {{ href }} %}`
|
||||
const expected =
|
||||
'<a class="link-title Bump-link--hover no-underline" href="/en/desktop/contributing-and-collaborating-using-github-desktop">'
|
||||
const output = await liquid.parseAndRender(template, context)
|
||||
expect(output.includes(expected)).toBe(true)
|
||||
})
|
||||
|
||||
test('link tag with absolute path', async () => {
|
||||
context.currentLanguage = 'en'
|
||||
const template =
|
||||
'{% link /desktop/contributing-and-collaborating-using-github-desktop/adding-and-cloning-repositories %}'
|
||||
const expected =
|
||||
'<a class="link-title Bump-link--hover no-underline" href="/en/desktop/contributing-and-collaborating-using-github-desktop/adding-and-cloning-repositories">Adding and cloning repositories</a>'
|
||||
const output = await liquid.parseAndRender(template, context)
|
||||
expect(output).toBe(expected)
|
||||
})
|
||||
|
||||
test('link_with_intro tag', async () => {
|
||||
const template = '{% link_with_intro /contributing-and-collaborating-using-github-desktop %}'
|
||||
const page = pageMap['/en/desktop/contributing-and-collaborating-using-github-desktop']
|
||||
const expected = `<a class="link-with-intro Bump-link--hover no-underline" href="/en/desktop/contributing-and-collaborating-using-github-desktop">
|
||||
<h2 class="link-with-intro-title f4">${page.title}<span class="Bump-link-symbol">→</span></h2>
|
||||
</a>
|
||||
<p class="link-with-intro-intro">${page.intro}</p>`
|
||||
const output = entities.decode(await liquid.parseAndRender(template, context))
|
||||
expect(output).toBe(expected)
|
||||
})
|
||||
|
||||
test('link_in_list tag', async () => {
|
||||
const template = '{% link_in_list /contributing-and-collaborating-using-github-desktop %}'
|
||||
const expected =
|
||||
'- <a class="article-link link Bump-link--hover no-underline" href="/en/desktop/contributing-and-collaborating-using-github-desktop">Contributing and collaborating using GitHub Desktop</a>'
|
||||
const output = await liquid.parseAndRender(template, context)
|
||||
expect(output).toBe(expected)
|
||||
})
|
||||
|
||||
test('link_as_article_card', async () => {
|
||||
const template =
|
||||
'{% link_as_article_card /contributing-and-collaborating-using-github-desktop %}'
|
||||
const expected = `<div class="d-flex col-12 col-md-4 pr-0 pr-md-6 pr-lg-8 <display condition> js-filter-card" data-type="" data-topics="">
|
||||
<a class="no-underline d-flex flex-column py-3 border-bottom" href="/en/desktop/contributing-and-collaborating-using-github-desktop">
|
||||
<h4 class="h4 color-text-primary mb-1">Contributing and collaborating using GitHub Desktop</h4>
|
||||
<div class="h6 text-uppercase"></div>
|
||||
<p class="color-text-secondary my-3">Use GitHub Desktop to manage your projects, create meaningful commits, and track the project's history in an app instead of on the command line.</p>`
|
||||
const output = await liquid.parseAndRender(template, context)
|
||||
expect(output.includes(expected)).toBe(true)
|
||||
})
|
||||
|
||||
describe('indented_data_reference tag', () => {
|
||||
test('without any number of spaces specified', async () => {
|
||||
const template = '{% indented_data_reference reusables.example %}'
|
||||
|
||||
Reference in New Issue
Block a user