docusaurus-plugin-glossary 1.0.2 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -1
- package/index.js +7 -1
- package/package.json +4 -1
- package/remark/glossary-terms.js +41 -0
- package/theme/GlossaryTerm/index.js +23 -4
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A comprehensive Docusaurus plugin that provides glossary functionality with an auto-generated glossary page, searchable terms, and inline term tooltips.
|
|
4
4
|
|
|
5
|
+
> Compatibility: Fully compatible with Docusaurus v3 (MDX v3). If you were on a v2-era fork, please upgrade to the latest 1.x release of this plugin. No manual MDX pipeline wiring is required when `autoLinkTerms` is enabled (default).
|
|
6
|
+
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
9
|
- **Auto-generated Glossary Page**: Displays all terms alphabetically with letter navigation
|
|
@@ -38,7 +40,7 @@ A comprehensive Docusaurus plugin that provides glossary functionality with an a
|
|
|
38
40
|
};
|
|
39
41
|
```
|
|
40
42
|
|
|
41
|
-
**That
|
|
43
|
+
**That’s it!** On Docusaurus v3, the remark plugin is automatically configured via the plugin’s `configureMarkdown` hook — no manual `markdown.remarkPlugins` setup needed.
|
|
42
44
|
|
|
43
45
|
3. **Create your glossary file at `glossary/glossary.json`:**
|
|
44
46
|
```json
|
|
@@ -168,6 +170,24 @@ module.exports = {
|
|
|
168
170
|
};
|
|
169
171
|
```
|
|
170
172
|
|
|
173
|
+
## Docusaurus v3 Notes and Troubleshooting
|
|
174
|
+
|
|
175
|
+
- **MDX imports**: The plugin injects `import GlossaryTerm from '@theme/GlossaryTerm';` automatically when it auto-links a term. If you’re writing MDX manually, you can also import and use it yourself:
|
|
176
|
+
|
|
177
|
+
```mdx
|
|
178
|
+
import GlossaryTerm from '@theme/GlossaryTerm';
|
|
179
|
+
|
|
180
|
+
Our <GlossaryTerm term="API" /> uses <GlossaryTerm term="REST">RESTful</GlossaryTerm> principles.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- **No tooltips or no auto-linking?**
|
|
184
|
+
- Confirm you’re on `@docusaurus/core@^3` and `react@^18`.
|
|
185
|
+
- Ensure the plugin is listed in `plugins` and `autoLinkTerms` is not disabled.
|
|
186
|
+
- Visit `/glossary`. If the page or route fails to render, verify your `glossaryPath` file exists and contains a `terms` array.
|
|
187
|
+
- If you previously used a local patch for `1.0.0`, remove it when using `1.0.2+`; the plugin bundles the v3-compatible theme and remark integration.
|
|
188
|
+
|
|
189
|
+
- **Opting out of auto-linking**: set `autoLinkTerms: false` and add the remark plugin manually (see above), or only use the `<GlossaryTerm />` component where you want explicit control.
|
|
190
|
+
|
|
171
191
|
### Step 3: Use Glossary Terms in Your Content
|
|
172
192
|
|
|
173
193
|
#### Option A: Automatic Detection (Recommended)
|
package/index.js
CHANGED
|
@@ -81,7 +81,7 @@ function glossaryPlugin(context, options = {}) {
|
|
|
81
81
|
},
|
|
82
82
|
|
|
83
83
|
async contentLoaded({ content, actions }) {
|
|
84
|
-
const { createData, addRoute } = actions;
|
|
84
|
+
const { createData, addRoute, setGlobalData } = actions;
|
|
85
85
|
|
|
86
86
|
// Create data file that can be imported by components
|
|
87
87
|
const glossaryDataPath = await createData('glossary-data.json', JSON.stringify(content));
|
|
@@ -104,6 +104,12 @@ function glossaryPlugin(context, options = {}) {
|
|
|
104
104
|
glossaryData: glossaryDataPath,
|
|
105
105
|
},
|
|
106
106
|
});
|
|
107
|
+
|
|
108
|
+
// Expose global data for runtime lookups (used by GlossaryTerm)
|
|
109
|
+
setGlobalData({
|
|
110
|
+
terms: content.terms || [],
|
|
111
|
+
routePath,
|
|
112
|
+
});
|
|
107
113
|
},
|
|
108
114
|
|
|
109
115
|
getThemePath() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-plugin-glossary",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A Docusaurus plugin for creating and managing glossary terms with auto-generated pages and inline tooltips",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
"test": "jest",
|
|
16
16
|
"test:watch": "jest --watch",
|
|
17
17
|
"test:coverage": "jest --coverage",
|
|
18
|
+
"example:start": "npm --prefix examples/docusaurus-v3 run start",
|
|
19
|
+
"example:build": "npm --prefix examples/docusaurus-v3 run build",
|
|
20
|
+
"example:serve": "npm --prefix examples/docusaurus-v3 run serve",
|
|
18
21
|
"prepublishOnly": "npm test",
|
|
19
22
|
"version": "npm version",
|
|
20
23
|
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,md}\"",
|
package/remark/glossary-terms.js
CHANGED
|
@@ -168,6 +168,7 @@ function remarkGlossaryTerms({
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
return (tree) => {
|
|
171
|
+
let usedGlossaryTerm = false;
|
|
171
172
|
visit(tree, 'text', (node, index, parent) => {
|
|
172
173
|
// Skip text nodes inside code blocks, links, or existing MDX components
|
|
173
174
|
if (
|
|
@@ -199,6 +200,12 @@ function remarkGlossaryTerms({
|
|
|
199
200
|
};
|
|
200
201
|
}
|
|
201
202
|
}
|
|
203
|
+
if (
|
|
204
|
+
replacement.type === 'mdxJsxFlowElement' ||
|
|
205
|
+
replacement.type === 'mdxJsxTextElement'
|
|
206
|
+
) {
|
|
207
|
+
usedGlossaryTerm = true;
|
|
208
|
+
}
|
|
202
209
|
return replacement;
|
|
203
210
|
});
|
|
204
211
|
|
|
@@ -207,6 +214,40 @@ function remarkGlossaryTerms({
|
|
|
207
214
|
return index + newNodes.length - 1; // Return new index to continue
|
|
208
215
|
}
|
|
209
216
|
});
|
|
217
|
+
|
|
218
|
+
// Inject MDX import for GlossaryTerm if we used it anywhere in this file
|
|
219
|
+
if (usedGlossaryTerm) {
|
|
220
|
+
const importNode = {
|
|
221
|
+
type: 'mdxjsEsm',
|
|
222
|
+
value: "import GlossaryTerm from '@theme/GlossaryTerm';",
|
|
223
|
+
data: {
|
|
224
|
+
estree: {
|
|
225
|
+
type: 'Program',
|
|
226
|
+
sourceType: 'module',
|
|
227
|
+
body: [
|
|
228
|
+
{
|
|
229
|
+
type: 'ImportDeclaration',
|
|
230
|
+
specifiers: [
|
|
231
|
+
{
|
|
232
|
+
type: 'ImportDefaultSpecifier',
|
|
233
|
+
local: { type: 'Identifier', name: 'GlossaryTerm' }
|
|
234
|
+
}
|
|
235
|
+
],
|
|
236
|
+
source: { type: 'Literal', value: '@theme/GlossaryTerm' }
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Avoid duplicate imports if already present
|
|
244
|
+
const hasExistingImport = Array.isArray(tree.children) && tree.children.some(
|
|
245
|
+
(n) => n.type === 'mdxjsEsm' && typeof n.value === 'string' && n.value.includes("@theme/GlossaryTerm")
|
|
246
|
+
);
|
|
247
|
+
if (!hasExistingImport) {
|
|
248
|
+
tree.children.unshift(importNode);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
210
251
|
};
|
|
211
252
|
}
|
|
212
253
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import {usePluginData} from '@docusaurus/useGlobalData';
|
|
2
3
|
import styles from './styles.module.css';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -20,13 +21,31 @@ import styles from './styles.module.css';
|
|
|
20
21
|
export default function GlossaryTerm({ term, definition, routePath = '/glossary', children }) {
|
|
21
22
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
22
23
|
|
|
24
|
+
// Pull definition/route from plugin global data if not provided
|
|
25
|
+
const pluginData = usePluginData('docusaurus-plugin-glossary');
|
|
26
|
+
const effectiveDefinition = useMemo(() => {
|
|
27
|
+
if (definition && typeof definition === 'string' && definition.length > 0) {
|
|
28
|
+
return definition;
|
|
29
|
+
}
|
|
30
|
+
const terms = (pluginData && pluginData.terms) || [];
|
|
31
|
+
const found = terms.find(
|
|
32
|
+
(t) => typeof t.term === 'string' && t.term.toLowerCase() === String(term).toLowerCase()
|
|
33
|
+
);
|
|
34
|
+
return found && found.definition ? found.definition : undefined;
|
|
35
|
+
}, [definition, pluginData, term]);
|
|
36
|
+
|
|
37
|
+
const effectiveRoutePath = useMemo(() => {
|
|
38
|
+
if (routePath && typeof routePath === 'string' && routePath.length > 0) return routePath;
|
|
39
|
+
return (pluginData && pluginData.routePath) || '/glossary';
|
|
40
|
+
}, [pluginData, routePath]);
|
|
41
|
+
|
|
23
42
|
const displayText = children || term;
|
|
24
43
|
const termId = term.toLowerCase().replace(/\s+/g, '-');
|
|
25
44
|
|
|
26
45
|
return (
|
|
27
46
|
<span className={styles.glossaryTermWrapper}>
|
|
28
47
|
<a
|
|
29
|
-
href={`${
|
|
48
|
+
href={`${effectiveRoutePath}#${termId}`}
|
|
30
49
|
className={styles.glossaryTerm}
|
|
31
50
|
onMouseEnter={() => setShowTooltip(true)}
|
|
32
51
|
onMouseLeave={() => setShowTooltip(false)}
|
|
@@ -36,13 +55,13 @@ export default function GlossaryTerm({ term, definition, routePath = '/glossary'
|
|
|
36
55
|
>
|
|
37
56
|
{displayText}
|
|
38
57
|
</a>
|
|
39
|
-
{
|
|
58
|
+
{effectiveDefinition && (
|
|
40
59
|
<span
|
|
41
60
|
id={`tooltip-${termId}`}
|
|
42
61
|
className={`${styles.tooltip} ${showTooltip ? styles.tooltipVisible : ''}`}
|
|
43
62
|
role="tooltip"
|
|
44
63
|
>
|
|
45
|
-
<strong>{term}:</strong> {
|
|
64
|
+
<strong>{term}:</strong> {effectiveDefinition}
|
|
46
65
|
</span>
|
|
47
66
|
)}
|
|
48
67
|
</span>
|