Skip to content

Commit c9b01b5

Browse files
authored
fix: numerous minor improvements and fixes for downloads page (#7368)
* fix: numerous minor improvements and fixes for downloads page * chore: little cleanup for the hook * chore: fix tests
1 parent 53591f9 commit c9b01b5

File tree

9 files changed

+72
-150
lines changed

9 files changed

+72
-150
lines changed

apps/site/components/Common/AlertBox/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const AlertBox: FC<AlertBoxProps> = ({
1717
}) => (
1818
<div className={classNames(styles.alertBox, styles[level], styles[size])}>
1919
<span className={styles.title}>{title}</span>
20-
{children}
20+
<span>{children}</span>
2121
</div>
2222
);
2323

apps/site/components/Downloads/Release/OperatingSystemDropdown.tsx

+16-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Select from '@/components/Common/Select';
88
import { useClientContext } from '@/hooks';
99
import { ReleaseContext } from '@/providers/releaseProvider';
1010
import type { UserOS } from '@/types/userOS';
11-
import { OPERATING_SYSTEMS, parseCompat } from '@/util/downloadUtils';
11+
import { nextItem, OPERATING_SYSTEMS, parseCompat } from '@/util/downloadUtils';
1212

1313
type OperatingSystemDropdownProps = { exclude?: Array<UserOS> };
1414

@@ -30,9 +30,22 @@ const OperatingSystemDropdown: FC<OperatingSystemDropdownProps> = () => {
3030
// We parse the compatibility of the dropdown items
3131
const parsedOperatingSystems = useMemo(
3232
() => parseCompat(OPERATING_SYSTEMS, release),
33-
// We only want to react on the change of the Install Method
33+
// We only want to react on the change of the Install Method and Version
3434
// eslint-disable-next-line react-hooks/exhaustive-deps
35-
[release.installMethod, release.os]
35+
[release.installMethod, release.version]
36+
);
37+
38+
// We set the OS to the next available OS when the current
39+
// one is not valid anymore due to Version changes
40+
useEffect(
41+
() => {
42+
if (release.os !== 'LOADING') {
43+
release.setOS(nextItem(release.os, parsedOperatingSystems));
44+
}
45+
},
46+
// We only want to react on the change of the Version, Install Method and OS
47+
// eslint-disable-next-line react-hooks/exhaustive-deps
48+
[release.installMethod, release.version, release.os]
3649
);
3750

3851
return (

apps/site/components/Downloads/Release/ReleaseCodeBox.tsx

+26-2
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,40 @@ const ReleaseCodeBox: FC = () => {
9696

9797
return (
9898
<div className="mb-6 mt-4 flex flex-col gap-2">
99+
<noscript>
100+
<AlertBox
101+
title={t('components.common.alertBox.warning')}
102+
level="warning"
103+
size="small"
104+
>
105+
{t.rich('layouts.download.codeBox.noScriptDetected', {
106+
link: text => (
107+
<Link href="/about/previous-releases#looking-for-latest-release-of-a-version-branch">
108+
<b>{text}</b>
109+
</Link>
110+
),
111+
})}
112+
</AlertBox>
113+
</noscript>
114+
99115
{release.status === 'End-of-life' && (
100-
<AlertBox title="Warning" level="warning" size="small">
116+
<AlertBox
117+
title={t('components.common.alertBox.warning')}
118+
level="warning"
119+
size="small"
120+
>
101121
{t.rich('layouts.download.codeBox.unsupportedVersionWarning', {
102122
link: text => <Link href="/about/previous-releases/">{text}</Link>,
103123
})}
104124
</AlertBox>
105125
)}
106126

107127
{!currentPlatform || currentPlatform.recommended || (
108-
<AlertBox title="Info" level="info" size="small">
128+
<AlertBox
129+
title={t('components.common.alertBox.info')}
130+
level="info"
131+
size="small"
132+
>
109133
{t('layouts.download.codeBox.communityPlatformInfo')}
110134
</AlertBox>
111135
)}

apps/site/hooks/react-client/__tests__/useMediaQuery.test.mjs

+9-28
Original file line numberDiff line numberDiff line change
@@ -3,75 +3,56 @@ import { renderHook } from '@testing-library/react';
33
import useMediaQuery from '@/hooks/react-client/useMediaQuery';
44

55
describe('useMediaQuery', () => {
6-
it('should check for matchMedia support', () => {
6+
it('should return undefined initially', () => {
77
const { result } = renderHook(() => useMediaQuery('media-query-mock'));
8-
9-
expect(result.current).toBe(undefined);
8+
expect(result.current).toBe(false);
109
});
1110

1211
it('should return true for matched query', () => {
1312
Object.defineProperty(window, 'matchMedia', {
1413
writable: true,
15-
value: () => ({
14+
value: query => ({
1615
matches: true,
16+
media: query,
1717
addEventListener: jest.fn(),
1818
removeEventListener: jest.fn(),
1919
}),
2020
});
2121

2222
const { result } = renderHook(() => useMediaQuery('media-query-mock'));
23-
2423
expect(result.current).toBe(true);
2524
});
2625

2726
it('should return false for not-matched query', () => {
2827
Object.defineProperty(window, 'matchMedia', {
2928
writable: true,
30-
value: () => ({
29+
value: query => ({
3130
matches: false,
31+
media: query,
3232
addEventListener: jest.fn(),
3333
removeEventListener: jest.fn(),
3434
}),
3535
});
3636

3737
const { result } = renderHook(() => useMediaQuery('media-query-mock'));
38-
3938
expect(result.current).toBe(false);
4039
});
4140

4241
it('should subscribe for media changes', () => {
4342
const listenerMock = jest.fn().mockImplementation((_, handler) => {
44-
handler();
43+
handler({ matches: false });
4544
});
4645

4746
Object.defineProperty(window, 'matchMedia', {
4847
writable: true,
49-
value: () => ({
48+
value: query => ({
5049
matches: false,
50+
media: query,
5151
addEventListener: listenerMock,
5252
removeEventListener: jest.fn(),
5353
}),
5454
});
5555

56-
renderHook(() => useMediaQuery('media-query-mock'));
57-
58-
expect(listenerMock).toHaveBeenCalledTimes(1);
59-
});
60-
61-
it("should support MediaQueryList's old event listeners", () => {
62-
const listenerMock = jest.fn().mockImplementation(handler => {
63-
handler();
64-
});
65-
66-
Object.defineProperty(window, 'matchMedia', {
67-
writable: true,
68-
value: () => ({
69-
matches: false,
70-
addListener: listenerMock,
71-
removeListener: jest.fn(),
72-
}),
73-
});
74-
7556
renderHook(() => useMediaQuery('media-query-mock'));
7657
expect(listenerMock).toHaveBeenCalledTimes(1);
7758
});

apps/site/hooks/react-client/useMediaQuery.ts

+13-29
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,24 @@
22

33
import { useState, useEffect } from 'react';
44

5-
const mediaQueryChangeSubscribe = (mq: MediaQueryList, handler: () => void) => {
6-
if (mq.addEventListener) {
7-
mq.addEventListener('change', handler);
8-
} else {
9-
mq.addListener(handler);
10-
}
11-
};
12-
13-
const mediaQueryChangeUnsubscribe = (
14-
mq: MediaQueryList,
15-
handler: () => void
16-
) => {
17-
if (mq.removeEventListener) {
18-
mq.removeEventListener('change', handler);
19-
} else {
20-
mq.removeListener(handler);
21-
}
22-
};
23-
24-
const useMediaQuery = (query: string): boolean | undefined => {
25-
const [matches, setMatches] = useState<boolean>();
5+
const useMediaQuery = (query: string) => {
6+
const [matches, setMatches] = useState(false);
267

278
useEffect(() => {
28-
if (typeof window?.matchMedia === 'function') {
29-
const mq = window.matchMedia(query);
30-
setMatches(mq.matches);
9+
const { matches, addEventListener, removeEventListener } =
10+
window.matchMedia?.(query) ?? {
11+
matches: false,
12+
addEventListener: () => {},
13+
removeEventListener: () => {},
14+
};
15+
16+
setMatches(matches);
3117

32-
const handler = (): void => setMatches(mq.matches);
33-
mediaQueryChangeSubscribe(mq, handler);
18+
const handler = (event: MediaQueryListEvent) => setMatches(event.matches);
3419

35-
return (): void => mediaQueryChangeUnsubscribe(mq, handler);
36-
}
20+
addEventListener('change', handler);
3721

38-
return undefined;
22+
return () => removeEventListener('change', handler);
3923
}, [query]);
4024

4125
return matches;

apps/site/navigation.json

-40
Original file line numberDiff line numberDiff line change
@@ -380,45 +380,5 @@
380380
}
381381
}
382382
}
383-
},
384-
"download": {
385-
"items": {
386-
"shaSums": {
387-
"link": "https://nodejs.org/dist/{nodeVersion}/SHASUMS256.txt.asc",
388-
"label": "components.downloadList.links.shaSums.title"
389-
},
390-
"allDownloads": {
391-
"link": "https://nodejs.org/dist/{nodeVersion}/",
392-
"label": "components.downloadList.links.allDownloads"
393-
},
394-
"packageManager": {
395-
"link": "/download/package-manager",
396-
"label": "components.downloadList.links.packageManager"
397-
},
398-
"previousReleases": {
399-
"link": "/about/previous-releases",
400-
"label": "components.downloadList.links.previousReleases"
401-
},
402-
"nightlyReleases": {
403-
"link": "https://nodejs.org/download/nightly/",
404-
"label": "components.downloadList.links.nightlyReleases"
405-
},
406-
"unofficialBuilds": {
407-
"link": "https://unofficial-builds.nodejs.org/download/",
408-
"label": "components.downloadList.links.unofficialBuilds"
409-
},
410-
"buildingFromSource": {
411-
"link": "https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms",
412-
"label": "components.downloadList.links.buildingFromSource"
413-
},
414-
"installingOnLinux": {
415-
"link": "https://github.com/nodejs/help/wiki/Installation",
416-
"label": "components.downloadList.links.installingOnLinux"
417-
},
418-
"installingOnWsl": {
419-
"link": "https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms",
420-
"label": "components.downloadList.links.installingOnWsl"
421-
}
422-
}
423383
}
424384
}

apps/site/pages/es/search.mdx

-6
This file was deleted.

apps/site/util/downloadUtils.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export const OPERATING_SYSTEMS: Array<DownloadDropdownItem<UserOS>> = [
144144
{
145145
label: OperatingSystemLabel.AIX,
146146
value: 'AIX',
147-
compatibility: { installMethod: [''] },
147+
compatibility: { installMethod: [''], semver: ['>= 6.7.0'] },
148148
iconImage: <OSIcons.AIX width={16} height={16} />,
149149
},
150150
];

packages/i18n/locales/en.json

+6-40
Original file line numberDiff line numberDiff line change
@@ -136,22 +136,6 @@
136136
}
137137
}
138138
},
139-
"downloadList": {
140-
"links": {
141-
"previousReleases": "Node.js Releases",
142-
"packageManager": "Installing Node.js via package manager",
143-
"shaSums": {
144-
"title": "Signed SHASUMS for release files",
145-
"howToVerify": " (How to verify)"
146-
},
147-
"allDownloads": "All download options",
148-
"nightlyReleases": "Nightly builds",
149-
"unofficialBuilds": "Unofficial builds",
150-
"buildingFromSource": "Building Node.js from source on supported platforms",
151-
"installingOnLinux": "Installing Node.js via binary archive",
152-
"installingOnWsl": "Install on Windows Subsystem for Linux (WSL)"
153-
}
154-
},
155139
"downloadReleasesTable": {
156140
"changelog": "Changelog",
157141
"releases": "Releases",
@@ -162,6 +146,11 @@
162146
"previous": "Previous"
163147
},
164148
"common": {
149+
"alertBox": {
150+
"info": "Info",
151+
"warning": "Warning",
152+
"danger": "Danger"
153+
},
165154
"breadcrumbs": {
166155
"navigateToHome": "Navigate to Home"
167156
},
@@ -202,32 +191,9 @@
202191
"viewAs": "View as",
203192
"tableOfContents": "Table of Contents"
204193
},
205-
"downloads": {
206-
"changelogModal": {
207-
"startContributing": "Start Contributing"
208-
}
209-
},
210194
"search": {
211195
"searchBox": {
212196
"placeholder": "Start typing..."
213-
},
214-
"seeAll": {
215-
"text": "See all {count} results"
216-
},
217-
"searchError": {
218-
"text": "An error occurred while searching. Please try again later."
219-
},
220-
"poweredBy": {
221-
"text": "Powered by"
222-
},
223-
"noResults": {
224-
"text": "No results found for \"{query}\"."
225-
},
226-
"emptyState": {
227-
"text": "Search something..."
228-
},
229-
"searchPage": {
230-
"title": "You're searching: {query}"
231197
}
232198
},
233199
"blog": {
@@ -278,7 +244,6 @@
278244
"backToHome": "Back to Home"
279245
},
280246
"download": {
281-
"selectCategory": "Categories",
282247
"buttons": {
283248
"installer": "{os} Installer (.{extension})",
284249
"binary": "Standalone Binary (.{extension})"
@@ -299,6 +264,7 @@
299264
"unsupportedVersionWarning": "This version is out of maintenance. Please use a currently supported version. <link>Understand EOL support.</link>",
300265
"communityPlatformInfo": "Installation methods that involve community software are supported by the teams maintaining that software.",
301266
"externalSupportInfo": "If you encounter any issues please visit <link>{platform}'s website</link>",
267+
"noScriptDetected": "This page requires JavaScript. You can download Node.js without JavaScript by visiting the <link>releases page</link> directly.",
302268
"platformInfo": {
303269
"default": "{platform} and their installation scripts are not maintained by the Node.js project.",
304270
"nvm": "\"nvm\" is a cross-platform Node.js version manager.",

0 commit comments

Comments
 (0)