Skip to content

Commit af65222

Browse files
authored
Merge pull request #2545 from ably/web-4327-non-js-docs-fix
[WEB-4327] Fix default language setting on non-JS templates
2 parents 21b7601 + 5d9334a commit af65222

File tree

8 files changed

+79
-120
lines changed

8 files changed

+79
-120
lines changed

src/components/LanguageButton/LanguageButton.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { languageInfo } from 'src/data/languages';
88
import { LanguageKey } from 'src/data/languages/types';
99
import { useLayoutContext } from 'src/contexts/layout-context';
1010

11-
const LanguageButton: FC<LanguageNavigationComponentProps> = ({ language, selectedLocalLanguage }) => {
11+
const LanguageButton: FC<LanguageNavigationComponentProps> = ({ language }) => {
1212
const { activePage, setLanguage } = useLayoutContext();
1313
const selectedLanguage = getTrimmedLanguage(language);
1414
const { isLanguageDefault, isPageLanguageDefault } = getLanguageDefaults(selectedLanguage, activePage.language);

src/components/Layout/LanguageSelector.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,9 @@ const LanguageSelectorOption = ({ isOption, setMenuOpen, langParam, ...props }:
7474
};
7575

7676
export const LanguageSelector = () => {
77-
const { activePage, products } = useLayoutContext();
77+
const { activePage } = useLayoutContext();
7878
const location = useLocation();
79-
const activeProduct = products[activePage.tree[0].index]?.[0];
80-
const languageVersions = languageData[activeProduct ?? 'pubsub'];
79+
const languageVersions = languageData[activePage.product ?? 'pubsub'];
8180
const [menuOpen, setMenuOpen] = useState(false);
8281
const [selectedOption, setSelectedOption] = useState<LanguageSelectorOptionData | null>(null);
8382
const selectRef = useRef<HTMLDivElement>(null);

src/components/Layout/LeftSidebar.test.tsx

+50-52
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { render, screen } from '@testing-library/react';
44
import '@testing-library/jest-dom/extend-expect';
55
import LeftSidebar from './LeftSidebar';
66
import { useLayoutContext } from 'src/contexts/layout-context';
7-
import { NavProduct } from 'src/data/nav/types';
8-
import { ProductKey } from 'src/data/types';
97

108
jest.mock('src/contexts/layout-context', () => ({
119
useLayoutContext: jest.fn(),
@@ -25,57 +23,58 @@ jest.mock('../Link', () => {
2523
return MockLink;
2624
});
2725

28-
const mockUseLayoutContext = useLayoutContext as jest.Mock;
29-
const mockUseLocation = useLocation as jest.Mock;
30-
31-
const mockProducts: [ProductKey, NavProduct][] = [
32-
[
33-
'platform',
34-
{
35-
name: 'Platform',
36-
icon: { open: 'icon-gui-chevron-up-micro', closed: 'icon-gui-chevron-down-micro' },
37-
content: [
38-
{
39-
name: 'Overview',
40-
pages: [
41-
{ name: 'Introduction', link: '/platform/intro' },
42-
{ name: 'Getting Started', link: '/platform/getting-started' },
43-
],
44-
},
45-
],
46-
api: [
47-
{
48-
name: 'API Overview',
49-
pages: [
50-
{ name: 'API Introduction', link: '/platform/api-intro' },
51-
{ name: 'API Reference', link: '/platform/api-reference' },
52-
],
53-
},
54-
],
55-
link: '/platform',
56-
showJumpLink: true,
26+
// Mock productData
27+
jest.mock('src/data', () => ({
28+
productData: {
29+
platform: {
30+
nav: {
31+
name: 'Platform',
32+
icon: { open: 'icon-gui-chevron-up-micro', closed: 'icon-gui-chevron-down-micro' },
33+
content: [
34+
{
35+
name: 'Overview',
36+
pages: [
37+
{ name: 'Introduction', link: '/platform/intro' },
38+
{ name: 'Getting Started', link: '/platform/getting-started' },
39+
],
40+
},
41+
],
42+
api: [
43+
{
44+
name: 'API Overview',
45+
pages: [
46+
{ name: 'API Introduction', link: '/platform/api-intro' },
47+
{ name: 'API Reference', link: '/platform/api-reference' },
48+
],
49+
},
50+
],
51+
link: '/platform',
52+
showJumpLink: true,
53+
},
5754
},
58-
],
59-
[
60-
'pubsub',
61-
{
62-
name: 'Pub/Sub',
63-
icon: { open: 'icon-gui-chevron-up-outline', closed: 'icon-gui-chevron-down-outline' },
64-
content: [
65-
{
66-
name: 'Overview',
67-
pages: [
68-
{ name: 'Introduction', link: '/pubsub/intro' },
69-
{ name: 'Getting Started', link: '/pubsub/getting-started' },
70-
],
71-
},
72-
],
73-
api: [],
74-
link: '/pubsub',
75-
showJumpLink: false,
55+
pubsub: {
56+
nav: {
57+
name: 'Pub/Sub',
58+
icon: { open: 'icon-gui-chevron-up-outline', closed: 'icon-gui-chevron-down-outline' },
59+
content: [
60+
{
61+
name: 'Overview',
62+
pages: [
63+
{ name: 'Introduction', link: '/pubsub/intro' },
64+
{ name: 'Getting Started', link: '/pubsub/getting-started' },
65+
],
66+
},
67+
],
68+
api: [],
69+
link: '/pubsub',
70+
showJumpLink: false,
71+
},
7672
},
77-
],
78-
];
73+
},
74+
}));
75+
76+
const mockUseLayoutContext = useLayoutContext as jest.Mock;
77+
const mockUseLocation = useLocation as jest.Mock;
7978

8079
describe('LeftSidebar', () => {
8180
beforeEach(() => {
@@ -86,7 +85,6 @@ describe('LeftSidebar', () => {
8685
{ index: 1, page: { name: 'Link 2', link: '/link-2' } },
8786
],
8887
},
89-
products: mockProducts,
9088
});
9189

9290
mockUseLocation.mockReturnValue({

src/components/Layout/LeftSidebar.tsx

+8-14
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import { useMemo, useState, useEffect, useRef } from 'react';
22
import { navigate, useLocation } from '@reach/router';
33
import cn from '@ably/ui/core/utils/cn';
44
import Accordion from '@ably/ui/core/Accordion';
5+
import { AccordionData } from '@ably/ui/core/Accordion/types';
56
import Icon from '@ably/ui/core/Icon';
7+
import { throttle } from 'lodash';
68

9+
import { productData } from 'src/data';
710
import { NavProduct, NavProductContent, NavProductPages } from 'src/data/nav/types';
811
import {
912
commonAccordionOptions,
@@ -13,11 +16,8 @@ import {
1316
sidebarAlignmentClasses,
1417
sidebarAlignmentStyles,
1518
} from './utils/nav';
16-
import { ProductKey } from 'src/data/types';
1719
import Link from '../Link';
1820
import { useLayoutContext } from 'src/contexts/layout-context';
19-
import { AccordionData } from '@ably/ui/core/Accordion/types';
20-
import { throttle } from 'lodash';
2121

2222
type ContentType = 'content' | 'api';
2323

@@ -119,12 +119,9 @@ const renderProductContent = (
119119
</div>
120120
));
121121

122-
const constructProductNavData = (
123-
activePageTree: PageTreeNode[],
124-
products: [ProductKey, NavProduct][],
125-
inHeader: boolean,
126-
): AccordionData[] => {
127-
const navData: AccordionData[] = products.map(([productKey, product], index) => {
122+
const constructProductNavData = (activePageTree: PageTreeNode[], inHeader: boolean): AccordionData[] => {
123+
const navData: AccordionData[] = Object.entries(productData).map(([productKey, productObj], index) => {
124+
const product = productObj.nav as NavProduct;
128125
const apiReferencesId = `${productKey}-api-references`;
129126

130127
return {
@@ -199,7 +196,7 @@ const constructProductNavData = (
199196
};
200197

201198
const LeftSidebar = ({ inHeader = false }: LeftSidebarProps) => {
202-
const { activePage, products } = useLayoutContext();
199+
const { activePage } = useLayoutContext();
203200
const [hasScrollbar, setHasScrollbar] = useState(false);
204201
const sidebarRef = useRef<HTMLDivElement>(null);
205202

@@ -218,10 +215,7 @@ const LeftSidebar = ({ inHeader = false }: LeftSidebarProps) => {
218215
};
219216
}, []);
220217

221-
const productNavData = useMemo(
222-
() => constructProductNavData(activePage.tree, products, inHeader),
223-
[activePage.tree, products, inHeader],
224-
);
218+
const productNavData = useMemo(() => constructProductNavData(activePage.tree, inHeader), [activePage.tree, inHeader]);
225219

226220
return (
227221
<Accordion

src/components/blocks/software/__snapshots__/Pre.test.tsx.snap

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ exports[`<Pre /> should successfully render Code elements with language 1`] = `
5555
role="log"
5656
/>
5757
<div
58-
class="ably-select__control css-bo7mvc-control"
58+
class="ably-select__control css-178amwe-control"
5959
>
6060
<div
6161
class="ably-select__value-container ably-select__value-container--has-value css-1fdsijx-ValueContainer"
@@ -185,7 +185,7 @@ exports[`<Pre /> should successfully render code elements with only Realtime la
185185
role="log"
186186
/>
187187
<div
188-
class="ably-select__control css-bo7mvc-control"
188+
class="ably-select__control css-178amwe-control"
189189
>
190190
<div
191191
class="ably-select__value-container ably-select__value-container--has-value css-1fdsijx-ValueContainer"
@@ -263,7 +263,7 @@ exports[`<Pre /> should successfully render code elements with only Rest langua
263263
</svg>
264264
</div>
265265
<div
266-
class="ml-8 leading-normal"
266+
class="ml-8 leading-tight"
267267
>
268268
You're currently viewing the
269269
<span
@@ -400,7 +400,7 @@ exports[`<Pre /> should successfully render code elements with both Rest and Rea
400400
role="log"
401401
/>
402402
<div
403-
class="ably-select__control css-bo7mvc-control"
403+
class="ably-select__control css-178amwe-control"
404404
>
405405
<div
406406
class="ably-select__value-container ably-select__value-container--has-value css-1fdsijx-ValueContainer"

src/components/blocks/wrappers/__snapshots__/LocalLanguageAlternatives.test.tsx.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ exports[`<LocalLanguageAlternatives /> renders correctly 1`] = `
4343
role="log"
4444
/>
4545
<div
46-
class="ably-select__control css-bo7mvc-control"
46+
class="ably-select__control css-178amwe-control"
4747
>
4848
<div
4949
class="ably-select__value-container ably-select__value-container--has-value css-1fdsijx-ValueContainer"

src/contexts/layout-context.tsx

+12-27
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,20 @@ import React, { createContext, PropsWithChildren, useContext, useEffect, useMemo
22
import { useLocation } from '@reach/router';
33
import { ActivePage, determineActivePage } from 'src/components/Layout/utils/nav';
44
import { productData } from 'src/data';
5-
import { NavProduct } from 'src/data/nav/types';
6-
import { ProductData, ProductKey } from 'src/data/types';
75
import { LanguageKey } from 'src/data/languages/types';
8-
import { languageData } from 'src/data/languages';
6+
import { languageData, languageInfo } from 'src/data/languages';
97

108
/**
119
* LayoutContext
1210
*
1311
* activePage - The navigation tree that leads to the current page, and a list of languages referenced on the page.
14-
* products - List of products with their navigation data.
15-
* setLanguages - Set the possible languages for the current page.
1612
* setLanguage - Set the active language for the current page.
1713
*/
1814

1915
export const DEFAULT_LANGUAGE = 'javascript';
2016

2117
const LayoutContext = createContext<{
2218
activePage: ActivePage;
23-
products: [ProductKey, NavProduct][];
24-
setLanguages: (languages: LanguageKey[]) => void;
2519
setLanguage: (language: LanguageKey) => void;
2620
}>({
2721
activePage: {
@@ -31,10 +25,6 @@ const LayoutContext = createContext<{
3125
language: DEFAULT_LANGUAGE,
3226
product: null,
3327
},
34-
products: [],
35-
setLanguages: (languages) => {
36-
console.warn('setLanguages called without a provider', languages);
37-
},
3828
setLanguage: (language) => {
3929
console.warn('setLanguage called without a provider', language);
4030
},
@@ -77,29 +67,24 @@ export const LayoutProvider: React.FC<PropsWithChildren> = ({ children }) => {
7767

7868
useEffect(() => {
7969
const params = new URLSearchParams(location.search);
70+
const langParam = params.get('lang') as LanguageKey;
8071

81-
if (params.get('lang')) {
82-
setLanguage(params.get('lang') as LanguageKey);
83-
} else if (activePage.product) {
84-
setLanguage(Object.keys(languageData[activePage.product])[0]);
85-
}
86-
}, [location.search, activePage.product]);
72+
if (langParam && Object.keys(languageInfo).includes(langParam)) {
73+
setLanguage(langParam);
74+
} else if (activePage.product && activePage.languages.length > 0) {
75+
const productLanguages = languageData[activePage.product];
76+
const defaultLanguage =
77+
Object.keys(productLanguages ?? []).filter((lang) => activePage.languages.includes(lang))[0] ??
78+
DEFAULT_LANGUAGE;
8779

88-
const products = useMemo(
89-
() =>
90-
Object.entries(productData satisfies ProductData).map((product) => [product[0], product[1].nav]) as [
91-
ProductKey,
92-
NavProduct,
93-
][],
94-
[],
95-
);
80+
setLanguage(defaultLanguage);
81+
}
82+
}, [location.search, activePage.product, activePage.languages]);
9683

9784
return (
9885
<LayoutContext.Provider
9986
value={{
10087
activePage,
101-
products,
102-
setLanguages,
10388
setLanguage,
10489
}}
10590
>

src/templates/base-template.tsx

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Script, ScriptStrategy } from 'gatsby';
2-
import { useLayoutEffect, useMemo } from 'react';
2+
import { useMemo } from 'react';
33

44
import { Head } from 'src/components/Head';
55
import Article from 'src/components/Article';
@@ -9,8 +9,6 @@ import { PathnameContext } from 'src/contexts';
99
import { AblyDocument, AblyDocumentMeta, AblyTemplateData, ProductName } from './template-data';
1010
import { useSiteMetadata } from 'src/hooks/use-site-metadata';
1111
import { getMetaTitle } from 'src/components/common/meta-title';
12-
import { useLayoutContext } from 'src/contexts/layout-context';
13-
import { LanguageKey } from 'src/data/languages/types';
1412

1513
const getMetaDataDetails = (
1614
document: AblyDocument,
@@ -31,21 +29,6 @@ const Template = ({
3129
data: { document: ablyDocument },
3230
currentProduct,
3331
}: ITemplate) => {
34-
const { setLanguages } = useLayoutContext();
35-
36-
useLayoutEffect(() => {
37-
const languagesSet = new Set<LanguageKey>();
38-
39-
document.querySelectorAll('.docs-language-navigation').forEach((element) => {
40-
const languages = element.getAttribute('data-languages');
41-
if (languages) {
42-
languages.split(',').forEach((language) => languagesSet.add(language as LanguageKey));
43-
}
44-
});
45-
46-
setLanguages(Array.from(languagesSet));
47-
}, [setLanguages]);
48-
4932
const title = getMetaDataDetails(ablyDocument, 'title') as string;
5033
const description = getMetaDataDetails(ablyDocument, 'meta_description', META_DESCRIPTION_FALLBACK) as string;
5134
const { canonicalUrl } = useSiteMetadata();

0 commit comments

Comments
 (0)