@f5-sales-demo/docs-theme 4.13.5 → 4.13.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@f5-sales-demo/docs-theme",
3
- "version": "4.13.5",
3
+ "version": "4.13.7",
4
4
  "description": "F5 Distributed Cloud branded Starlight documentation theme",
5
5
  "type": "module",
6
6
  "engines": {
@@ -64,7 +64,13 @@ describe('buildSubcategorySidebar without subcategories', () => {
64
64
  label: 'Reference',
65
65
  collapsed: true,
66
66
  translations: expect.any(Object),
67
- items: [{ label: 'Overview', slug: 'reference', translations: expect.any(Object) }],
67
+ items: [
68
+ {
69
+ label: 'Overview',
70
+ slug: 'reference',
71
+ translations: expect.any(Object),
72
+ },
73
+ ],
68
74
  },
69
75
  {
70
76
  label: 'Demo',
@@ -76,12 +82,20 @@ describe('buildSubcategorySidebar without subcategories', () => {
76
82
  collapsed: true,
77
83
  translations: expect.any(Object),
78
84
  items: [
79
- { label: 'Overview', slug: 'demo/troubleshooting', translations: expect.any(Object) },
85
+ {
86
+ label: 'Overview',
87
+ slug: 'demo/troubleshooting',
88
+ translations: expect.any(Object),
89
+ },
80
90
  {
81
91
  label: 'BGP',
82
92
  collapsed: true,
83
93
  items: [
84
- { label: 'Overview', slug: 'demo/troubleshooting/bgp', translations: expect.any(Object) },
94
+ {
95
+ label: 'Overview',
96
+ slug: 'demo/troubleshooting/bgp',
97
+ translations: expect.any(Object),
98
+ },
85
99
  { slug: 'demo/troubleshooting/bgp/routes' },
86
100
  ],
87
101
  },
@@ -111,7 +125,11 @@ describe('buildSubcategorySidebar without subcategories', () => {
111
125
  collapsed: true,
112
126
  translations: expect.any(Object),
113
127
  items: [
114
- { label: 'Overview', slug: 'guides', translations: expect.any(Object) },
128
+ {
129
+ label: 'Overview',
130
+ slug: 'guides',
131
+ translations: expect.any(Object),
132
+ },
115
133
  { slug: 'guides/a-first' },
116
134
  { slug: 'guides/z-last' },
117
135
  ],
@@ -132,7 +150,7 @@ describe('authored sidebar metadata', () => {
132
150
  return buildSubcategorySidebar(root);
133
151
  }
134
152
 
135
- it('uses authored root and nested index labels without Overview translations', async () => {
153
+ it('keeps the directory title independent of authored landing labels', async () => {
136
154
  const sidebar = await fixture({
137
155
  'index.mdx': 'sidebar:\n label: Home\n order: 0',
138
156
  'plugins/index.mdx': 'sidebar:\n label: Plugin catalog\n order: 1',
@@ -141,7 +159,7 @@ describe('authored sidebar metadata', () => {
141
159
  expect(sidebar).toEqual([
142
160
  { label: 'Home', link: '/' },
143
161
  {
144
- label: 'Plugin catalog',
162
+ label: 'Article title',
145
163
  collapsed: true,
146
164
  items: [
147
165
  { label: 'Plugin catalog', slug: 'plugins' },
@@ -163,10 +181,15 @@ describe('authored sidebar metadata', () => {
163
181
  });
164
182
  expect(sidebar).toEqual([
165
183
  {
166
- label: 'Plugins',
184
+ label: 'Article title',
167
185
  collapsed: true,
168
- translations: expect.any(Object),
169
- items: [{ label: 'Article title', collapsed: true, items: [{ slug: 'plugins/deep/visible' }] }],
186
+ items: [
187
+ {
188
+ label: 'Article title',
189
+ collapsed: true,
190
+ items: [{ slug: 'plugins/deep/visible' }],
191
+ },
192
+ ],
170
193
  },
171
194
  ]);
172
195
  });
@@ -191,7 +214,69 @@ describe('authored sidebar metadata', () => {
191
214
  'index.mdx': 'sidebar:\n label: " "\n hidden: "true"',
192
215
  'page.mdx': 'sidebar:\n label: " "\n hidden: false',
193
216
  });
194
- expect(sidebar?.[0]).toMatchObject({ label: 'Overview', link: '/', translations: expect.any(Object) });
217
+ expect(sidebar?.[0]).toMatchObject({
218
+ label: 'Overview',
219
+ link: '/',
220
+ translations: expect.any(Object),
221
+ });
195
222
  expect(sidebar?.[1]).toEqual({ slug: 'page' });
196
223
  });
197
224
  });
225
+
226
+ describe('directory titles with repeated Overview links', () => {
227
+ it('preserves distinct localized titles, ordered groups, and Overview children', async () => {
228
+ const root = await mkdtemp(path.join(tmpdir(), 'docs-theme-overview-'));
229
+ workspaces.push(root);
230
+ for (const [directory, title, order] of [
231
+ ['alpha', 'Utiliser xcsh', 20],
232
+ ['zebra', 'Bien démarrer', 10],
233
+ ] as const) {
234
+ await mkdir(path.join(root, directory), { recursive: true });
235
+ await writeFile(
236
+ path.join(root, directory, 'index.mdx'),
237
+ `---\ntitle: ${title}\nsidebar:\n label: Overview\n order: ${order}\n---\n`,
238
+ );
239
+ await writeFile(path.join(root, directory, 'child.mdx'), '---\ntitle: Child\n---\n');
240
+ await writeFile(path.join(root, directory, 'hidden.mdx'), '---\ntitle: Hidden\nsidebar:\n hidden: true\n---\n');
241
+ }
242
+ const sidebar = await buildSubcategorySidebar(root);
243
+ expect(sidebar?.map((group) => group.label)).toEqual(['Bien démarrer', 'Utiliser xcsh']);
244
+ expect(sidebar).toMatchObject([
245
+ {
246
+ label: 'Bien démarrer',
247
+ items: [{ label: 'Overview', slug: 'zebra' }, { slug: 'zebra/child' }],
248
+ },
249
+ {
250
+ label: 'Utiliser xcsh',
251
+ items: [{ label: 'Overview', slug: 'alpha' }, { slug: 'alpha/child' }],
252
+ },
253
+ ]);
254
+ });
255
+ });
256
+
257
+ it('localizes group titles from locale indexes and defaults landing links to localized Overview', async () => {
258
+ const root = await mkdtemp(path.join(tmpdir(), 'docs-theme-localized-index-'));
259
+ workspaces.push(root);
260
+ for (const [locale, title] of [
261
+ ['en', 'Use xcsh'],
262
+ ['fr', 'Utiliser xcsh'],
263
+ ] as const) {
264
+ await mkdir(path.join(root, locale, 'use'), { recursive: true });
265
+ await writeFile(path.join(root, locale, 'use/index.mdx'), `---\ntitle: ${title}\nsidebar:\n order: 20\n---\n`);
266
+ await writeFile(path.join(root, locale, 'use/child.mdx'), '---\ntitle: Child\n---\n');
267
+ }
268
+ expect(await buildSubcategorySidebar(root)).toMatchObject([
269
+ {
270
+ label: 'Use xcsh',
271
+ translations: { fr: 'Utiliser xcsh' },
272
+ items: [
273
+ {
274
+ label: 'Overview',
275
+ translations: { fr: expect.any(String) },
276
+ slug: 'use',
277
+ },
278
+ { slug: 'use/child' },
279
+ ],
280
+ },
281
+ ]);
282
+ });
@@ -186,13 +186,28 @@ function buildDirectorySidebar(dirPath: string, scanDir: string): OrderedSidebar
186
186
  items.push(...children.map((child) => child.item));
187
187
  if (items.length === 0) return undefined;
188
188
 
189
- const groupLabel = metadata.label ?? metadata.title;
190
- const translations = sidebarTranslations[groupLabel as keyof typeof sidebarTranslations];
189
+ const groupLabel = metadata.title;
190
+ const translations: Record<string, string> = {
191
+ ...sidebarTranslations[groupLabel as keyof typeof sidebarTranslations],
192
+ };
193
+ // The sidebar is scanned from English once. Localized index titles supply
194
+ // group translations without reusing the landing link's sidebar.label.
195
+ if (indexEntry && path.basename(scanDir) === 'en') {
196
+ for (const locale of fs.readdirSync(path.dirname(scanDir), {
197
+ withFileTypes: true,
198
+ })) {
199
+ if (!locale.isDirectory() || locale.name === 'en') continue;
200
+ const localizedIndex = path.join(path.dirname(scanDir), locale.name, relativeDir, indexEntry.name);
201
+ if (fs.existsSync(localizedIndex)) {
202
+ translations[locale.name] = readNavigationMetadata(localizedIndex, groupLabel).title;
203
+ }
204
+ }
205
+ }
191
206
  return {
192
207
  item: {
193
208
  label: groupLabel,
194
209
  collapsed: true,
195
- ...(translations ? { translations } : {}),
210
+ ...(Object.keys(translations).length ? { translations } : {}),
196
211
  items,
197
212
  },
198
213
  order: metadata.order,