@defra/docusaurus-theme-govuk 0.0.8-alpha → 0.0.10-alpha
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/index.js
CHANGED
|
@@ -99,6 +99,23 @@ module.exports = function themeGovuk(context, options) {
|
|
|
99
99
|
break;
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
+
if (!resolved) {
|
|
103
|
+
// Also try {slug}/index.md for directory-based doc sections
|
|
104
|
+
for (const ext of ['.md', '.mdx']) {
|
|
105
|
+
const candidate = path.join(docsDir, slug, `index${ext}`);
|
|
106
|
+
if (fs.existsSync(candidate)) {
|
|
107
|
+
section.sidebar = {
|
|
108
|
+
_auto: true,
|
|
109
|
+
items: parseHeadingsToSidebar(
|
|
110
|
+
fs.readFileSync(candidate, 'utf-8'),
|
|
111
|
+
href
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
resolved = true;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
102
119
|
if (!resolved) {
|
|
103
120
|
console.warn(
|
|
104
121
|
`[docusaurus-theme-govuk] sidebar: "auto" on "${href}" — could not find markdown file at ${path.join(docsDir, slug)}.(md|mdx)`
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {useDoc} from '../docContext';
|
|
3
3
|
import MDXContent from '@theme/MDXContent';
|
|
4
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
4
5
|
|
|
5
6
|
// Render a synthetic title if needed
|
|
6
7
|
function useSyntheticTitle() {
|
|
7
8
|
const {metadata, frontMatter, contentTitle} = useDoc();
|
|
9
|
+
const {siteConfig} = useDocusaurusContext();
|
|
8
10
|
const shouldRender =
|
|
9
11
|
!frontMatter.hide_title &&
|
|
10
12
|
typeof contentTitle === 'undefined' &&
|
|
@@ -12,6 +14,10 @@ function useSyntheticTitle() {
|
|
|
12
14
|
if (!shouldRender) {
|
|
13
15
|
return null;
|
|
14
16
|
}
|
|
17
|
+
// For the root index page, use the Docusaurus site title instead of the filename
|
|
18
|
+
if (metadata.title?.toLowerCase() === 'index') {
|
|
19
|
+
return siteConfig.title;
|
|
20
|
+
}
|
|
15
21
|
return metadata.title;
|
|
16
22
|
}
|
|
17
23
|
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Head from '@docusaurus/Head';
|
|
3
3
|
import {useDoc} from '../docContext';
|
|
4
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
4
5
|
|
|
5
6
|
export default function DocItemMetadata() {
|
|
6
7
|
const {metadata} = useDoc();
|
|
7
|
-
const {
|
|
8
|
+
const {siteConfig} = useDocusaurusContext();
|
|
9
|
+
const {description} = metadata;
|
|
10
|
+
// Use the Docusaurus site title for root index pages instead of the filename
|
|
11
|
+
const title = metadata.title?.toLowerCase() === 'index'
|
|
12
|
+
? siteConfig.title
|
|
13
|
+
: metadata.title;
|
|
8
14
|
|
|
9
15
|
return (
|
|
10
16
|
<Head>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, {useState, useEffect} from 'react';
|
|
2
2
|
import '../../css/theme.scss';
|
|
3
3
|
import {SkipLink, Footer, PhaseBanner, ServiceNavigation} from '@not-govuk/simple-components';
|
|
4
4
|
import Header from '../Header';
|
|
@@ -140,7 +140,7 @@ export default function Layout(props) {
|
|
|
140
140
|
const activeSection = getActiveSection(pathname, navigation);
|
|
141
141
|
const basePath = activeSection?.href || '/';
|
|
142
142
|
const effectiveSidebar = activeSection ? getEffectiveSidebar(activeSection) : null;
|
|
143
|
-
const
|
|
143
|
+
const staticSidebarItems = effectiveSidebar
|
|
144
144
|
? resolveSidebarPaths(effectiveSidebar.items, basePath).map(item => ({
|
|
145
145
|
...item,
|
|
146
146
|
href: withBase(item.href),
|
|
@@ -150,6 +150,43 @@ export default function Layout(props) {
|
|
|
150
150
|
}))
|
|
151
151
|
: null;
|
|
152
152
|
|
|
153
|
+
// When on a sub-page of an auto-sidebar section, build the sidebar from the
|
|
154
|
+
// current page's own headings rather than the section index's headings.
|
|
155
|
+
// null = not yet scanned (SSR safe — sidebar renders only after hydration).
|
|
156
|
+
const [autoItems, setAutoItems] = useState(null);
|
|
157
|
+
const isSubPage = effectiveSidebar?._auto && pathname !== basePath;
|
|
158
|
+
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (!isSubPage) {
|
|
161
|
+
setAutoItems(null);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Read h2/h3 elements from the article rendered in main content.
|
|
165
|
+
const article = document.querySelector('#main-content article, #main-content .markdown, #main-content');
|
|
166
|
+
if (!article) return;
|
|
167
|
+
const headings = Array.from(article.querySelectorAll('h2, h3'));
|
|
168
|
+
const items = [];
|
|
169
|
+
let currentH2 = null;
|
|
170
|
+
for (const el of headings) {
|
|
171
|
+
const id = el.id;
|
|
172
|
+
if (!id) continue;
|
|
173
|
+
const text = el.textContent?.trim() ?? '';
|
|
174
|
+
const href = withBase(`${pathname}#${id}`);
|
|
175
|
+
if (el.tagName === 'H2') {
|
|
176
|
+
currentH2 = {text, href, items: []};
|
|
177
|
+
items.push(currentH2);
|
|
178
|
+
} else if (el.tagName === 'H3' && currentH2) {
|
|
179
|
+
currentH2.items.push({text, href});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
setAutoItems(items.length > 0 ? items : []);
|
|
183
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
184
|
+
}, [pathname]);
|
|
185
|
+
|
|
186
|
+
const sidebarItems = isSubPage
|
|
187
|
+
? (autoItems && autoItems.length > 0 ? autoItems : null)
|
|
188
|
+
: staticSidebarItems;
|
|
189
|
+
|
|
153
190
|
// Convert navigation to service navigation format (Level 1 only)
|
|
154
191
|
const serviceNavItems = navigation.map(item => ({
|
|
155
192
|
href: withBase(item.href),
|