From abe2da4961d5cf3154c9af3248a79e0d7f92eade Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Wed, 25 Dec 2024 02:28:18 +0000 Subject: [PATCH] feat: introduced new downloads page chore: removed all translated (old) downloads page (forcing re-translation) fix: fix build and extension extraction chore: just update todo text Apply suggestions from code review Co-authored-by: Geoffrey Booth Signed-off-by: Claudio W fix: fixed unit tests chore: unnecessary memoization of reqs chore: some minor code review changes feat: code review and iteration on logic chore: improvements for docker chore: more improvements for texts and sizes chore: minor design updates chore: numerous improvements and fixes chore: some typo fixes feat: bug fixes, improved types, handle unknown scenarios and fallback chore: always use corepack to enable pnpm chore: util will always return string, but `parseNumericBitness` ensures number is set chore: improved types chore: random changed file chore: some code reviews and bug fixes chore: not an external link --- .../blog-data/[category]/[page]/route.ts | 7 +- .../Common/AlertBox/index.module.css | 5 +- .../components/Common/BlogPostCard/index.tsx | 3 +- .../components/Common/Button/index.module.css | 1 + .../components/Common/Select/index.module.css | 10 +- .../Common/Select/index.stories.tsx | 13 +- apps/site/components/Common/Select/index.tsx | 52 ++- .../site/components/Common/Skeleton/index.tsx | 11 +- .../components/Containers/MetaBar/index.tsx | 4 +- .../Downloads/Release/BitnessDropdown.tsx | 116 ++--- .../Downloads/Release/DownloadButton.tsx | 60 ++- .../components/Downloads/Release/NpmLink.tsx | 21 - .../Release/OperatingSystemDropdown.tsx | 73 ++-- .../Release/PackageManagerDropdown.tsx | 53 +++ .../Downloads/Release/PlatformDropdown.tsx | 120 +++--- .../Downloads/Release/ReleaseCodeBox.tsx | 114 +++-- .../Downloads/Release/ReleaseStatus.tsx | 16 - .../Downloads/Release/ReleaseVersion.tsx | 16 - .../Downloads/Release/SourceButton.tsx | 30 -- .../Release/VerifyingBinariesLink.tsx | 11 - .../Downloads/Release/VersionDropdown.tsx | 7 +- .../{Platform => OperatingSystem}/AIX.tsx | 0 .../{Platform => OperatingSystem}/Apple.tsx | 0 .../{Platform => OperatingSystem}/Linux.tsx | 0 .../Microsoft.tsx | 0 .../components/Icons/OperatingSystem/index.ts | 6 + .../components/Icons/PackageManager/index.ts | 5 + .../components/Icons/Platform/Generic.tsx | 22 - apps/site/components/Icons/Platform/index.ts | 7 + apps/site/components/JSX/CodeBox/index.tsx | 3 +- .../__design__/package-manager.stories.tsx | 10 +- .../__design__/platform-logos.stories.tsx | 28 +- apps/site/components/withBlogCrossLinks.tsx | 3 +- .../components/withDownloadCategories.tsx | 79 ---- apps/site/components/withDownloadSection.tsx | 41 ++ apps/site/global.d.ts | 29 ++ .../hooks/react-generic/useSiteNavigation.ts | 2 +- apps/site/layouts/Blog.tsx | 8 +- apps/site/layouts/Download.tsx | 15 +- apps/site/next-data/blogData.ts | 7 +- apps/site/next-data/providers/blogData.ts | 42 +- apps/site/next-env.d.ts | 2 +- apps/site/next.constants.mjs | 10 - apps/site/next.jsx.compiler.mjs | 2 +- apps/site/next.mdx.use.client.mjs | 40 ++ apps/site/next.mdx.use.mjs | 49 --- apps/site/package.json | 8 +- apps/site/pages/en/download/current.mdx | 36 ++ apps/site/pages/en/download/index.mdx | 36 ++ .../en/download/package-manager/current.mdx | 24 -- .../en/download/package-manager/index.mdx | 24 -- .../en/download/prebuilt-binaries/current.mdx | 24 -- .../en/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../en/download/prebuilt-installer/index.mdx | 26 -- .../pages/en/download/source-code/current.mdx | 24 -- .../pages/en/download/source-code/index.mdx | 24 -- .../pages/es/download/package-manager/all.md | 393 ----------------- .../es/download/package-manager/current.mdx | 24 -- .../es/download/package-manager/index.mdx | 24 -- .../es/download/prebuilt-binaries/current.mdx | 24 -- .../es/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../es/download/prebuilt-installer/index.mdx | 26 -- .../pages/es/download/source-code/current.mdx | 24 -- .../pages/es/download/source-code/index.mdx | 24 -- .../pages/fa/download/package-manager/all.md | 392 ----------------- .../fa/download/package-manager/current.mdx | 24 -- .../fa/download/package-manager/index.mdx | 24 -- .../fa/download/prebuilt-binaries/current.mdx | 23 - .../fa/download/prebuilt-binaries/index.mdx | 23 - .../download/prebuilt-installer/current.mdx | 26 -- .../fa/download/prebuilt-installer/index.mdx | 26 -- .../pages/fa/download/source-code/current.mdx | 24 -- .../pages/fa/download/source-code/index.mdx | 24 -- .../pages/fr/download/package-manager/all.md | 400 ------------------ .../fr/download/package-manager/current.mdx | 24 -- .../fr/download/package-manager/index.mdx | 24 -- .../fr/download/prebuilt-binaries/current.mdx | 24 -- .../fr/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../fr/download/prebuilt-installer/index.mdx | 26 -- .../pages/fr/download/source-code/current.mdx | 24 -- .../pages/fr/download/source-code/index.mdx | 24 -- .../pages/id/download/package-manager/all.md | 395 ----------------- .../id/download/package-manager/current.mdx | 24 -- .../id/download/package-manager/index.mdx | 24 -- .../id/download/prebuilt-binaries/current.mdx | 24 -- .../id/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../id/download/prebuilt-installer/index.mdx | 26 -- .../pages/id/download/source-code/current.mdx | 24 -- .../pages/id/download/source-code/index.mdx | 24 -- .../ja/download/package-manager/current.mdx | 29 -- .../ja/download/package-manager/index.mdx | 29 -- .../ja/download/prebuilt-binaries/current.mdx | 28 -- .../ja/download/prebuilt-binaries/index.mdx | 23 - .../download/prebuilt-installer/current.mdx | 30 -- .../ja/download/prebuilt-installer/index.mdx | 30 -- .../pages/ja/download/source-code/current.mdx | 29 -- .../pages/ja/download/source-code/index.mdx | 29 -- .../pages/ko/download/package-manager/all.md | 390 ----------------- .../ko/download/package-manager/current.mdx | 25 -- .../ko/download/package-manager/index.mdx | 25 -- .../ko/download/prebuilt-binaries/current.mdx | 24 -- .../ko/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../ko/download/prebuilt-installer/index.mdx | 26 -- .../pages/ko/download/source-code/current.mdx | 25 -- .../pages/ko/download/source-code/index.mdx | 25 -- .../pages/pt/download/package-manager/all.md | 387 ----------------- .../pt/download/package-manager/current.mdx | 24 -- .../pt/download/package-manager/index.mdx | 24 -- .../pt/download/prebuilt-binaries/current.mdx | 24 -- .../pt/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../pt/download/prebuilt-installer/index.mdx | 26 -- .../pages/pt/download/source-code/current.mdx | 24 -- .../pages/pt/download/source-code/index.mdx | 24 -- .../pages/tr/download/package-manager/all.md | 398 ----------------- .../tr/download/package-manager/current.mdx | 24 -- .../tr/download/package-manager/index.mdx | 25 -- .../tr/download/prebuilt-binaries/current.mdx | 24 -- .../tr/download/prebuilt-binaries/index.mdx | 26 -- .../download/prebuilt-installer/current.mdx | 26 -- .../tr/download/prebuilt-installer/index.mdx | 26 -- .../pages/tr/download/source-code/current.mdx | 24 -- .../pages/tr/download/source-code/index.mdx | 24 -- .../pages/uk/download/package-manager/all.md | 392 ----------------- .../uk/download/package-manager/current.mdx | 24 -- .../uk/download/package-manager/index.mdx | 24 -- .../uk/download/prebuilt-binaries/current.mdx | 24 -- .../uk/download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../uk/download/prebuilt-installer/index.mdx | 26 -- .../pages/uk/download/source-code/current.mdx | 24 -- .../pages/uk/download/source-code/index.mdx | 24 -- .../zh-cn/download/package-manager/all.md | 389 ----------------- .../download/package-manager/current.mdx | 24 -- .../zh-cn/download/package-manager/index.mdx | 24 -- .../download/prebuilt-binaries/current.mdx | 24 -- .../download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../download/prebuilt-installer/index.mdx | 26 -- .../zh-cn/download/source-code/current.mdx | 24 -- .../zh-cn/download/source-code/index.mdx | 24 -- .../zh-tw/download/package-manager/all.md | 391 ----------------- .../download/package-manager/current.mdx | 24 -- .../zh-tw/download/package-manager/index.mdx | 24 -- .../download/prebuilt-binaries/current.mdx | 24 -- .../download/prebuilt-binaries/index.mdx | 24 -- .../download/prebuilt-installer/current.mdx | 26 -- .../download/prebuilt-installer/index.mdx | 26 -- .../zh-tw/download/source-code/current.mdx | 24 -- .../zh-tw/download/source-code/index.mdx | 24 -- apps/site/providers/releaseProvider.tsx | 122 +++--- apps/site/redirects.json | 38 +- apps/site/reducers/releaseReducer.ts | 45 ++ apps/site/snippets/en/download/brew.bash | 16 +- apps/site/snippets/en/download/choco.bash | 16 +- apps/site/snippets/en/download/docker.bash | 17 +- apps/site/snippets/en/download/fnm.bash | 21 +- apps/site/snippets/en/download/npm.bash | 2 + apps/site/snippets/en/download/nvm.bash | 11 +- apps/site/snippets/en/download/pnpm.bash | 5 + apps/site/snippets/en/download/yarn.bash | 5 + apps/site/tsconfig.json | 1 + apps/site/types/blog.ts | 5 +- apps/site/types/navigation.ts | 4 +- apps/site/types/release.ts | 30 +- .../util/__tests__/downloadUtils.test.mjs | 159 ------- .../getUserBitnessByArchitecture.test.mjs | 2 +- apps/site/util/downloadUtils.ts | 173 -------- apps/site/util/downloadUtils.tsx | 295 +++++++++++++ .../site/util/getUserBitnessByArchitecture.ts | 4 +- package-lock.json | 337 +++++++-------- packages/i18n/locales/en.json | 32 +- 177 files changed, 1327 insertions(+), 7561 deletions(-) delete mode 100644 apps/site/components/Downloads/Release/NpmLink.tsx create mode 100644 apps/site/components/Downloads/Release/PackageManagerDropdown.tsx delete mode 100644 apps/site/components/Downloads/Release/ReleaseStatus.tsx delete mode 100644 apps/site/components/Downloads/Release/ReleaseVersion.tsx delete mode 100644 apps/site/components/Downloads/Release/SourceButton.tsx delete mode 100644 apps/site/components/Downloads/Release/VerifyingBinariesLink.tsx rename apps/site/components/Icons/{Platform => OperatingSystem}/AIX.tsx (100%) rename apps/site/components/Icons/{Platform => OperatingSystem}/Apple.tsx (100%) rename apps/site/components/Icons/{Platform => OperatingSystem}/Linux.tsx (100%) rename apps/site/components/Icons/{Platform => OperatingSystem}/Microsoft.tsx (100%) create mode 100644 apps/site/components/Icons/OperatingSystem/index.ts create mode 100644 apps/site/components/Icons/PackageManager/index.ts delete mode 100644 apps/site/components/Icons/Platform/Generic.tsx create mode 100644 apps/site/components/Icons/Platform/index.ts delete mode 100644 apps/site/components/withDownloadCategories.tsx create mode 100644 apps/site/components/withDownloadSection.tsx create mode 100644 apps/site/global.d.ts create mode 100644 apps/site/pages/en/download/current.mdx create mode 100644 apps/site/pages/en/download/index.mdx delete mode 100644 apps/site/pages/en/download/package-manager/current.mdx delete mode 100644 apps/site/pages/en/download/package-manager/index.mdx delete mode 100644 apps/site/pages/en/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/en/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/en/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/en/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/en/download/source-code/current.mdx delete mode 100644 apps/site/pages/en/download/source-code/index.mdx delete mode 100644 apps/site/pages/es/download/package-manager/all.md delete mode 100644 apps/site/pages/es/download/package-manager/current.mdx delete mode 100644 apps/site/pages/es/download/package-manager/index.mdx delete mode 100644 apps/site/pages/es/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/es/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/es/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/es/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/es/download/source-code/current.mdx delete mode 100644 apps/site/pages/es/download/source-code/index.mdx delete mode 100644 apps/site/pages/fa/download/package-manager/all.md delete mode 100644 apps/site/pages/fa/download/package-manager/current.mdx delete mode 100644 apps/site/pages/fa/download/package-manager/index.mdx delete mode 100644 apps/site/pages/fa/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/fa/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/fa/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/fa/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/fa/download/source-code/current.mdx delete mode 100644 apps/site/pages/fa/download/source-code/index.mdx delete mode 100644 apps/site/pages/fr/download/package-manager/all.md delete mode 100644 apps/site/pages/fr/download/package-manager/current.mdx delete mode 100644 apps/site/pages/fr/download/package-manager/index.mdx delete mode 100644 apps/site/pages/fr/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/fr/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/fr/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/fr/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/fr/download/source-code/current.mdx delete mode 100644 apps/site/pages/fr/download/source-code/index.mdx delete mode 100644 apps/site/pages/id/download/package-manager/all.md delete mode 100644 apps/site/pages/id/download/package-manager/current.mdx delete mode 100644 apps/site/pages/id/download/package-manager/index.mdx delete mode 100644 apps/site/pages/id/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/id/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/id/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/id/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/id/download/source-code/current.mdx delete mode 100644 apps/site/pages/id/download/source-code/index.mdx delete mode 100644 apps/site/pages/ja/download/package-manager/current.mdx delete mode 100644 apps/site/pages/ja/download/package-manager/index.mdx delete mode 100644 apps/site/pages/ja/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/ja/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/ja/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/ja/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/ja/download/source-code/current.mdx delete mode 100644 apps/site/pages/ja/download/source-code/index.mdx delete mode 100644 apps/site/pages/ko/download/package-manager/all.md delete mode 100644 apps/site/pages/ko/download/package-manager/current.mdx delete mode 100644 apps/site/pages/ko/download/package-manager/index.mdx delete mode 100644 apps/site/pages/ko/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/ko/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/ko/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/ko/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/ko/download/source-code/current.mdx delete mode 100644 apps/site/pages/ko/download/source-code/index.mdx delete mode 100644 apps/site/pages/pt/download/package-manager/all.md delete mode 100644 apps/site/pages/pt/download/package-manager/current.mdx delete mode 100644 apps/site/pages/pt/download/package-manager/index.mdx delete mode 100644 apps/site/pages/pt/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/pt/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/pt/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/pt/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/pt/download/source-code/current.mdx delete mode 100644 apps/site/pages/pt/download/source-code/index.mdx delete mode 100644 apps/site/pages/tr/download/package-manager/all.md delete mode 100644 apps/site/pages/tr/download/package-manager/current.mdx delete mode 100644 apps/site/pages/tr/download/package-manager/index.mdx delete mode 100644 apps/site/pages/tr/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/tr/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/tr/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/tr/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/tr/download/source-code/current.mdx delete mode 100644 apps/site/pages/tr/download/source-code/index.mdx delete mode 100644 apps/site/pages/uk/download/package-manager/all.md delete mode 100644 apps/site/pages/uk/download/package-manager/current.mdx delete mode 100644 apps/site/pages/uk/download/package-manager/index.mdx delete mode 100644 apps/site/pages/uk/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/uk/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/uk/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/uk/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/uk/download/source-code/current.mdx delete mode 100644 apps/site/pages/uk/download/source-code/index.mdx delete mode 100644 apps/site/pages/zh-cn/download/package-manager/all.md delete mode 100644 apps/site/pages/zh-cn/download/package-manager/current.mdx delete mode 100644 apps/site/pages/zh-cn/download/package-manager/index.mdx delete mode 100644 apps/site/pages/zh-cn/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/zh-cn/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/zh-cn/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/zh-cn/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/zh-cn/download/source-code/current.mdx delete mode 100644 apps/site/pages/zh-cn/download/source-code/index.mdx delete mode 100644 apps/site/pages/zh-tw/download/package-manager/all.md delete mode 100644 apps/site/pages/zh-tw/download/package-manager/current.mdx delete mode 100644 apps/site/pages/zh-tw/download/package-manager/index.mdx delete mode 100644 apps/site/pages/zh-tw/download/prebuilt-binaries/current.mdx delete mode 100644 apps/site/pages/zh-tw/download/prebuilt-binaries/index.mdx delete mode 100644 apps/site/pages/zh-tw/download/prebuilt-installer/current.mdx delete mode 100644 apps/site/pages/zh-tw/download/prebuilt-installer/index.mdx delete mode 100644 apps/site/pages/zh-tw/download/source-code/current.mdx delete mode 100644 apps/site/pages/zh-tw/download/source-code/index.mdx create mode 100644 apps/site/reducers/releaseReducer.ts create mode 100644 apps/site/snippets/en/download/npm.bash create mode 100644 apps/site/snippets/en/download/pnpm.bash create mode 100644 apps/site/snippets/en/download/yarn.bash delete mode 100644 apps/site/util/__tests__/downloadUtils.test.mjs delete mode 100644 apps/site/util/downloadUtils.ts create mode 100644 apps/site/util/downloadUtils.tsx diff --git a/apps/site/app/[locale]/next-data/blog-data/[category]/[page]/route.ts b/apps/site/app/[locale]/next-data/blog-data/[category]/[page]/route.ts index c0061c6a366ad..ed7977b3d6252 100644 --- a/apps/site/app/[locale]/next-data/blog-data/[category]/[page]/route.ts +++ b/apps/site/app/[locale]/next-data/blog-data/[category]/[page]/route.ts @@ -3,8 +3,13 @@ import { providePaginatedBlogPosts, } from '@/next-data/providers/blogData'; import { defaultLocale } from '@/next.locales.mjs'; +import type { BlogCategory } from '@/types'; -type DynamicStaticPaths = { locale: string; category: string; page: string }; +type DynamicStaticPaths = { + locale: string; + category: BlogCategory; + page: string; +}; type StaticParams = { params: Promise }; // This is the Route Handler for the `GET` method which handles the request diff --git a/apps/site/components/Common/AlertBox/index.module.css b/apps/site/components/Common/AlertBox/index.module.css index 3714979473e5d..c3e31ae888704 100644 --- a/apps/site/components/Common/AlertBox/index.module.css +++ b/apps/site/components/Common/AlertBox/index.module.css @@ -10,9 +10,10 @@ text-white; a { - @apply font-ibm-plex-mono + @apply font-bold text-white - underline; + underline + hover:text-white; &:hover { @apply no-underline; diff --git a/apps/site/components/Common/BlogPostCard/index.tsx b/apps/site/components/Common/BlogPostCard/index.tsx index 4f8696dd20565..30815ad9ed62c 100644 --- a/apps/site/components/Common/BlogPostCard/index.tsx +++ b/apps/site/components/Common/BlogPostCard/index.tsx @@ -5,13 +5,14 @@ import FormattedTime from '@/components/Common/FormattedTime'; import Preview from '@/components/Common/Preview'; import Link from '@/components/Link'; import WithAvatarGroup from '@/components/withAvatarGroup'; +import type { BlogCategory } from '@/types'; import { mapBlogCategoryToPreviewType } from '@/util/blogUtils'; import styles from './index.module.css'; type BlogPostCardProps = { title: string; - category: string; + category: BlogCategory; description?: string; authors?: Array; date?: Date; diff --git a/apps/site/components/Common/Button/index.module.css b/apps/site/components/Common/Button/index.module.css index 4d8786bc63b14..6f2d69b8e9bef 100644 --- a/apps/site/components/Common/Button/index.module.css +++ b/apps/site/components/Common/Button/index.module.css @@ -3,6 +3,7 @@ relative inline-flex items-center + justify-center gap-2 py-2.5 text-center diff --git a/apps/site/components/Common/Select/index.module.css b/apps/site/components/Common/Select/index.module.css index 346ee8ee1ef1d..1e13248039a83 100644 --- a/apps/site/components/Common/Select/index.module.css +++ b/apps/site/components/Common/Select/index.module.css @@ -108,8 +108,14 @@ } } -.dropdown:has(.label) .text > span > span { - @apply pl-3; +.dropdown:has(.label) .text > span { + &:has(svg) > svg { + @apply ml-3; + } + + &:not(&:has(svg)) > span { + @apply ml-3; + } } .inline { diff --git a/apps/site/components/Common/Select/index.stories.tsx b/apps/site/components/Common/Select/index.stories.tsx index 59b5da23b7f48..4c24dd474aca0 100644 --- a/apps/site/components/Common/Select/index.stories.tsx +++ b/apps/site/components/Common/Select/index.stories.tsx @@ -1,10 +1,7 @@ import type { Meta as MetaObj, StoryObj } from '@storybook/react'; import Select from '@/components/Common/Select'; -import AIX from '@/components/Icons/Platform/AIX'; -import Apple from '@/components/Icons/Platform/Apple'; -import Linux from '@/components/Icons/Platform/Linux'; -import Microsoft from '@/components/Icons/Platform/Microsoft'; +import OSIcons from '@/components/Icons/OperatingSystem'; type Story = StoryObj; type Meta = MetaObj; @@ -79,22 +76,22 @@ export const InlineSelect: Story = { { value: 'linux', label: 'Linux', - iconImage: , + iconImage: , }, { value: 'macos', label: 'macOS', - iconImage: , + iconImage: , }, { value: 'windows', label: 'Windows', - iconImage: , + iconImage: , }, { value: 'aix', label: 'AIX', - iconImage: , + iconImage: , }, ], }, diff --git a/apps/site/components/Common/Select/index.tsx b/apps/site/components/Common/Select/index.tsx index 66dfed76ff0ab..1428b39a0f487 100644 --- a/apps/site/components/Common/Select/index.tsx +++ b/apps/site/components/Common/Select/index.tsx @@ -5,44 +5,47 @@ import * as ScrollPrimitive from '@radix-ui/react-scroll-area'; import * as SelectPrimitive from '@radix-ui/react-select'; import classNames from 'classnames'; import { useEffect, useId, useMemo, useState } from 'react'; -import type { FC } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import Skeleton from '@/components/Common/Skeleton'; import type { FormattedMessage } from '@/types'; import styles from './index.module.css'; -type SelectValue = { - label: FormattedMessage; - value: string; - iconImage?: React.ReactNode; +export type SelectValue = { + label: FormattedMessage | string; + value: T; + iconImage?: ReactElement; disabled?: boolean; }; -type SelectGroup = { - label?: FormattedMessage; - items: Array; +export type SelectGroup = { + label?: FormattedMessage | string; + items: Array>; }; const isStringArray = (values: Array): values is Array => Boolean(values[0] && typeof values[0] === 'string'); -const isValuesArray = (values: Array): values is Array => +const isValuesArray = ( + values: Array +): values is Array> => Boolean(values[0] && typeof values[0] === 'object' && 'value' in values[0]); -type SelectProps = { - values: Array; - defaultValue?: string; +type SelectProps = { + values: Array> | Array | Array>; + defaultValue?: T; placeholder?: string; label?: string; inline?: boolean; - onChange?: (value: string) => void; + onChange?: (value: T) => void; className?: string; ariaLabel?: string; loading?: boolean; + disabled?: boolean; }; -const Select: FC = ({ +const Select = ({ values = [], defaultValue, placeholder, @@ -52,7 +55,8 @@ const Select: FC = ({ className, ariaLabel, loading = false, -}) => { + disabled = false, +}: SelectProps): ReactNode => { const id = useId(); const [value, setValue] = useState(defaultValue); @@ -69,7 +73,7 @@ const Select: FC = ({ return [{ items: mappedValues }]; } - return mappedValues as Array; + return mappedValues as Array>; }, [values]); // We render the actual item slotted to fix/prevent the issue @@ -83,7 +87,7 @@ const Select: FC = ({ ); // Both change the internal state and emit the change event - const handleChange = (value: string) => { + const handleChange = (value: T) => { setValue(value); if (typeof onChange === 'function') { @@ -106,15 +110,23 @@ const Select: FC = ({ )} - + - {currentItem?.iconImage} - {currentItem?.label} + {currentItem !== undefined && ( + <> + {currentItem.iconImage} + {currentItem.label} + + )} diff --git a/apps/site/components/Common/Skeleton/index.tsx b/apps/site/components/Common/Skeleton/index.tsx index cb5439345c09b..640c1f2e3852d 100644 --- a/apps/site/components/Common/Skeleton/index.tsx +++ b/apps/site/components/Common/Skeleton/index.tsx @@ -3,12 +3,21 @@ import { isValidElement } from 'react'; import styles from './index.module.css'; -type SkeletonProps = { loading?: boolean }; +type SkeletonProps = { hide?: boolean; loading?: boolean }; const Skeleton: FC> = ({ children, + hide = false, loading = true, }) => { + // This can be used to completely hide the children after the Skeleton has loaded + // If certain criterias do not match. This is useful for conditional rendering without + // changing the actual tree that the Skeleton is wrapping + if (!loading && hide) { + return null; + } + + // If we finished loading, we can hide the Skeleton and render the children tree if (!loading) { return children; } diff --git a/apps/site/components/Containers/MetaBar/index.tsx b/apps/site/components/Containers/MetaBar/index.tsx index b4bc0fccf70f8..febcc88bf3e60 100644 --- a/apps/site/components/Containers/MetaBar/index.tsx +++ b/apps/site/components/Containers/MetaBar/index.tsx @@ -8,7 +8,7 @@ import Link from '@/components/Link'; import styles from './index.module.css'; type MetaBarProps = { - items: Record; + items: Partial>; headings?: { items: Array; minDepth?: number; @@ -33,7 +33,7 @@ const MetaBar: FC = ({ items, headings }) => { .filter(([, value]) => !!value) .map(([key, value]) => ( -
{t(key)}
+
{t(key as IntlMessageKeys)}
{value}
))} diff --git a/apps/site/components/Downloads/Release/BitnessDropdown.tsx b/apps/site/components/Downloads/Release/BitnessDropdown.tsx index e48b44cba48b0..b4b7b2ad83db6 100644 --- a/apps/site/components/Downloads/Release/BitnessDropdown.tsx +++ b/apps/site/components/Downloads/Release/BitnessDropdown.tsx @@ -3,107 +3,63 @@ import { useTranslations } from 'next-intl'; import type { FC } from 'react'; import { useEffect, useContext, useMemo } from 'react'; -import semVer from 'semver'; import Select from '@/components/Common/Select'; import { useClientContext } from '@/hooks'; import { ReleaseContext } from '@/providers/releaseProvider'; -import { bitnessItems, formatDropdownItems } from '@/util/downloadUtils'; +import { ARCHITECTURES, nextItem, parseCompat } from '@/util/downloadUtils'; import { getUserBitnessByArchitecture } from '@/util/getUserBitnessByArchitecture'; const parseNumericBitness = (bitness: string) => /^\d+$/.test(bitness) ? Number(bitness) : bitness; const BitnessDropdown: FC = () => { - const { bitness: userBitness, architecture: userArchitecture } = - useClientContext(); - const { bitness, os, release, setBitness } = useContext(ReleaseContext); - const t = useTranslations(); - - useEffect(() => { - setBitness(getUserBitnessByArchitecture(userArchitecture, userBitness)); - // we shouldn't update the effect on setter state change - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [userArchitecture, userBitness]); - - // @TODO: We should have a proper utility that gives - // disabled OSs, Platforms, based on specific criteria - // this can be an optimisation for the future - // to remove this logic from this component - const disabledItems = useMemo(() => { - const disabledItems = []; - - if (os === 'WIN' && semVer.satisfies(release.version, '< 19.9.0')) { - disabledItems.push('arm64'); - } - - if (os === 'WIN' && semVer.satisfies(release.version, '>= 23.0.0')) { - disabledItems.push('86'); - } - - if (os === 'LINUX' && semVer.satisfies(release.version, '< 4.0.0')) { - disabledItems.push('arm64', 'armv7l'); - } - - if (os === 'LINUX' && semVer.satisfies(release.version, '< 4.4.0')) { - disabledItems.push('ppc64le'); - } + const { architecture, bitness } = useClientContext(); - if (os === 'LINUX' && semVer.satisfies(release.version, '< 6.6.0')) { - disabledItems.push('s390x'); - } + const release = useContext(ReleaseContext); + const t = useTranslations(); - if (os === 'AIX' && semVer.satisfies(release.version, '< 6.7.0')) { - disabledItems.push('ppc64'); + // Prevents the Bitness from being set during OS loading state + // and always correctly parses the Bitness to a number when needed + const setBitness = (bitness: string) => { + if (release.os !== 'LOADING') { + release.setBitness(parseNumericBitness(bitness)); } + }; - return disabledItems; - }, [os, release.version]); - - // @TODO: We should have a proper utility that gives - // disabled OSs, Platforms, based on specific criteria - // this can be an optimisation for the future - // to remove this logic from this component - useEffect(() => { - const mappedBitnessValues = bitnessItems[os].map(({ value }) => value); - - const currentBitnessExcluded = - // Different OSs support different Bitnessess, hence we should also check - // if besides the current bitness not being supported for a given release version - // we also should check if it is not supported by the OS - disabledItems.includes(String(bitness)) || - !mappedBitnessValues.includes(String(bitness)); - - const nonExcludedBitness = mappedBitnessValues.find( - bitness => !disabledItems.includes(bitness) - ); + useEffect( + () => setBitness(getUserBitnessByArchitecture(architecture, bitness)), + // Only react on the change of the Client Context Architecture and Bitness + // eslint-disable-next-line react-hooks/exhaustive-deps + [architecture, bitness] + ); - if (currentBitnessExcluded && nonExcludedBitness) { - // We set it as a Number for cases where it is 64 or 86 otherwise we are - // setting it as a string (ARMv7, ARMv6, etc.) - const numericBitness = Number(nonExcludedBitness); + // We parse the compatibility of the dropdown items + const parsedArchitectures = useMemo( + () => parseCompat(ARCHITECTURES[release.os], release), + // We only want to react on the change of the OS, Bitness, and Version + // eslint-disable-next-line react-hooks/exhaustive-deps + [release.os, release.bitness, release.version] + ); - setBitness( - numericBitness.toString() === nonExcludedBitness - ? numericBitness - : nonExcludedBitness - ); - } - // we shouldn't react when "actions" change + // We set the Bitness to the next available Architecture when the current + // one is not valid anymore due to OS or Version changes + useEffect( + () => setBitness(nextItem(String(release.bitness), parsedArchitectures)), + // We only want to react on the change of the OS and Version // eslint-disable-next-line react-hooks/exhaustive-deps - }, [os, disabledItems]); + [release.os, release.version, release.bitness] + ); return ( , - MAC: , - LINUX: , - AIX: , - }, - })} - defaultValue={os} - loading={os === 'LOADING'} + + values={parsedOperatingSystems} + defaultValue={release.os} + loading={release.os === 'LOADING'} + placeholder={t('layouts.download.dropdown.unknown')} ariaLabel={t('layouts.download.dropdown.os')} - onChange={value => setOS(value as UserOS)} + onChange={value => setOS(value)} className="min-w-[8.5rem]" inline={true} /> diff --git a/apps/site/components/Downloads/Release/PackageManagerDropdown.tsx b/apps/site/components/Downloads/Release/PackageManagerDropdown.tsx new file mode 100644 index 0000000000000..14d21ad2b7a5b --- /dev/null +++ b/apps/site/components/Downloads/Release/PackageManagerDropdown.tsx @@ -0,0 +1,53 @@ +'use client'; + +import { useTranslations } from 'next-intl'; +import { useContext, useEffect, useMemo } from 'react'; +import type { FC } from 'react'; + +import Select from '@/components/Common/Select'; +import { ReleaseContext } from '@/providers/releaseProvider'; +import type { PackageManager } from '@/types/release'; +import { nextItem, PACKAGE_MANAGERS, parseCompat } from '@/util/downloadUtils'; + +const PackageManagerDropdown: FC = () => { + const release = useContext(ReleaseContext); + const t = useTranslations(); + + // Prevents the Package Manager from being set during OS loading state + const setManager = (manager: PackageManager | '') => { + if (release.os !== 'LOADING') { + release.setPackageManager(manager); + } + }; + + // We parse the compatibility of the dropdown items + const parsedPackageManagers = useMemo( + () => parseCompat(PACKAGE_MANAGERS, release), + // We only want to react on the change of the Version + // eslint-disable-next-line react-hooks/exhaustive-deps + [release.version] + ); + + // We set the Package Manager to the next available Package Manager when the current + // one is not valid anymore due to Version changes + useEffect( + () => setManager(nextItem(release.packageManager, parsedPackageManagers)), + // We only want to react on the change of the Version + // eslint-disable-next-line react-hooks/exhaustive-deps + [release.version] + ); + + return ( + + values={parsedPackageManagers} + defaultValue={release.packageManager} + loading={release.os === 'LOADING' || release.platform === ''} + ariaLabel={t('layouts.download.dropdown.packageManager')} + onChange={manager => manager && setManager(manager)} + className="min-w-28" + inline={true} + /> + ); +}; + +export default PackageManagerDropdown; diff --git a/apps/site/components/Downloads/Release/PlatformDropdown.tsx b/apps/site/components/Downloads/Release/PlatformDropdown.tsx index 2839fab44b357..3b31bd60b7a82 100644 --- a/apps/site/components/Downloads/Release/PlatformDropdown.tsx +++ b/apps/site/components/Downloads/Release/PlatformDropdown.tsx @@ -5,82 +5,80 @@ import { useContext, useEffect, useMemo } from 'react'; import type { FC } from 'react'; import Select from '@/components/Common/Select'; -import Choco from '@/components/Icons/Platform/Choco'; -import Docker from '@/components/Icons/Platform/Docker'; -import FNM from '@/components/Icons/Platform/FNM'; -import Homebrew from '@/components/Icons/Platform/Homebrew'; -import NVM from '@/components/Icons/Platform/NVM'; import { ReleaseContext } from '@/providers/releaseProvider'; -import type { PackageManager } from '@/types/release'; -import { formatDropdownItems, platformItems } from '@/util/downloadUtils'; - -const supportedHomebrewVersions = ['LTS', 'Current']; +import type { InstallationMethod } from '@/types/release'; +import { nextItem, INSTALL_METHODS, parseCompat } from '@/util/downloadUtils'; const PlatformDropdown: FC = () => { - const { release, os, platform, setPlatform } = useContext(ReleaseContext); + const release = useContext(ReleaseContext); const t = useTranslations(); - // @TODO: We should have a proper utility that gives - // disabled OSs, Platforms, based on specific criteria - // this can be an optimisation for the future - // to remove this logic from this component - const disabledItems = useMemo(() => { - const disabledItems = []; - - if (os === 'WIN') { - disabledItems.push('BREW', 'NVM'); - } - - if (os === 'LINUX' || os === 'MAC') { - disabledItems.push('CHOCO'); + // Prevents the Platform from being set during OS loading state + // This also prevents the Platform from being set (by Dropdwon or Automatic methods) + // when we haven't yet loaded the OS and defined the initial Platform + const setPlaform = (platform: InstallationMethod | '') => { + if (release.os !== 'LOADING' && release.platform !== '') { + release.setPlatform(platform); } + }; - const releaseSupportsHomebrew = supportedHomebrewVersions.includes( - release.status - ); - - if (!releaseSupportsHomebrew) { - disabledItems.push('BREW'); - } + // We parse the compatibility of the dropdown items + const parsedPlatforms = useMemo( + () => parseCompat(INSTALL_METHODS, release), + // We only want to react on the change of the OS and Version + // eslint-disable-next-line react-hooks/exhaustive-deps + [release.os, release.version] + ); - return disabledItems; - }, [os, release.status]); + // We group Platforms on the Platform Dropdown to provide the User + // understanding of what is recommended/official and what is not. + const grouppedPlatforms = useMemo( + () => [ + { + label: t('layouts.download.dropdown.platformGroups.official'), + items: parsedPlatforms.filter(({ recommended }) => recommended), + }, + { + label: t('layouts.download.dropdown.platformGroups.unofficial'), + items: parsedPlatforms.filter(({ recommended }) => !recommended), + }, + ], + // We only want to react on the change of the parsedPlatforms + // eslint-disable-next-line react-hooks/exhaustive-deps + [parsedPlatforms] + ); - // @TODO: We should have a proper utility that gives - // disabled OSs, Platforms, based on specific criteria - // this can be an optimisation for the future - // to remove this logic from this component useEffect(() => { - const currentPlatformExcluded = disabledItems.includes(platform); - - const nonExcludedPlatform = platformItems - .map(({ value }) => value) - .find(platform => !disabledItems.includes(platform)); - - if (currentPlatformExcluded && nonExcludedPlatform) { - setPlatform(nonExcludedPlatform); + // We should only define the initial Platform if the current platform is empty + // (aka has not yet been set) and the OS has finished loading (in the sense that) + // `detectOS` has finished running and decided what platform we are running on. + if (release.os !== 'LOADING' && release.platform === '') { + release.setPlatform( + // Sets either the utmost recommended platform or the first non-disabled one + // Note that the first item of groupped platforms is always the recommended one + nextItem('', grouppedPlatforms[0].items) || + nextItem('', parsedPlatforms) + ); } - // we shouldn't react when "actions" change // eslint-disable-next-line react-hooks/exhaustive-deps - }, [release.status, disabledItems, platform]); + }, [parsedPlatforms, release.platform, release.os]); + + // We set the Platform to the next available platform when the current + // one is not valid anymore due to OS or Version changes + useEffect( + () => setPlaform(nextItem(release.platform, parsedPlatforms)), + // We only want to react on the change of the OS and Version + // eslint-disable-next-line react-hooks/exhaustive-deps + [release.os, release.version] + ); return ( -