diff --git a/apps/site/components/EOL/VulnerabilitiesTable.tsx b/apps/site/components/EOL/VulnerabilitiesTable.tsx index fac5d23d3107d..8ea8efe857bc7 100644 --- a/apps/site/components/EOL/VulnerabilitiesTable.tsx +++ b/apps/site/components/EOL/VulnerabilitiesTable.tsx @@ -1,4 +1,3 @@ -import classNames from 'classnames'; import { useTranslations } from 'next-intl'; import type { FC } from 'react'; @@ -9,7 +8,7 @@ import type { Vulnerability } from '#site/types/vulnerabilities'; const VulnerabilitiesTable: FC<{ vulnerabilities: Array; maxWidth?: string; -}> = ({ vulnerabilities, maxWidth = 'max-w-2xs' }) => { +}> = ({ vulnerabilities, maxWidth = 'md:max-w-2xs' }) => { const t = useTranslations(); if (!vulnerabilities.length) { @@ -29,7 +28,7 @@ const VulnerabilitiesTable: FC<{ {vulnerabilities.map((vulnerability, i) => ( - + {vulnerability.cve.map(cveId => (
0 || '-'} - + - + {vulnerability.description || vulnerability.overview || '-'} - + {vulnerability.url && ( = ({ const t = useTranslations(); return ( - + {count > 0 ? {count} : null} {t(`components.eolChip.severity.${severity}`)} diff --git a/apps/site/components/EOL/VulnerabilityChips/index.tsx b/apps/site/components/EOL/VulnerabilityChips/index.tsx index d1cb0354dd794..a6a9cdf7b276b 100644 --- a/apps/site/components/EOL/VulnerabilityChips/index.tsx +++ b/apps/site/components/EOL/VulnerabilityChips/index.tsx @@ -23,7 +23,7 @@ const VulnerabilityChips: FC = ({ ); return ( -
+
{SEVERITY_ORDER.filter(severity => groupedBySeverity[severity] > 0).map( severity => ( = ({ releases }) => { const t = useTranslations(); return ( -
- - - - - - - - - - {releases.map(release => ( - - + + ))} + +
{t('components.minorReleasesTable.version')}{t('components.minorReleasesTable.information')}{t('components.minorReleasesTable.links')}
- - v{release.version} + + + + + + + + + + + + {releases.map(release => ( + + + + + + - - - - ))} - -
{t('components.minorReleasesTable.version')}{t('components.minorReleasesTable.nApiVersion')}{t('components.minorReleasesTable.npmVersion')}{t('components.minorReleasesTable.v8Version')}{t('components.minorReleasesTable.links')}
+ + v{release.version} + + + {release.modules && ( + + )} + + {release.npm && ( + + )} + + + +
+ + {t('components.minorReleasesTable.actions.docs')} -
-
- {release.modules && ( - <> - - - - )} - {release.npm && ( - <> - - - - )} - -
-
-
- - {t('components.minorReleasesTable.actions.docs')} - - - - {t('components.minorReleasesTable.actions.changelog')} - -
-
- + + + {t('components.minorReleasesTable.actions.changelog')} + + +
); }; diff --git a/apps/site/components/Releases/PreviousReleasesTable.tsx b/apps/site/components/Releases/PreviousReleasesTable.tsx index 2471caa45c942..58f7846f80fd2 100644 --- a/apps/site/components/Releases/PreviousReleasesTable.tsx +++ b/apps/site/components/Releases/PreviousReleasesTable.tsx @@ -43,24 +43,30 @@ const PreviousReleasesTable: FC = () => { {releaseData.map(release => ( - - + + v{release.major} - {release.codename || '-'} + + {release.codename || '-'} + - + - + - + {release.status} {release.status === 'End-of-life' ? ' (EoL)' : ''} diff --git a/apps/site/components/Releases/ReleaseOverview/ReleaseOverviewItem/index.tsx b/apps/site/components/Releases/ReleaseOverview/ReleaseOverviewItem/index.tsx index 2f1ca257a1d90..935d04d660ce5 100644 --- a/apps/site/components/Releases/ReleaseOverview/ReleaseOverviewItem/index.tsx +++ b/apps/site/components/Releases/ReleaseOverview/ReleaseOverviewItem/index.tsx @@ -1,3 +1,4 @@ +import classNames from 'classnames'; import type { FC, ReactNode, SVGProps } from 'react'; import styles from './index.module.css'; @@ -5,19 +6,21 @@ import styles from './index.module.css'; type ReleaseOverviewItemProps = { Icon: FC>; title: ReactNode; - subtitle: ReactNode; + subtitle?: ReactNode; + className?: string; }; const ReleaseOverviewItem: FC = ({ Icon, title, subtitle, + className, }) => { return ( -
+
-

{subtitle}

+ {subtitle &&

{subtitle}

}

{title}

diff --git a/apps/site/next.mdx.plugins.mjs b/apps/site/next.mdx.plugins.mjs index a857a298de193..76a8cd777982b 100644 --- a/apps/site/next.mdx.plugins.mjs +++ b/apps/site/next.mdx.plugins.mjs @@ -7,6 +7,8 @@ import rehypeSlug from 'rehype-slug'; import remarkGfm from 'remark-gfm'; import readingTime from 'remark-reading-time'; +import remarkTableTitles from './util/table'; + /** * Provides all our Rehype Plugins that are used within MDX */ @@ -30,4 +32,5 @@ export const REMARK_PLUGINS = [ remarkHeadings, // Calculates the reading time of the content readingTime, + remarkTableTitles, ]; diff --git a/apps/site/package.json b/apps/site/package.json index ee68546fb5a79..1c33850e433c4 100644 --- a/apps/site/package.json +++ b/apps/site/package.json @@ -59,6 +59,7 @@ "feed": "~5.1.0", "github-slugger": "~2.0.0", "gray-matter": "~4.0.3", + "mdast-util-to-string": "^4.0.0", "next": "15.5.2", "next-intl": "~4.3.5", "next-themes": "~0.4.6", @@ -73,6 +74,7 @@ "semver": "~7.7.2", "sval": "^0.6.3", "tailwindcss": "catalog:", + "unist-util-visit": "^5.0.0", "vfile": "~6.0.3", "vfile-matter": "~5.0.1" }, @@ -83,6 +85,7 @@ "@opennextjs/cloudflare": "^1.6.4", "@playwright/test": "^1.54.1", "@testing-library/user-event": "~14.6.1", + "@types/mdast": "^4.0.4", "@types/mdx": "^2.0.13", "@types/semver": "~7.7.0", "dedent": "^1.6.0", diff --git a/apps/site/util/table.ts b/apps/site/util/table.ts new file mode 100644 index 0000000000000..fa1bc93f7fc91 --- /dev/null +++ b/apps/site/util/table.ts @@ -0,0 +1,48 @@ +import type { Root } from 'mdast'; +import { toString } from 'mdast-util-to-string'; +import { visit } from 'unist-util-visit'; + +/** + * Remark plugin that adds data-label attributes to table cells (td) + * based on their corresponding table headers (th). + */ +export default function remarkTableTitles() { + return (tree: Root) => { + visit(tree, 'table', table => { + // Ensure table has at least a header row and one data row + if (table.children.length < 2) { + return; + } + + const [headerRow, ...dataRows] = table.children; + + if (headerRow.children.length <= 1) { + table.data ??= {}; + + table.data.hProperties = { + 'data-cards': 'false', + }; + } + + // Extract header labels from the first row + const headerLabels = headerRow.children.map(headerCell => + toString(headerCell.children) + ); + + // Assign data-label to each cell in data rows + dataRows.forEach(row => { + row.children.forEach((cell, idx) => { + cell.data ??= {}; + + if (idx > headerLabels.length) { + return; + } + + cell.data.hProperties = { + 'data-label': headerLabels[idx], + }; + }); + }); + }); + }; +} diff --git a/packages/i18n/src/locales/en.json b/packages/i18n/src/locales/en.json index 3fec6ccf78e87..18faf3a92c9af 100644 --- a/packages/i18n/src/locales/en.json +++ b/packages/i18n/src/locales/en.json @@ -217,7 +217,9 @@ "minorReleasesTable": { "version": "Version", "links": "Links", - "information": "Version Informations", + "nApiVersion": "N-API version", + "npmVersion": "npm version", + "v8Version": "V8 version", "actions": { "release": "Release", "changelog": "Changelog", diff --git a/packages/ui-components/src/Common/Badge/index.module.css b/packages/ui-components/src/Common/Badge/index.module.css index 49226aa0c9c00..e66c7ef94f282 100644 --- a/packages/ui-components/src/Common/Badge/index.module.css +++ b/packages/ui-components/src/Common/Badge/index.module.css @@ -1,7 +1,8 @@ @reference "../../styles/index.css"; .badge { - @apply rounded-full + @apply whitespace-nowrap + rounded-full text-center text-white; diff --git a/packages/ui-components/src/Common/Modal/index.module.css b/packages/ui-components/src/Common/Modal/index.module.css index c9da0809358e1..0ab884d4f99f7 100644 --- a/packages/ui-components/src/Common/Modal/index.module.css +++ b/packages/ui-components/src/Common/Modal/index.module.css @@ -23,9 +23,11 @@ border border-neutral-200 bg-white - p-8 + p-4 focus:outline-none sm:my-20 + md:p-6 + lg:p-8 xl:p-12 dark:border-neutral-800 dark:bg-neutral-950; diff --git a/packages/ui-components/src/styles/markdown.css b/packages/ui-components/src/styles/markdown.css index b4f9a2cc73cde..53176317a4007 100644 --- a/packages/ui-components/src/styles/markdown.css +++ b/packages/ui-components/src/styles/markdown.css @@ -134,10 +134,10 @@ main { text-sm dark:border-neutral-800; + /* Common border and text styles */ th, td { - @apply max-xs:block - max-xs:border-l-0 + @apply break-words border border-r-0 border-t-0 @@ -148,8 +148,8 @@ main { dark:border-neutral-800 dark:text-white; - > a { - @apply pr-2; + a + a { + @apply mr-2; } } @@ -170,4 +170,66 @@ main { @apply sm:border-l-0; } } + + /* Mobile-specific styles */ + @media (max-width: 40rem) { + table:not([data-cards='false']) { + @apply block + border-0; + + thead { + @apply sr-only; + } + + tbody { + @apply block + space-y-4; + } + + tr { + @apply rounded-xs + block + border + border-neutral-200 + p-4 + before:mb-2 + before:text-sm + before:font-medium + before:text-neutral-500 + before:content-[attr(data-label)] + dark:border-neutral-800 + dark:before:text-neutral-400; + } + + td { + @apply relative + block + border-0 + border-b + px-0 + py-2 + pl-[33%] + text-right + text-neutral-600 + before:absolute + before:left-0 + before:top-1/2 + before:w-1/3 + before:-translate-y-1/2 + before:break-words + before:text-left + before:font-medium + before:text-neutral-700 + before:content-[attr(data-label)] + last:border-0 + dark:border-neutral-900 + dark:text-neutral-300 + dark:before:text-neutral-200; + } + + td div { + @apply justify-end; + } + } + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d01f9b6bf95b..c17f79f6944d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -159,6 +159,9 @@ importers: gray-matter: specifier: ~4.0.3 version: 4.0.3 + mdast-util-to-string: + specifier: ^4.0.0 + version: 4.0.0 next: specifier: 15.5.2 version: 15.5.2(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -201,6 +204,9 @@ importers: tailwindcss: specifier: 'catalog:' version: 4.0.17 + unist-util-visit: + specifier: ^5.0.0 + version: 5.0.0 vfile: specifier: ~6.0.3 version: 6.0.3 @@ -226,6 +232,9 @@ importers: '@testing-library/user-event': specifier: ~14.6.1 version: 14.6.1(@testing-library/dom@10.4.0) + '@types/mdast': + specifier: ^4.0.4 + version: 4.0.4 '@types/mdx': specifier: ^2.0.13 version: 2.0.13