-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
Changes from 2 commits
5b00807
f618a72
4949fb6
947b034
bc56aba
59212bb
7d454b4
9c7773d
53337bf
5d11d6e
89262c2
636d82b
dc897b6
975a1ae
a31b864
c049e7b
de11d50
3c358b4
d6bbbb4
7075b98
ea612f3
7bc7473
0a6d771
2c21138
134b896
724b27d
51fd4ab
1708882
c3a1c76
50b8c78
b3231ee
15f3a44
3171b83
f460912
58367bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
|
@@ -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), | ||
}; | ||
|
@@ -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), | ||
); | ||
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}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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`, | ||
|
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
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -117,6 +118,7 @@ export type DocMetadataBase = LastUpdateData & { | |
permalink: string; | ||
sidebar_label?: string; | ||
editUrl?: string | null; | ||
tags: string[]; | ||
}; | ||
|
||
export type DocNavLink = { | ||
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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>; | ||
}; | ||
|
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
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just an example |
||
--- | ||
|
||
## Disclaimer | ||
|
There was a problem hiding this comment.
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)