@defra/docusaurus-theme-govuk 0.0.9-alpha → 0.0.11-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)`
@@ -363,7 +380,7 @@ module.exports = function themeGovuk(context, options) {
363
380
  path.resolve(__dirname, 'node_modules'),
364
381
  ],
365
382
  quietDeps: true,
366
- silenceDeprecations: ['import', 'if-function'],
383
+ silenceDeprecations: ['import'],
367
384
  },
368
385
  },
369
386
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/docusaurus-theme-govuk",
3
- "version": "0.0.9-alpha",
3
+ "version": "0.0.11-alpha",
4
4
  "description": "A Docusaurus theme implementing the GOV.UK Design System for consistent, accessible documentation sites",
5
5
  "main": "index.js",
6
6
  "license": "MIT",
@@ -17,3 +17,10 @@
17
17
  .container {
18
18
  max-width: 100%;
19
19
  }
20
+
21
+ /* Prevent images from overflowing the content area */
22
+ .markdown img,
23
+ article img {
24
+ max-width: 100%;
25
+ height: auto;
26
+ }
@@ -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 sidebarItems = effectiveSidebar
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),