diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 01c13f3..7df1473 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,7 +7,7 @@ but intended to evolve over time with _community_ contributions.
Trying to figure out how to make it work? Or how to use it in your scenario?
-1. Review the [README](README.md)
+1. Review the [README](https://github.com/FortAwesome/react-fontawesome?tab=readme-ov-file)
2. Get familiar with the documentation for the [SVG with JavaScript](https://fontawesome.com/how-to-use/svg-with-js) implementation,
the framework upon which this component is built. Sometimes the answers you need may be there.
3. Post any remaining questions on [StackOverflow](https://stackoverflow.com/questions/tagged/react-fontawesome) with the tag `react-fontawesome`.
diff --git a/docs/src/API-Reference-Readme.md b/docs/src/API-Reference-Readme.md
index 785859a..304242d 100644
--- a/docs/src/API-Reference-Readme.md
+++ b/docs/src/API-Reference-Readme.md
@@ -1,4 +1,4 @@
-# Overview
+# Overview
This documentation serves purely as an API Reference for the modules contained in the latest version of the `react-fontawesome` library.
@@ -15,8 +15,8 @@ For more detailed documentation on how to use FontAwesome with React in general,
In the side-bar menu, the top level items are the two key module entry points that are exported by the library:
-- `index` - includes anything exported via the main entry point
+- `main` - includes anything exported via the main entry point
- e.g. `import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'`
-- `components/rsc/CustomPrefixProvider` - special module for using custom FA prefixes with server-side rendering
+- `CustomPrefixProvider` - special module for using custom FA prefixes with server-side rendering
- e.g. `import { CustomPrefixProvider } from '@fortawesome/react-fontawesome/components/rsc/CustomPrefixProvider'`
- `` - refers to types and interfaces that are used internally within the package but are not exported by the package to consumers
diff --git a/package-lock.json b/package-lock.json
index a295a32..88d5984 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9570,9 +9570,9 @@
}
},
"node_modules/flatted": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz",
- "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
diff --git a/src/components/rsc/CustomPrefixProvider.tsx b/src/components/rsc/CustomPrefixProvider.tsx
index c493b46..737a323 100644
--- a/src/components/rsc/CustomPrefixProvider.tsx
+++ b/src/components/rsc/CustomPrefixProvider.tsx
@@ -1,3 +1,5 @@
+/** @module CustomPrefixProvider */
+
'use client'
import { config } from '@fortawesome/fontawesome-svg-core'
diff --git a/src/index.ts b/src/index.ts
index 87f11f3..cd03cdc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,4 @@
+/** @module main */
export * from './components/FontAwesomeIcon'
export * from './components/FontAwesomeLayers'
export * from './types/animation-props'
diff --git a/typedoc.config.mjs b/typedoc.config.mjs
index 0cfa05f..9e6af96 100644
--- a/typedoc.config.mjs
+++ b/typedoc.config.mjs
@@ -1,10 +1,45 @@
+import { cp, mkdir, readdir } from 'node:fs/promises'
+import path from 'node:path'
+import fs from 'node:fs'
import { JSX } from 'typedoc'
/**
- * Custom TypeDoc plugin to insert FontAwesome into the generated documentation.
- * @type {(app: import('typedoc').Application) => void}
+ * Custom TypeDoc plugin.
+ * @param {import('typedoc').Application} app
*/
function customPlugin(app) {
+ /**
+ * Remove `.html` from internal links while preserving query/hash fragments.
+ * External links are left untouched.
+ * @param {string} href
+ */
+ function toExtensionlessHref(href, ignoreAbsolute = true) {
+ // Ignore absolute/protocol links and special schemes.
+ if (
+ ignoreAbsolute &&
+ (/^(?:[a-z][a-z\d+.-]*:)?\/\//i.test(href) ||
+ /^[a-z][a-z\d+.-]*:/i.test(href))
+ ) {
+ return href
+ }
+
+ const [withoutHash, hash = ''] = href.split('#', 2)
+ const [pathname, query = ''] = withoutHash.split('?', 2)
+
+ let nextPath = pathname
+ if (nextPath.endsWith('/index.html')) {
+ nextPath = nextPath.slice(0, -'index.html'.length)
+ } else if (nextPath === 'index.html') {
+ nextPath = './'
+ } else if (nextPath.endsWith('.html')) {
+ nextPath = nextPath.slice(0, -'.html'.length)
+ }
+
+ const rebuilt = `${nextPath}${query ? `?${query}` : ''}`
+ return `${rebuilt}${hash ? `#${hash}` : ''}`
+ }
+
+ // Insert FontAwesome CSS into the head of the generated documentation
app.renderer.hooks.on('head.end', (_context) => {
return JSX.createElement('link', {
rel: 'stylesheet',
@@ -12,29 +47,92 @@ function customPlugin(app) {
})
})
+ // Insert FontAwesome JS into the body of the generated documentation
app.renderer.hooks.on('body.end', (_context) => {
return JSX.createElement('script', {
src: 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.2.0/js/all.min.js',
defer: true,
})
})
+
+ // Rewrite generated internal links to extensionless paths.
+ app.renderer.on('endPage', (page) => {
+ if (!page.contents) {
+ return
+ }
+
+ page.contents = page.contents.replaceAll(
+ /href="([^"]+)"/g,
+ (_match, href) => {
+ return `href="${toExtensionlessHref(href)}"`
+ },
+ )
+ })
+
+ app.renderer.postRenderAsyncJobs.push(async (event) => {
+ // Create `name/index.html` aliases for root-level `name.html` pages.
+ const rootEntries = await readdir(event.outputDirectory, {
+ withFileTypes: true,
+ })
+ const rootHtmlFiles = rootEntries.filter(
+ (entry) =>
+ entry.isFile() &&
+ entry.name.endsWith('.html') &&
+ entry.name !== 'index.html' &&
+ entry.name !== '404.html',
+ )
+
+ await Promise.all(
+ rootHtmlFiles.map(async (entry) => {
+ const fileName = entry.name
+ const basename = fileName.slice(0, -'.html'.length)
+ const source = path.join(event.outputDirectory, fileName)
+ const targetDir = path.join(event.outputDirectory, basename)
+ const target = path.join(targetDir, 'index.html')
+
+ await mkdir(targetDir, { recursive: true })
+ await cp(source, target)
+ }),
+ )
+
+ // Rewrite the `.html` extension from the generated `sitemap.xml` as well.
+ const sitemapPath = path.join(event.outputDirectory, 'sitemap.xml')
+ try {
+ const sitemapContents = fs.readFileSync(sitemapPath).toString('utf-8')
+ const rewritten = sitemapContents
+ .toString()
+ .replaceAll(/([^<]+)<\/loc>/g, (_match, loc) => {
+ return `${toExtensionlessHref(loc, false)}`
+ })
+ await fs.writeFile(sitemapPath, rewritten, () => {})
+ } catch (err) {
+ // If the sitemap doesn't exist, ignore the error and continue.
+ if (err.code !== 'ENOENT') {
+ throw err
+ }
+ }
+ })
}
/** @type {Partial & Partial & import('typedoc-plugin-umami-analytics').Config} */
const config = {
+ cleanOutputDir: true,
commentStyle: 'all',
customFooterHtml:
'Built with by the FontAwesome Team and community contributors.',
entryPoints: ['./src/index.ts', './src/components/rsc/*.tsx'],
- entryPointStrategy: 'resolve',
+ // entryPointStrategy: 'resolve',
excludeExternals: true,
excludeNotDocumented: false,
// Ensure references from @fortawesome packages are not considered external and therefore excluded, e.g. svg-core & common-types (we want them included)
externalPattern: ['**/node_modules/!(@fortawesome)/**'],
+ githubPages: true,
gitRemote: 'origin',
gitRevision: 'main',
favicon: './docs/src/assets/favicon.ico',
hideGenerator: true,
+ hostedBaseUrl: 'https://fortawesome.github.io/react-fontawesome/',
+ markdownLinkExternal: true,
mergeModulesMergeMode: 'module',
mergeModulesRenameDefaults: true,
name: 'FontAwesome React API Reference',
@@ -53,20 +151,26 @@ const config = {
'typedoc-plugin-umami-analytics',
customPlugin,
],
- projectDocuments: ['./CHANGELOG.md'],
+ projectDocuments: [
+ './CHANGELOG.md',
+ './CONTRIBUTING.md',
+ './CODE_OF_CONDUCT.md',
+ ],
readme: './docs/src/API-Reference-Readme.md',
- router: 'structure',
+ router: 'structure-dir',
sort: [
'required-first',
'kind',
'instance-first',
'alphabetical-ignoring-documents',
],
- tsconfig: './tsconfig.json',
+ sourceLinkExternal: true,
theme: 'typedoc-github-theme',
+ tsconfig: './tsconfig.json',
umamiScriptURL: 'https://analytics.charlesharwood.dev/script.js',
umamiWebsiteID: 'd0b01ae4-f0b1-4f6c-8967-6a9c1504cd49',
useFirstParagraphOfCommentAsSummary: true,
+ visibilityFilters: {},
}
export default config