From 460850088e93458ebe7299aa1bf6785b30863135 Mon Sep 17 00:00:00 2001 From: bmuenzenmeyer Date: Sat, 4 Jul 2026 20:03:05 -0500 Subject: [PATCH 1/3] add navitem accent and beta docs --- apps/site/components/withNavBar.tsx | 13 ++++++---- apps/site/hooks/useSiteNavigation.ts | 4 +++- apps/site/navigation.json | 6 +++++ apps/site/types/navigation.ts | 2 ++ packages/i18n/src/locales/en.json | 1 + .../NavBar/NavItem/index.module.css | 24 +++++++++++++++++++ .../src/Containers/NavBar/NavItem/index.tsx | 9 ++++++- .../src/Containers/NavBar/index.stories.tsx | 6 +++++ .../src/Containers/NavBar/index.tsx | 4 +++- 9 files changed, 61 insertions(+), 8 deletions(-) diff --git a/apps/site/components/withNavBar.tsx b/apps/site/components/withNavBar.tsx index 275419bbf18a8..722fb3ede57f0 100644 --- a/apps/site/components/withNavBar.tsx +++ b/apps/site/components/withNavBar.tsx @@ -54,11 +54,14 @@ const WithNavBar: FC = () => { ({ - link, - text: label, - target, - }))} + navItems={navigationItems.map( + ([, { label, link, target, accent }]) => ({ + link, + text: label, + target, + accent, + }) + )} pathname={pathname} as={Link} Logo={WithNodejsLogo} diff --git a/apps/site/hooks/useSiteNavigation.ts b/apps/site/hooks/useSiteNavigation.ts index aa7a2be8efb78..d0c8236010b45 100644 --- a/apps/site/hooks/useSiteNavigation.ts +++ b/apps/site/hooks/useSiteNavigation.ts @@ -19,6 +19,7 @@ type MappedNavigationEntry = { label: FormattedMessage; link: string; target?: HTMLAttributeAnchorTarget | undefined; + accent?: boolean; }; // Provides Context replacement for variables within the Link. This is also something that is not going @@ -44,13 +45,14 @@ const useSiteNavigation = () => { t.rich(label, context[key] || {}) as FormattedMessage; return Object.entries(entries).map( - ([key, { label, link, items, target }]): [ + ([key, { label, link, items, target, accent }]): [ string, MappedNavigationEntry, ] => [ key, { target, + accent, label: label ? getFormattedMessage(label, key) : '', link: link ? replaceLinkWithContext(link, context[key]) : '', items: items ? mapNavigationEntries(items, context) : [], diff --git a/apps/site/navigation.json b/apps/site/navigation.json index 65d0e9f69b295..c90136d5edbd8 100644 --- a/apps/site/navigation.json +++ b/apps/site/navigation.json @@ -20,6 +20,12 @@ "link": "https://nodejs.org/docs/latest/api/", "label": "components.containers.navBar.links.docs" }, + "betaDocs": { + "link": "https://beta.docs.nodejs.org/", + "label": "components.containers.navBar.links.betaDocs", + "target": "_blank", + "accent": true + }, "contribute": { "link": "https://github.com/nodejs/node/blob/main/CONTRIBUTING.md", "label": "components.containers.navBar.links.contribute", diff --git a/apps/site/types/navigation.ts b/apps/site/types/navigation.ts index 5f3d4db1fbe70..b12e85e4c0ac2 100644 --- a/apps/site/types/navigation.ts +++ b/apps/site/types/navigation.ts @@ -16,6 +16,7 @@ export type NavigationKeys = | 'about' | 'download' | 'docs' + | 'betaDocs' | 'getInvolved' | 'certification' | 'learn' @@ -26,6 +27,7 @@ export type NavigationEntry = { link?: string; items?: Record; target?: HTMLAttributeAnchorTarget | undefined; + accent?: boolean; }; export type SiteNavigation = { diff --git a/packages/i18n/src/locales/en.json b/packages/i18n/src/locales/en.json index 4fbbeb0c19b46..7456002bd5f38 100644 --- a/packages/i18n/src/locales/en.json +++ b/packages/i18n/src/locales/en.json @@ -36,6 +36,7 @@ "about": "About", "download": "Download", "docs": "Docs", + "betaDocs": "Beta Docs", "guides": "Guides", "learn": "Learn", "security": "Security", diff --git a/packages/ui-components/src/Containers/NavBar/NavItem/index.module.css b/packages/ui-components/src/Containers/NavBar/NavItem/index.module.css index 7b49c39378c02..52362b8f87362 100644 --- a/packages/ui-components/src/Containers/NavBar/NavItem/index.module.css +++ b/packages/ui-components/src/Containers/NavBar/NavItem/index.module.css @@ -45,6 +45,30 @@ } } + &.accent { + @apply bg-brand-100 + ring-brand-600/20 + dark:bg-brand-600/15 + dark:ring-brand-400/20 + ring-1 + ring-inset; + + .label { + @apply text-brand-700 + dark:text-brand-400; + } + + .icon { + @apply text-brand-600 + dark:text-brand-400; + } + + &:hover { + @apply bg-brand-200 + dark:bg-brand-600/25; + } + } + &.footer { .label { @apply text-neutral-800 diff --git a/packages/ui-components/src/Containers/NavBar/NavItem/index.tsx b/packages/ui-components/src/Containers/NavBar/NavItem/index.tsx index 69faa243a455c..5fcc7f6f29975 100644 --- a/packages/ui-components/src/Containers/NavBar/NavItem/index.tsx +++ b/packages/ui-components/src/Containers/NavBar/NavItem/index.tsx @@ -15,6 +15,7 @@ type NavItemProps = { type?: NavItemType; className?: string; target?: HTMLAttributeAnchorTarget | undefined; + accent?: boolean; pathname: string; as: LinkLike; @@ -26,12 +27,18 @@ const NavItem: FC> = ({ children, className, target, + accent, ...props }) => ( ; Logo: ElementType; as: LinkLike; @@ -76,13 +77,14 @@ const NavBar: FC> = ({
{navItems && navItems.length > 0 && (
- {navItems.map(({ text, link, target }) => ( + {navItems.map(({ text, link, target, accent }) => ( {text} From c1a02eb53acad37ecf7a8eaf285b53b183887e5a Mon Sep 17 00:00:00 2001 From: bmuenzenmeyer Date: Sat, 4 Jul 2026 20:44:35 -0500 Subject: [PATCH 2/3] filter out 'Beta Docs' from expected navigation translations in tests --- apps/site/tests/e2e/general-behavior.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/site/tests/e2e/general-behavior.spec.ts b/apps/site/tests/e2e/general-behavior.spec.ts index 813fabf5ed209..117ee2e05b2f7 100644 --- a/apps/site/tests/e2e/general-behavior.spec.ts +++ b/apps/site/tests/e2e/general-behavior.spec.ts @@ -51,7 +51,9 @@ const verifyTranslation = async (page: Page, locale: Locale | string) => { .all(); const expectedTexts = Object.values( localeData.components.containers.navBar.links - ); + ) + // Filter out 'Beta Docs' link as it is not present in the navigation for some locales + .filter(entry => entry !== 'Beta Docs'); // Verify each navigation link text matches an expected translation for (const link of links) { From 9ce978194e095a311b1e26c90660729e3dcddef4 Mon Sep 17 00:00:00 2001 From: bmuenzenmeyer Date: Sat, 4 Jul 2026 21:09:13 -0500 Subject: [PATCH 3/3] refactor test --- apps/site/tests/e2e/general-behavior.spec.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/site/tests/e2e/general-behavior.spec.ts b/apps/site/tests/e2e/general-behavior.spec.ts index 117ee2e05b2f7..fc0ca9107daa9 100644 --- a/apps/site/tests/e2e/general-behavior.spec.ts +++ b/apps/site/tests/e2e/general-behavior.spec.ts @@ -10,6 +10,9 @@ const locators = { mobileMenuToggleName: englishLocale.components.containers.navBar.controls.toggle, navLinksLocator: `[aria-label="${englishLocale.components.containers.navBar.controls.toggle}"] + div`, + // The Beta Docs link renders untranslated (English) across locales, so we + // match on its English label to skip it during translation checks. + betaDocsName: englishLocale.components.containers.navBar.links.betaDocs, // Global UI controls languageDropdownName: englishLocale.components.common.languageDropdown.label, themeToggleName: englishLocale.components.header.buttons.theme, @@ -51,14 +54,18 @@ const verifyTranslation = async (page: Page, locale: Locale | string) => { .all(); const expectedTexts = Object.values( localeData.components.containers.navBar.links - ) - // Filter out 'Beta Docs' link as it is not present in the navigation for some locales - .filter(entry => entry !== 'Beta Docs'); + ); // Verify each navigation link text matches an expected translation for (const link of links) { - const linkText = await link.textContent(); - expect(expectedTexts).toContain(linkText!.trim()); + const linkText = (await link.textContent())!.trim(); + // Skip the Beta Docs link: it renders untranslated (English) across + // locales and has no translation entry in most locale files, so it + // won't appear in `expectedTexts` for non-English locales (e.g. es). + if (linkText === locators.betaDocsName) { + continue; + } + expect(expectedTexts).toContain(linkText); } };