diff --git a/.storybook/constants.js b/.storybook/constants.js deleted file mode 100644 index 97ffed04f635d..0000000000000 --- a/.storybook/constants.js +++ /dev/null @@ -1,35 +0,0 @@ -import en from '../i18n/locales/en.json'; - -const i18nData = { - currentLocale: { - code: 'en', - localName: 'English', - name: 'English', - langDir: 'ltr', - dateFormat: 'MM.DD.YYYY', - hrefLang: 'en-US', - enabled: true, - }, - localeMessages: en, -}; - -const nodeVersionData = { - nodeVersionData: [ - { - node: 'v19.8.1', - nodeNumeric: '19.8.1', - nodeMajor: 'v19.x', - npm: '9.5.1', - isLts: false, - }, - { - node: 'v18.15.0', - nodeNumeric: '18.15.0', - nodeMajor: 'v18.x', - npm: '9.5.0', - isLts: true, - }, - ], -}; - -export const pageProps = { i18nData, nodeVersionData }; diff --git a/.storybook/constants.ts b/.storybook/constants.ts new file mode 100644 index 0000000000000..8d5ee42a41129 --- /dev/null +++ b/.storybook/constants.ts @@ -0,0 +1,34 @@ +import type { AppProps, NodeVersionData } from '../types'; +import englishMessages from '../i18n/locales/en.json'; + +const i18nData: AppProps['i18nData'] = { + currentLocale: { + code: 'en', + localName: 'English', + name: 'English', + langDir: 'ltr', + dateFormat: 'MM.DD.YYYY', + hrefLang: 'en-US', + enabled: true, + }, + localeMessages: englishMessages, +}; + +const nodeVersionData: NodeVersionData[] = [ + { + node: 'v19.8.1', + nodeNumeric: '19.8.1', + nodeMajor: 'v19.x', + npm: '9.5.1', + isLts: false, + }, + { + node: 'v18.15.0', + nodeNumeric: '18.15.0', + nodeMajor: 'v18.x', + npm: '9.5.0', + isLts: true, + }, +]; + +export const pageProps = { i18nData, nodeVersionData }; diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index caa61821492d6..283ef3270bc53 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,10 +1,13 @@ import type { Preview } from '@storybook/react'; import NextImage from 'next/image'; import { ThemeProvider } from 'next-themes'; -import App from '../pages/_app.mdx'; +import { NodeDataProvider } from '../providers/nodeDataProvider'; +import { LocaleProvider } from '../providers/localeProvider'; +import { SiteProvider } from '../providers/siteProvider'; +import openSans from '../util/openSans'; import { pageProps } from './constants'; -import '../styles/tokens.scss'; +import '../styles/index.scss'; const preview: Preview = { parameters: { @@ -26,7 +29,20 @@ const preview: Preview = { export const decorators = [ Story => ( - + + + + + + + + ), ]; diff --git a/components/Common/AnimatedPlaceholder/AnimatedPlaceholder.stories.tsx b/components/Common/AnimatedPlaceholder/index.stories.tsx similarity index 100% rename from components/Common/AnimatedPlaceholder/AnimatedPlaceholder.stories.tsx rename to components/Common/AnimatedPlaceholder/index.stories.tsx diff --git a/components/Common/Banner/index.module.scss b/components/Common/Banner/index.module.scss index 98bc2d14b9314..98be8f6b45dd7 100644 --- a/components/Common/Banner/index.module.scss +++ b/components/Common/Banner/index.module.scss @@ -1,7 +1,5 @@ -@import 'styles/_variables'; - .banner { - color: $node-gray; + color: var(--color-text-primary); margin: 0 auto; max-width: 90vw; padding-top: var(--space-08); @@ -15,13 +13,12 @@ a { align-items: center; + color: var(--color-text-primary); display: flex; flex-direction: column; text-decoration: none; &:hover { - background-color: transparent !important; - color: $node-green; text-decoration: underline; } @@ -48,7 +45,7 @@ white-space: nowrap; &:hover { - background-color: $node-green !important; + background-color: var(--color-text-primary); cursor: pointer; } } @@ -66,7 +63,6 @@ a { &:hover { - background-color: transparent !important; text-decoration: underline; } } diff --git a/components/Common/Banner/Banner.stories.tsx b/components/Common/Banner/index.stories.tsx similarity index 78% rename from components/Common/Banner/Banner.stories.tsx rename to components/Common/Banner/index.stories.tsx index 134224fc22b6d..1688438477a92 100644 --- a/components/Common/Banner/Banner.stories.tsx +++ b/components/Common/Banner/index.stories.tsx @@ -37,4 +37,15 @@ export const WithHTML: Story = { }, }; +export const WithHTMLImage: Story = { + args: { + bannersIndex: { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + html: 'Banner Image', + link: 'https://nodejs.org/en/', + }, + }, +}; + export default { component: Banner } as Meta; diff --git a/components/Common/DarkModeToggle/__tests__/__snapshots__/index.test.tsx.snap b/components/Common/DarkModeToggle/__tests__/__snapshots__/index.test.tsx.snap index 72a0b72875a00..6f3759d5005b0 100644 --- a/components/Common/DarkModeToggle/__tests__/__snapshots__/index.test.tsx.snap +++ b/components/Common/DarkModeToggle/__tests__/__snapshots__/index.test.tsx.snap @@ -3,15 +3,11 @@ exports[`DarkModeToggle Component render dark mode toggle 1`] = `
diff --git a/components/Common/LanguageSelector/__tests__/index.test.tsx b/components/Common/LanguageSelector/__tests__/index.test.tsx index 28901cb0a7b32..8fbdb2c963a42 100644 --- a/components/Common/LanguageSelector/__tests__/index.test.tsx +++ b/components/Common/LanguageSelector/__tests__/index.test.tsx @@ -1,4 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react'; +import { IntlProvider } from 'react-intl'; import LanguageSelector from '..'; jest.mock('../../../../hooks/useLocale', () => ({ @@ -13,7 +14,11 @@ jest.mock('../../../../hooks/useLocale', () => ({ describe('LanguageSelector', () => { test('clicking the language switch button toggles the dropdown display', () => { - render(); + render( + {}}> + + + ); const button = screen.getByRole('button'); expect(screen.queryByText('English')).not.toBeVisible(); fireEvent.click(button); @@ -23,7 +28,11 @@ describe('LanguageSelector', () => { }); test('renders the Dropdown component with correct style', () => { - render(); + render( + {}}> + + + ); const button = screen.getByRole('button'); fireEvent.click(button); const dropdown = screen.getByRole('list'); diff --git a/components/Common/LanguageSelector/index.tsx b/components/Common/LanguageSelector/index.tsx index 6f323a063f7c8..e966f0f1cace6 100644 --- a/components/Common/LanguageSelector/index.tsx +++ b/components/Common/LanguageSelector/index.tsx @@ -1,5 +1,6 @@ import { useMemo, useState } from 'react'; import { MdOutlineTranslate } from 'react-icons/md'; +import { useIntl } from 'react-intl'; import styles from './index.module.scss'; import Dropdown from '../Dropdown'; import { useLocale } from '../../../hooks/useLocale'; @@ -16,6 +17,8 @@ const LanguageSelector = () => { const { availableLocales, currentLocale } = useLocale(); + const intl = useIntl(); + const dropdownItems = useMemo( () => availableLocales.map(locale => ({ @@ -29,6 +32,10 @@ const LanguageSelector = () => { [availableLocales, currentLocale] ); + const ariaLabelText = intl.formatMessage({ + id: 'components.common.languageSelector.button.title', + }); + return (
diff --git a/global.d.ts b/global.d.ts index 488111db6dc52..31cf7ebe910a2 100644 --- a/global.d.ts +++ b/global.d.ts @@ -9,4 +9,9 @@ declare global { } } +declare module '*.json' { + const value: any; + export default value; +} + export default global; diff --git a/i18n/locales/en.json b/i18n/locales/en.json index e6d10e5eb38cb..8667724be699a 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -38,5 +38,6 @@ "layouts.blogIndex.currentYear": "News from {year}", "components.common.banner.button.text": "Read More", "components.article.author.githubLinkLabel": "{username} Github - opens in new tab", - "components.article.authorList.title": "Article Authors" + "components.article.authorList.title": "Article Authors", + "components.common.languageSelector.button.title": "Switch Language" } diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index a1e917d3bf9d6..0000000000000 --- a/jsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "styles/*": ["./styles/*"], - "i18n/*": ["./i18n/*"] - } - } -} diff --git a/package-lock.json b/package-lock.json index 07f901a050008..013039806d5f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,11 +45,15 @@ "@storybook/testing-library": "^0.1.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", + "@types/jest": "^29.5.1", + "@types/mdx": "^2.0.4", "@types/node": "^18.15.11", "@types/react": "^18.0.31", "@types/react-dom": "^18.0.11", "@types/semver": "^7.3.13", "@types/strftime": "^0.9.4", + "@types/testing-library__jest-dom": "^5.14.5", "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.59.0", "critters": "^0.0.16", @@ -5929,6 +5933,22 @@ "ts-dedent": "^2.2.0" } }, + "node_modules/@storybook/testing-library/node_modules/@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@storybook/theming": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.0.5.tgz", @@ -6205,15 +6225,12 @@ } }, "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, "engines": { - "node": ">=10", + "node": ">=12", "npm": ">=6" }, "peerDependencies": { @@ -6500,9 +6517,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "version": "29.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.1.tgz", + "integrity": "sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==", "dev": true, "dependencies": { "expect": "^29.0.0", diff --git a/package.json b/package.json index 5ee3a8de27111..e392b347934f4 100644 --- a/package.json +++ b/package.json @@ -70,11 +70,15 @@ "@storybook/testing-library": "^0.1.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", + "@types/jest": "^29.5.1", + "@types/mdx": "^2.0.4", "@types/node": "^18.15.11", "@types/react": "^18.0.31", "@types/react-dom": "^18.0.11", "@types/semver": "^7.3.13", "@types/strftime": "^0.9.4", + "@types/testing-library__jest-dom": "^5.14.5", "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.59.0", "critters": "^0.0.16", diff --git a/pages/_app.mdx b/pages/_app.mdx index 16e07178f663a..4b240cf8e1b1a 100644 --- a/pages/_app.mdx +++ b/pages/_app.mdx @@ -2,8 +2,8 @@ import { NodeDataProvider } from '../providers/nodeDataProvider'; import { LocaleProvider } from '../providers/localeProvider'; import { SiteProvider } from '../providers/siteProvider'; import sourceSansPro from '../util/sourceSansPro'; -import '../styles/styles.scss'; -import '../styles/tokens.scss'; + +import '../styles/old/index.scss'; export default function App({ Component, pageProps }) { return ( diff --git a/styles/base.scss b/styles/base.scss new file mode 100644 index 0000000000000..5daac1a37903d --- /dev/null +++ b/styles/base.scss @@ -0,0 +1,47 @@ +html { + box-sizing: border-box; + font-size: 10px; + height: 100%; + margin: 0; + + @media (max-width: 900px) { + font-size: 0.5625rem; + } +} + +body { + background: var(--color-fill-app); + color: var(--color-text-primary); + font-size: var(--font-size-body1); + height: 100%; + margin: 0 0; + overflow-x: hidden; + + /* Set in JavaScript */ + --banner-clip: polygon(0 0, 100% 0, 100% calc(100% - 72px), 0 100%); + --banner-gradient: linear-gradient(to right, var(--accent9), var(--info7)); + --nav-height: 73px; + --hero-height: 36rem; + --brand-light: var(--brand3); + --brand: var(--brand5); + --brand-dark: var(--brand7); + + @media (max-width: 1262px) and (min-width: 900px) { + --banner-clip: polygon(0 0, 100% 0, 100% calc(100% - 52px), 0 100%); + } + + @media (max-width: 900px) { + --nav-height: 42px; + --banner-clip: polygon( + 0 0, + 100% 0, + 100% calc(100% - 52px), + 0 calc(100% - 32px) + ); + } +} + +[data-theme='light'] .dark-mode-only, +[data-theme='dark'] .light-mode-only { + display: none; +} diff --git a/styles/index.scss b/styles/index.scss new file mode 100644 index 0000000000000..1b897f6d6b74f --- /dev/null +++ b/styles/index.scss @@ -0,0 +1,2 @@ +@import './tokens'; +@import './base'; diff --git a/styles/_base.scss b/styles/old/_base.scss similarity index 100% rename from styles/_base.scss rename to styles/old/_base.scss diff --git a/styles/_utils.scss b/styles/old/_utils.scss similarity index 100% rename from styles/_utils.scss rename to styles/old/_utils.scss diff --git a/styles/_variables.scss b/styles/old/_variables.scss similarity index 100% rename from styles/_variables.scss rename to styles/old/_variables.scss diff --git a/styles/styles.scss b/styles/old/index.scss similarity index 100% rename from styles/styles.scss rename to styles/old/index.scss diff --git a/styles/layout/_dark-theme.scss b/styles/old/layout/_dark-theme.scss similarity index 100% rename from styles/layout/_dark-theme.scss rename to styles/old/layout/_dark-theme.scss diff --git a/styles/layout/_grid.scss b/styles/old/layout/_grid.scss similarity index 100% rename from styles/layout/_grid.scss rename to styles/old/layout/_grid.scss diff --git a/styles/layout/_lists.scss b/styles/old/layout/_lists.scss similarity index 100% rename from styles/layout/_lists.scss rename to styles/old/layout/_lists.scss diff --git a/styles/layout/_main.scss b/styles/old/layout/_main.scss similarity index 100% rename from styles/layout/_main.scss rename to styles/old/layout/_main.scss diff --git a/styles/layout/_sticky-footer.scss b/styles/old/layout/_sticky-footer.scss similarity index 100% rename from styles/layout/_sticky-footer.scss rename to styles/old/layout/_sticky-footer.scss diff --git a/styles/page-modules/_anchorLinks.scss b/styles/old/page-modules/_anchorLinks.scss similarity index 100% rename from styles/page-modules/_anchorLinks.scss rename to styles/old/page-modules/_anchorLinks.scss diff --git a/styles/page-modules/_blog-index.scss b/styles/old/page-modules/_blog-index.scss similarity index 100% rename from styles/page-modules/_blog-index.scss rename to styles/old/page-modules/_blog-index.scss diff --git a/styles/page-modules/_blog-post.scss b/styles/old/page-modules/_blog-post.scss similarity index 100% rename from styles/page-modules/_blog-post.scss rename to styles/old/page-modules/_blog-post.scss diff --git a/styles/page-modules/_download.scss b/styles/old/page-modules/_download.scss similarity index 100% rename from styles/page-modules/_download.scss rename to styles/old/page-modules/_download.scss diff --git a/styles/page-modules/_footer.scss b/styles/old/page-modules/_footer.scss similarity index 100% rename from styles/page-modules/_footer.scss rename to styles/old/page-modules/_footer.scss diff --git a/styles/page-modules/_header.scss b/styles/old/page-modules/_header.scss similarity index 100% rename from styles/page-modules/_header.scss rename to styles/old/page-modules/_header.scss diff --git a/styles/page-modules/_home.scss b/styles/old/page-modules/_home.scss similarity index 100% rename from styles/page-modules/_home.scss rename to styles/old/page-modules/_home.scss diff --git a/styles/page-modules/_jsfoundation.scss b/styles/old/page-modules/_jsfoundation.scss similarity index 100% rename from styles/page-modules/_jsfoundation.scss rename to styles/old/page-modules/_jsfoundation.scss diff --git a/styles/page-modules/_prev-next-navigation.scss b/styles/old/page-modules/_prev-next-navigation.scss similarity index 100% rename from styles/page-modules/_prev-next-navigation.scss rename to styles/old/page-modules/_prev-next-navigation.scss diff --git a/styles/page-modules/_scrollToTop.scss b/styles/old/page-modules/_scrollToTop.scss similarity index 100% rename from styles/page-modules/_scrollToTop.scss rename to styles/old/page-modules/_scrollToTop.scss diff --git a/styles/vendor/prism-tomorrow.css b/styles/old/vendor/prism-tomorrow.css similarity index 100% rename from styles/vendor/prism-tomorrow.css rename to styles/old/vendor/prism-tomorrow.css diff --git a/tsconfig.json b/tsconfig.json index 455c5589a055e..ad41fe1b04ad4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,47 @@ { "compilerOptions": { - "target": "ES5", - "module": "ESNext", - "declaration": false, - "noEmit": true, - "esModuleInterop": true, - "strict": true, + "target": "esnext", + "module": "esnext", + "lib": ["es6", "es7", "es2020", "esnext", "dom"], "skipLibCheck": true, - "allowJs": true, "jsx": "preserve", + "removeComments": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, "moduleResolution": "node", - "lib": ["ESNext", "DOM", "DOM.Iterable"], "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "inlineSourceMap": true, + "inlineSources": true, + "allowJs": true, "forceConsistentCasingInFileNames": true, + "noEmit": true, "incremental": true, - "isolatedModules": true, - "downlevelIteration": true + "isolatedModules": true }, + "exclude": [ + "node_modules", + "**/node_modules/*", + "build", + ".next", + "coverage", + "public" + ], "include": [ "next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx", - "next.config.mjs", - "next.data.mjs" - ], - "exclude": ["node_modules"] + "**/*.d.ts" + ] } diff --git a/util/openSans.ts b/util/openSans.ts new file mode 100644 index 0000000000000..4475f1f8e233e --- /dev/null +++ b/util/openSans.ts @@ -0,0 +1,9 @@ +import { Open_Sans } from 'next/font/google'; + +const openSans = Open_Sans({ + weight: ['300', '400', '600'], + display: 'fallback', + subsets: ['latin'], +}); + +export default openSans;