Skip to content

Commit

Permalink
fix: numerous minor improvements and fixes for downloads page (#7368)
Browse files Browse the repository at this point in the history
* fix: numerous minor improvements and fixes for downloads page

* chore: little cleanup for the hook

* chore: fix tests
  • Loading branch information
ovflowd authored Dec 28, 2024
1 parent 53591f9 commit c9b01b5
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 150 deletions.
2 changes: 1 addition & 1 deletion apps/site/components/Common/AlertBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const AlertBox: FC<AlertBoxProps> = ({
}) => (
<div className={classNames(styles.alertBox, styles[level], styles[size])}>
<span className={styles.title}>{title}</span>
{children}
<span>{children}</span>
</div>
);

Expand Down
19 changes: 16 additions & 3 deletions apps/site/components/Downloads/Release/OperatingSystemDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Select from '@/components/Common/Select';
import { useClientContext } from '@/hooks';
import { ReleaseContext } from '@/providers/releaseProvider';
import type { UserOS } from '@/types/userOS';
import { OPERATING_SYSTEMS, parseCompat } from '@/util/downloadUtils';
import { nextItem, OPERATING_SYSTEMS, parseCompat } from '@/util/downloadUtils';

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

Expand All @@ -30,9 +30,22 @@ const OperatingSystemDropdown: FC<OperatingSystemDropdownProps> = () => {
// We parse the compatibility of the dropdown items
const parsedOperatingSystems = useMemo(
() => parseCompat(OPERATING_SYSTEMS, release),
// We only want to react on the change of the Install Method
// We only want to react on the change of the Install Method and Version
// eslint-disable-next-line react-hooks/exhaustive-deps
[release.installMethod, release.os]
[release.installMethod, release.version]
);

// We set the OS to the next available OS when the current
// one is not valid anymore due to Version changes
useEffect(
() => {
if (release.os !== 'LOADING') {
release.setOS(nextItem(release.os, parsedOperatingSystems));
}
},
// We only want to react on the change of the Version, Install Method and OS
// eslint-disable-next-line react-hooks/exhaustive-deps
[release.installMethod, release.version, release.os]
);

return (
Expand Down
28 changes: 26 additions & 2 deletions apps/site/components/Downloads/Release/ReleaseCodeBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,40 @@ const ReleaseCodeBox: FC = () => {

return (
<div className="mb-6 mt-4 flex flex-col gap-2">
<noscript>
<AlertBox
title={t('components.common.alertBox.warning')}
level="warning"
size="small"
>
{t.rich('layouts.download.codeBox.noScriptDetected', {
link: text => (
<Link href="/about/previous-releases#looking-for-latest-release-of-a-version-branch">
<b>{text}</b>
</Link>
),
})}
</AlertBox>
</noscript>

{release.status === 'End-of-life' && (
<AlertBox title="Warning" level="warning" size="small">
<AlertBox
title={t('components.common.alertBox.warning')}
level="warning"
size="small"
>
{t.rich('layouts.download.codeBox.unsupportedVersionWarning', {
link: text => <Link href="/about/previous-releases/">{text}</Link>,
})}
</AlertBox>
)}

{!currentPlatform || currentPlatform.recommended || (
<AlertBox title="Info" level="info" size="small">
<AlertBox
title={t('components.common.alertBox.info')}
level="info"
size="small"
>
{t('layouts.download.codeBox.communityPlatformInfo')}
</AlertBox>
)}
Expand Down
37 changes: 9 additions & 28 deletions apps/site/hooks/react-client/__tests__/useMediaQuery.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,56 @@ import { renderHook } from '@testing-library/react';
import useMediaQuery from '@/hooks/react-client/useMediaQuery';

describe('useMediaQuery', () => {
it('should check for matchMedia support', () => {
it('should return undefined initially', () => {
const { result } = renderHook(() => useMediaQuery('media-query-mock'));

expect(result.current).toBe(undefined);
expect(result.current).toBe(false);
});

it('should return true for matched query', () => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: () => ({
value: query => ({
matches: true,
media: query,
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
}),
});

const { result } = renderHook(() => useMediaQuery('media-query-mock'));

expect(result.current).toBe(true);
});

it('should return false for not-matched query', () => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: () => ({
value: query => ({
matches: false,
media: query,
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
}),
});

const { result } = renderHook(() => useMediaQuery('media-query-mock'));

expect(result.current).toBe(false);
});

it('should subscribe for media changes', () => {
const listenerMock = jest.fn().mockImplementation((_, handler) => {
handler();
handler({ matches: false });
});

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: () => ({
value: query => ({
matches: false,
media: query,
addEventListener: listenerMock,
removeEventListener: jest.fn(),
}),
});

renderHook(() => useMediaQuery('media-query-mock'));

expect(listenerMock).toHaveBeenCalledTimes(1);
});

it("should support MediaQueryList's old event listeners", () => {
const listenerMock = jest.fn().mockImplementation(handler => {
handler();
});

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: () => ({
matches: false,
addListener: listenerMock,
removeListener: jest.fn(),
}),
});

renderHook(() => useMediaQuery('media-query-mock'));
expect(listenerMock).toHaveBeenCalledTimes(1);
});
Expand Down
42 changes: 13 additions & 29 deletions apps/site/hooks/react-client/useMediaQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,24 @@

import { useState, useEffect } from 'react';

const mediaQueryChangeSubscribe = (mq: MediaQueryList, handler: () => void) => {
if (mq.addEventListener) {
mq.addEventListener('change', handler);
} else {
mq.addListener(handler);
}
};

const mediaQueryChangeUnsubscribe = (
mq: MediaQueryList,
handler: () => void
) => {
if (mq.removeEventListener) {
mq.removeEventListener('change', handler);
} else {
mq.removeListener(handler);
}
};

const useMediaQuery = (query: string): boolean | undefined => {
const [matches, setMatches] = useState<boolean>();
const useMediaQuery = (query: string) => {
const [matches, setMatches] = useState(false);

useEffect(() => {
if (typeof window?.matchMedia === 'function') {
const mq = window.matchMedia(query);
setMatches(mq.matches);
const { matches, addEventListener, removeEventListener } =
window.matchMedia?.(query) ?? {
matches: false,
addEventListener: () => {},
removeEventListener: () => {},
};

setMatches(matches);

const handler = (): void => setMatches(mq.matches);
mediaQueryChangeSubscribe(mq, handler);
const handler = (event: MediaQueryListEvent) => setMatches(event.matches);

return (): void => mediaQueryChangeUnsubscribe(mq, handler);
}
addEventListener('change', handler);

return undefined;
return () => removeEventListener('change', handler);
}, [query]);

return matches;
Expand Down
40 changes: 0 additions & 40 deletions apps/site/navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -380,45 +380,5 @@
}
}
}
},
"download": {
"items": {
"shaSums": {
"link": "https://nodejs.org/dist/{nodeVersion}/SHASUMS256.txt.asc",
"label": "components.downloadList.links.shaSums.title"
},
"allDownloads": {
"link": "https://nodejs.org/dist/{nodeVersion}/",
"label": "components.downloadList.links.allDownloads"
},
"packageManager": {
"link": "/download/package-manager",
"label": "components.downloadList.links.packageManager"
},
"previousReleases": {
"link": "/about/previous-releases",
"label": "components.downloadList.links.previousReleases"
},
"nightlyReleases": {
"link": "https://nodejs.org/download/nightly/",
"label": "components.downloadList.links.nightlyReleases"
},
"unofficialBuilds": {
"link": "https://unofficial-builds.nodejs.org/download/",
"label": "components.downloadList.links.unofficialBuilds"
},
"buildingFromSource": {
"link": "https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms",
"label": "components.downloadList.links.buildingFromSource"
},
"installingOnLinux": {
"link": "https://github.com/nodejs/help/wiki/Installation",
"label": "components.downloadList.links.installingOnLinux"
},
"installingOnWsl": {
"link": "https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms",
"label": "components.downloadList.links.installingOnWsl"
}
}
}
}
6 changes: 0 additions & 6 deletions apps/site/pages/es/search.mdx

This file was deleted.

2 changes: 1 addition & 1 deletion apps/site/util/downloadUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export const OPERATING_SYSTEMS: Array<DownloadDropdownItem<UserOS>> = [
{
label: OperatingSystemLabel.AIX,
value: 'AIX',
compatibility: { installMethod: [''] },
compatibility: { installMethod: [''], semver: ['>= 6.7.0'] },
iconImage: <OSIcons.AIX width={16} height={16} />,
},
];
Expand Down
46 changes: 6 additions & 40 deletions packages/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,22 +136,6 @@
}
}
},
"downloadList": {
"links": {
"previousReleases": "Node.js Releases",
"packageManager": "Installing Node.js via package manager",
"shaSums": {
"title": "Signed SHASUMS for release files",
"howToVerify": " (How to verify)"
},
"allDownloads": "All download options",
"nightlyReleases": "Nightly builds",
"unofficialBuilds": "Unofficial builds",
"buildingFromSource": "Building Node.js from source on supported platforms",
"installingOnLinux": "Installing Node.js via binary archive",
"installingOnWsl": "Install on Windows Subsystem for Linux (WSL)"
}
},
"downloadReleasesTable": {
"changelog": "Changelog",
"releases": "Releases",
Expand All @@ -162,6 +146,11 @@
"previous": "Previous"
},
"common": {
"alertBox": {
"info": "Info",
"warning": "Warning",
"danger": "Danger"
},
"breadcrumbs": {
"navigateToHome": "Navigate to Home"
},
Expand Down Expand Up @@ -202,32 +191,9 @@
"viewAs": "View as",
"tableOfContents": "Table of Contents"
},
"downloads": {
"changelogModal": {
"startContributing": "Start Contributing"
}
},
"search": {
"searchBox": {
"placeholder": "Start typing..."
},
"seeAll": {
"text": "See all {count} results"
},
"searchError": {
"text": "An error occurred while searching. Please try again later."
},
"poweredBy": {
"text": "Powered by"
},
"noResults": {
"text": "No results found for \"{query}\"."
},
"emptyState": {
"text": "Search something..."
},
"searchPage": {
"title": "You're searching: {query}"
}
},
"blog": {
Expand Down Expand Up @@ -278,7 +244,6 @@
"backToHome": "Back to Home"
},
"download": {
"selectCategory": "Categories",
"buttons": {
"installer": "{os} Installer (.{extension})",
"binary": "Standalone Binary (.{extension})"
Expand All @@ -299,6 +264,7 @@
"unsupportedVersionWarning": "This version is out of maintenance. Please use a currently supported version. <link>Understand EOL support.</link>",
"communityPlatformInfo": "Installation methods that involve community software are supported by the teams maintaining that software.",
"externalSupportInfo": "If you encounter any issues please visit <link>{platform}'s website</link>",
"noScriptDetected": "This page requires JavaScript. You can download Node.js without JavaScript by visiting the <link>releases page</link> directly.",
"platformInfo": {
"default": "{platform} and their installation scripts are not maintained by the Node.js project.",
"nvm": "\"nvm\" is a cross-platform Node.js version manager.",
Expand Down

0 comments on commit c9b01b5

Please sign in to comment.