Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: doc tags (same as blog tags) #3646

Merged
merged 35 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5b00807
[v2] tags to doc, same as tags to blog - [IN PROGRESS]
isaac-philip Oct 24, 2020
f618a72
docs: make tags list page work
slorber Oct 28, 2020
4949fb6
temp: disable onBrokenLinks
slorber Oct 28, 2020
947b034
theme bootstrap: create DocTagsListPage
slorber Oct 29, 2020
bc56aba
DocTagsPage added and functionality too
isaac-philip May 27, 2021
59212bb
Added all Docs Tags Link
isaac-philip May 29, 2021
7d454b4
Merge branch 'master' into docs_get_tags
slorber Aug 17, 2021
9c7773d
add some shared tag utils
slorber Aug 17, 2021
53337bf
move tag tests to _dogfooding
slorber Aug 17, 2021
5d11d6e
fix type
slorber Aug 17, 2021
89262c2
fix some tests
slorber Aug 17, 2021
636d82b
fix blog test
slorber Aug 17, 2021
dc897b6
refactor blog post tags handling
slorber Aug 17, 2021
975a1ae
Merge branch 'main' into docs_get_tags
slorber Aug 18, 2021
a31b864
better yaml tag examples
slorber Aug 18, 2021
c049e7b
better dogfood md files
slorber Aug 18, 2021
de11d50
refactor and factorize theme tag components
slorber Aug 18, 2021
3c358b4
finish DocTagDocListPage
slorber Aug 18, 2021
d6bbbb4
Extract DocItemFooter + add inline tag list
slorber Aug 18, 2021
7075b98
minor fix
slorber Aug 18, 2021
ea612f3
better typings
slorber Aug 18, 2021
7bc7473
fix versions.test.ts tests
slorber Aug 18, 2021
0a6d771
add tests for doc tags
slorber Aug 18, 2021
2c21138
fix tests
slorber Aug 18, 2021
134b896
test toTagDocListProp
slorber Aug 18, 2021
724b27d
move shared theme code to tagUtils
slorber Aug 18, 2021
51fd4ab
Add new theme translation keys
slorber Aug 18, 2021
1708882
move common theme code to tagUtils + add tests
slorber Aug 18, 2021
c3a1c76
update-code-translations should handle theme-common
slorber Aug 18, 2021
50b8c78
update french translation
slorber Aug 18, 2021
b3231ee
revert add translation
slorber Aug 18, 2021
15f3a44
fix pluralization problem in theme.docs.tagDocListPageTitle
slorber Aug 18, 2021
3171b83
add theme component configuration options
slorber Aug 18, 2021
f460912
add more tags tests
slorber Aug 18, 2021
58367bb
add documentation for docs tagging
slorber Aug 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ export async function readVersionDocs(
);
}

function readFrontmatterTags(frontMatter: any): string[] {
const tags: string[] = frontMatter.tags ?? [];
if (tags instanceof Array && tags.every((tag) => typeof tag === 'string')) {
return tags;
} else {
throw new Error(
`Bad frontmatter document tags.\nTags should be an array of strings.\nExample => 'tags: [tag1, tag2, tag3]'\nActual value=${tags}`,
);
}
}

export function processDocMetadata({
docFile,
versionMetadata,
Expand Down Expand Up @@ -175,6 +186,7 @@ export function processDocMetadata({
slug: docSlug,
permalink,
editUrl: custom_edit_url !== undefined ? custom_edit_url : docsEditUrl,
tags: readFrontmatterTags(frontMatter),
version: versionMetadata.versionName,
lastUpdatedBy: lastUpdate.lastUpdatedBy,
lastUpdatedAt: lastUpdate.lastUpdatedAt,
Expand Down
42 changes: 41 additions & 1 deletion packages/docusaurus-plugin-content-docs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ import {
LoadedVersion,
DocFile,
DocsMarkdownOption,
VersionTag,
} from './types';
import {PermalinkToSidebar} from '@docusaurus/plugin-content-docs-types';
import {RuleSetRule} from 'webpack';
import {cliDocsVersionCommand} from './cli';
import {VERSIONS_JSON_FILE} from './constants';
import {OptionsSchema} from './options';
import {flatten, keyBy, compact} from 'lodash';
import {flatten, keyBy, compact, mapValues} from 'lodash';
import {toGlobalDataVersion} from './globalData';
import {toVersionMetadataProp} from './props';
import chalk from 'chalk';
import {getVersionTags} from './tags';

export default function pluginContentDocs(
context: LoadContext,
Expand Down Expand Up @@ -217,10 +219,16 @@ export default function pluginContentDocs(
}
}

const tags = getVersionTags({
docs,
tagsPath: versionMetadata.tagsPath,
});

return {
...versionMetadata,
mainDocId: getMainDoc().unversionedId,
sidebars,
tags,
permalinkToSidebar,
docs: docs.map(addNavData),
};
Expand Down Expand Up @@ -262,7 +270,39 @@ export default function pluginContentDocs(
return routes.sort((a, b) => a.path.localeCompare(b.path));
};

async function createVersionTagsRoutes(loadedVersion: LoadedVersion) {
async function createTagsListRoute() {
const tagsProp = mapValues(loadedVersion.tags, (tagValue) => ({
name: tagValue.name,
permalink: tagValue.permalink,
count: tagValue.docIds.length,
}));
const tagsPropPath = await createData(
`${docuHash(`tags-list-${loadedVersion.versionName}-prop`)}.json`,
JSON.stringify(tagsProp, null, 2),
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is how you create a component prop as json object (should rather be moved to props.ts and have an explicit type)

addRoute({
path: loadedVersion.tagsPath,
exact: true,
component: '@theme/DocTagsListPage',
slorber marked this conversation as resolved.
Show resolved Hide resolved
modules: {
tags: aliasedSource(tagsPropPath),
slorber marked this conversation as resolved.
Show resolved Hide resolved
},
});
}

async function createTagPage(tag: VersionTag) {
// TODO
console.log(`todo createTagPage for tag=${tag.name}`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: do something similar to create one page per tag

}

await createTagsListRoute();
await Promise.all(Object.values(loadedVersion.tags).map(createTagPage));
}

async function handleVersion(loadedVersion: LoadedVersion) {
await createVersionTagsRoutes(loadedVersion);

const versionMetadataPropPath = await createData(
`${docuHash(
`version-${loadedVersion.versionName}-metadata-prop`,
Expand Down
47 changes: 47 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/tags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {normalizeUrl} from '@docusaurus/utils';
import {VersionTags, DocMetadata} from './types';
import {kebabCase} from 'lodash';

function normalizeTag(tag: string) {
return kebabCase(tag);
}

export function getVersionTags({
tagsPath,
docs,
}: {
tagsPath: string;
docs: DocMetadata[];
}): VersionTags {
const versionTags: VersionTags = {};

function initTagData(tag: string) {
return {
// Will only use the name of the first occurrence of the tag
name: tag.toLowerCase(),
permalink: normalizeUrl([tagsPath, normalizeTag(tag)]),
docIds: [],
};
}

docs.forEach((doc) => {
const tags: string[] = doc.tags ?? [];
tags.forEach((tag) => {
const normalizedTag = normalizeTag(tag);
// init data for a tag the first time we see it
if (!versionTags[normalizedTag]) {
versionTags[normalizedTag] = initTagData(tag);
}
versionTags[normalizedTag].docIds.push(doc.id);
});
});

return versionTags;
}
slorber marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 13 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type VersionMetadata = {
versionName: VersionName; // 1.0.0
versionLabel: string; // Version 1.0.0
versionPath: string; // /baseUrl/docs/1.0.0
tagsPath: string;
isLast: boolean;
docsDirPath: string; // versioned_docs/1.0.0
sidebarFilePath: string; // versioned_sidebars/1.0.0.json
Expand Down Expand Up @@ -117,6 +118,7 @@ export type DocMetadataBase = LastUpdateData & {
permalink: string;
sidebar_label?: string;
editUrl?: string | null;
tags: string[];
};

export type DocNavLink = {
Expand All @@ -133,10 +135,21 @@ export type DocMetadata = DocMetadataBase & {
export type SourceToPermalink = {
[source: string]: string;
};

export type VersionTag = {
name: string; // normalized name/label of the tag
docIds: string[]; // all doc ids having this tag
permalink: string; // pathname of the tag
};
export type VersionTags = {
[key: string]: VersionTag;
};

export type LoadedVersion = VersionMetadata & {
versionPath: string;
mainDocId: string;
docs: DocMetadata[];
tags: VersionTags;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the tags are per version, it's not just a global set of tags for all the docs of the site, there is one set of tag per version

sidebars: Sidebars;
permalinkToSidebar: Record<string, string>;
};
Expand Down
3 changes: 3 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,13 @@ function createVersionMetadata({
// Because /docs/:route` should always be after `/docs/versionName/:route`.
const routePriority = versionPathPart === '' ? -1 : undefined;

const tagsPath = normalizeUrl([versionPath, 'tags']);

return {
versionName,
versionLabel,
versionPath,
tagsPath,
isLast,
routePriority,
sidebarFilePath,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';

import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';

// TODO add TS types later
// import type {Props} from '@theme/DocTagsListPage';
type Props = {
tags: Record<string, {name: string; permalink: string; count: number}>;
};
slorber marked this conversation as resolved.
Show resolved Hide resolved

function getCategoryOfTag(tag: string) {
// tag's category should be customizable
return tag[0].toUpperCase();
}

function DocTagsListPage({tags}: Props): JSX.Element {
const tagCategories: {[category: string]: string[]} = {};
Object.keys(tags).forEach((tag) => {
const category = getCategoryOfTag(tag);
tagCategories[category] = tagCategories[category] || [];
tagCategories[category].push(tag);
});
const tagsList = Object.entries(tagCategories).sort(([a], [b]) => {
if (a === b) {
return 0;
}
return a > b ? 1 : -1;
});
const tagsSection = tagsList
.map(([category, tagsForCategory]) => (
<div key={category}>
<h3>{category}</h3>
{tagsForCategory.map((tag) => (
<Link
className="padding-right--md"
href={tags[tag].permalink}
key={tag}>
{tags[tag].name} ({tags[tag].count})
</Link>
))}
<hr />
</div>
))
.filter((item) => item != null);

return (
<Layout title="Tags" description="Doc Tags">
<div className="container margin-vert--lg">
<div className="row">
<main className="col col--8 col--offset-2">
<h1>Tags</h1>
<div className="margin-vert--lg">{tagsSection}</div>
</main>
</div>
</div>
</Layout>
);
}

export default DocTagsListPage;
slorber marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions website/docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: introduction
title: Introduction
description: Docusaurus was designed from the ground up to be easily installed and used to get your website up and running quickly.
slug: /
tags: [test-tag, myOtherTag]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just an example

---

## Disclaimer
Expand Down