Skip to content

Commit 2573702

Browse files
authored
Merge pull request #632 from FortAwesome/chore/docs-cleanup
chore(docs): clean up API docs output structure, rewrite html links
2 parents c540f90 + a7782b8 commit 2573702

File tree

6 files changed

+120
-13
lines changed

6 files changed

+120
-13
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ but intended to evolve over time with _community_ contributions.
77

88
Trying to figure out how to make it work? Or how to use it in your scenario?
99

10-
1. Review the [README](README.md)
10+
1. Review the [README](https://github.com/FortAwesome/react-fontawesome?tab=readme-ov-file)
1111
2. Get familiar with the documentation for the [SVG with JavaScript](https://fontawesome.com/how-to-use/svg-with-js) implementation,
1212
the framework upon which this component is built. Sometimes the answers you need may be there.
1313
3. Post any remaining questions on [StackOverflow](https://stackoverflow.com/questions/tagged/react-fontawesome) with the tag `react-fontawesome`.

docs/src/API-Reference-Readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Overview <i color="#428fdc" class="fa-solid fa-font-awesome" aria-label="FontAwesome"></i>
1+
# Overview <i color="#428fdc" class="fa-solid fa-font-awesome"></i>
22

33
This documentation serves purely as an API Reference for the modules contained in the latest version of the `react-fontawesome` library.
44

@@ -15,8 +15,8 @@ For more detailed documentation on how to use FontAwesome with React in general,
1515

1616
In the side-bar menu, the top level items are the two key module entry points that are exported by the library:
1717

18-
- `index` - includes anything exported via the main entry point
18+
- `main` - includes anything exported via the main entry point
1919
- e.g. `import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'`
20-
- `components/rsc/CustomPrefixProvider` - special module for using custom FA prefixes with server-side rendering
20+
- `CustomPrefixProvider` - special module for using custom FA prefixes with server-side rendering
2121
- e.g. `import { CustomPrefixProvider } from '@fortawesome/react-fontawesome/components/rsc/CustomPrefixProvider'`
2222
- `<internal>` - refers to types and interfaces that are used internally within the package but are not exported by the package to consumers

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/rsc/CustomPrefixProvider.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/** @module CustomPrefixProvider */
2+
13
'use client'
24

35
import { config } from '@fortawesome/fontawesome-svg-core'

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @module main */
12
export * from './components/FontAwesomeIcon'
23
export * from './components/FontAwesomeLayers'
34
export * from './types/animation-props'

typedoc.config.mjs

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,138 @@
1+
import { cp, mkdir, readdir } from 'node:fs/promises'
2+
import path from 'node:path'
3+
import fs from 'node:fs'
14
import { JSX } from 'typedoc'
25

36
/**
4-
* Custom TypeDoc plugin to insert FontAwesome into the generated documentation.
5-
* @type {(app: import('typedoc').Application) => void}
7+
* Custom TypeDoc plugin.
8+
* @param {import('typedoc').Application} app
69
*/
710
function customPlugin(app) {
11+
/**
12+
* Remove `.html` from internal links while preserving query/hash fragments.
13+
* External links are left untouched.
14+
* @param {string} href
15+
*/
16+
function toExtensionlessHref(href, ignoreAbsolute = true) {
17+
// Ignore absolute/protocol links and special schemes.
18+
if (
19+
ignoreAbsolute &&
20+
(/^(?:[a-z][a-z\d+.-]*:)?\/\//i.test(href) ||
21+
/^[a-z][a-z\d+.-]*:/i.test(href))
22+
) {
23+
return href
24+
}
25+
26+
const [withoutHash, hash = ''] = href.split('#', 2)
27+
const [pathname, query = ''] = withoutHash.split('?', 2)
28+
29+
let nextPath = pathname
30+
if (nextPath.endsWith('/index.html')) {
31+
nextPath = nextPath.slice(0, -'index.html'.length)
32+
} else if (nextPath === 'index.html') {
33+
nextPath = './'
34+
} else if (nextPath.endsWith('.html')) {
35+
nextPath = nextPath.slice(0, -'.html'.length)
36+
}
37+
38+
const rebuilt = `${nextPath}${query ? `?${query}` : ''}`
39+
return `${rebuilt}${hash ? `#${hash}` : ''}`
40+
}
41+
42+
// Insert FontAwesome CSS into the head of the generated documentation
843
app.renderer.hooks.on('head.end', (_context) => {
944
return JSX.createElement('link', {
1045
rel: 'stylesheet',
1146
href: 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.2.0/css/fontawesome.min.css',
1247
})
1348
})
1449

50+
// Insert FontAwesome JS into the body of the generated documentation
1551
app.renderer.hooks.on('body.end', (_context) => {
1652
return JSX.createElement('script', {
1753
src: 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.2.0/js/all.min.js',
1854
defer: true,
1955
})
2056
})
57+
58+
// Rewrite generated internal links to extensionless paths.
59+
app.renderer.on('endPage', (page) => {
60+
if (!page.contents) {
61+
return
62+
}
63+
64+
page.contents = page.contents.replaceAll(
65+
/href="([^"]+)"/g,
66+
(_match, href) => {
67+
return `href="${toExtensionlessHref(href)}"`
68+
},
69+
)
70+
})
71+
72+
app.renderer.postRenderAsyncJobs.push(async (event) => {
73+
// Create `name/index.html` aliases for root-level `name.html` pages.
74+
const rootEntries = await readdir(event.outputDirectory, {
75+
withFileTypes: true,
76+
})
77+
const rootHtmlFiles = rootEntries.filter(
78+
(entry) =>
79+
entry.isFile() &&
80+
entry.name.endsWith('.html') &&
81+
entry.name !== 'index.html' &&
82+
entry.name !== '404.html',
83+
)
84+
85+
await Promise.all(
86+
rootHtmlFiles.map(async (entry) => {
87+
const fileName = entry.name
88+
const basename = fileName.slice(0, -'.html'.length)
89+
const source = path.join(event.outputDirectory, fileName)
90+
const targetDir = path.join(event.outputDirectory, basename)
91+
const target = path.join(targetDir, 'index.html')
92+
93+
await mkdir(targetDir, { recursive: true })
94+
await cp(source, target)
95+
}),
96+
)
97+
98+
// Rewrite the `.html` extension from the generated `sitemap.xml` as well.
99+
const sitemapPath = path.join(event.outputDirectory, 'sitemap.xml')
100+
try {
101+
const sitemapContents = fs.readFileSync(sitemapPath).toString('utf-8')
102+
const rewritten = sitemapContents
103+
.toString()
104+
.replaceAll(/<loc>([^<]+)<\/loc>/g, (_match, loc) => {
105+
return `<loc>${toExtensionlessHref(loc, false)}</loc>`
106+
})
107+
await fs.writeFile(sitemapPath, rewritten, () => {})
108+
} catch (err) {
109+
// If the sitemap doesn't exist, ignore the error and continue.
110+
if (err.code !== 'ENOENT') {
111+
throw err
112+
}
113+
}
114+
})
21115
}
22116

23117
/** @type {Partial<import('typedoc').TypeDocOptions> & Partial<import('typedoc-plugin-merge-modules').Config> & import('typedoc-plugin-umami-analytics').Config} */
24118
const config = {
119+
cleanOutputDir: true,
25120
commentStyle: 'all',
26121
customFooterHtml:
27122
'Built with <i color="#f31e1e" class="fa-solid fa-heart" aria-label="love"></i> by the <a href="https://fontawesome.com/">FontAwesome Team</a> and <a href="https://github.com/FortAwesome/react-fontawesome/graphs/contributors">community contributors</a>.',
28123
entryPoints: ['./src/index.ts', './src/components/rsc/*.tsx'],
29-
entryPointStrategy: 'resolve',
124+
// entryPointStrategy: 'resolve',
30125
excludeExternals: true,
31126
excludeNotDocumented: false,
32127
// Ensure references from @fortawesome packages are not considered external and therefore excluded, e.g. svg-core & common-types (we want them included)
33128
externalPattern: ['**/node_modules/!(@fortawesome)/**'],
129+
githubPages: true,
34130
gitRemote: 'origin',
35131
gitRevision: 'main',
36132
favicon: './docs/src/assets/favicon.ico',
37133
hideGenerator: true,
134+
hostedBaseUrl: 'https://fortawesome.github.io/react-fontawesome/',
135+
markdownLinkExternal: true,
38136
mergeModulesMergeMode: 'module',
39137
mergeModulesRenameDefaults: true,
40138
name: 'FontAwesome React API Reference',
@@ -53,20 +151,26 @@ const config = {
53151
'typedoc-plugin-umami-analytics',
54152
customPlugin,
55153
],
56-
projectDocuments: ['./CHANGELOG.md'],
154+
projectDocuments: [
155+
'./CHANGELOG.md',
156+
'./CONTRIBUTING.md',
157+
'./CODE_OF_CONDUCT.md',
158+
],
57159
readme: './docs/src/API-Reference-Readme.md',
58-
router: 'structure',
160+
router: 'structure-dir',
59161
sort: [
60162
'required-first',
61163
'kind',
62164
'instance-first',
63165
'alphabetical-ignoring-documents',
64166
],
65-
tsconfig: './tsconfig.json',
167+
sourceLinkExternal: true,
66168
theme: 'typedoc-github-theme',
169+
tsconfig: './tsconfig.json',
67170
umamiScriptURL: 'https://analytics.charlesharwood.dev/script.js',
68171
umamiWebsiteID: 'd0b01ae4-f0b1-4f6c-8967-6a9c1504cd49',
69172
useFirstParagraphOfCommentAsSummary: true,
173+
visibilityFilters: {},
70174
}
71175

72176
export default config

0 commit comments

Comments
 (0)