Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/site/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import '#site/styles/index.css';

const fontClasses = classNames(IBM_PLEX_MONO.variable, OPEN_SANS.variable);

type RotLayoutProps = PropsWithChildren<{ params: { locale: string } }>;
type RootLayoutProps = PropsWithChildren<{
params: Promise<{ locale: string }>;
}>;

const RootLayout: FC<RotLayoutProps> = async ({ children, params }) => {
const RootLayout: FC<RootLayoutProps> = async ({ children, params }) => {
const { locale } = await params;

const { langDir, hrefLang } = availableLocalesMap[locale] || defaultLocale;
Expand Down
59 changes: 34 additions & 25 deletions apps/site/app/[locale]/next-data/api-data/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,40 @@ export const GET = async () => {
authorizationHeaders
);

return gitHubApiResponse.json().then((apiDocsFiles: Array<GitHubApiFile>) => {
// maps over each api file and get the download_url, fetch the content and deflates it
const mappedApiFiles = apiDocsFiles.map(
async ({ name, path: filename, download_url }) => {
const apiFileResponse = await fetch(download_url);

// Retrieves the content as a raw text string
const source = await apiFileResponse.text();

// Removes empty/blank lines or lines just with spaces and trims each line
// from leading and trailing paddings/spaces
const cleanedContent = parseRichTextIntoPlainText(source);

const deflatedSource = deflateSync(cleanedContent).toString('base64');

return {
filename: filename,
pathname: getPathnameForApiFile(name, versionWithPrefix),
content: deflatedSource,
};
}
);

return Promise.all(mappedApiFiles).then(Response.json);
});
// transforms the response into an array of GitHubApiFile
const apiDocsFiles: Array<GitHubApiFile> = await gitHubApiResponse.json();

// prevent the route from crashing if the response is not an array of GitHubApiFile
// and return an empty array instead. This is a fallback for when the GitHub API is not available.
if (!Array.isArray(apiDocsFiles)) {
return Response.json([]);
}

// maps over each api file and get the download_url, fetch the content and deflates it
const mappedApiFiles = apiDocsFiles.map(
async ({ name, path: filename, download_url }) => {
const apiFileResponse = await fetch(download_url);

// Retrieves the content as a raw text string
const source = await apiFileResponse.text();

// Removes empty/blank lines or lines just with spaces and trims each line
// from leading and trailing paddings/spaces
const cleanedContent = parseRichTextIntoPlainText(source);

const deflatedSource = deflateSync(cleanedContent).toString('base64');

return {
filename: filename,
pathname: getPathnameForApiFile(name, versionWithPrefix),
content: deflatedSource,
};
}
);

const data = await Promise.all(mappedApiFiles);

return Response.json(data);
};

// This function generates the static paths that come from the dynamic segments
Expand Down
37 changes: 0 additions & 37 deletions apps/site/app/[locale]/next-data/download-snippets/route.tsx

This file was deleted.

66 changes: 37 additions & 29 deletions apps/site/app/[locale]/next-data/page-data/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,52 @@ import { parseRichTextIntoPlainText } from '#site/util/string';
// for a digest and metadata of all existing pages on Node.js Website
// @see https://nextjs.org/docs/app/building-your-application/routing/router-handlers
export const GET = async () => {
// Retrieves all available routes for the default locale
const allAvailbleRoutes = await dynamicRouter.getRoutesByLanguage(
defaultLocale.code
);

const availablePagesMetadata = allAvailbleRoutes
.filter(route => !route.startsWith('blog'))
.map(async pathname => {
const { source, filename } = await dynamicRouter.getMarkdownFile(
defaultLocale.code,
pathname
);
// We exclude the blog routes from the available pages metadata
// as they are generated separately and are not part of the static pages
// and are not part of the static pages metadata
const routesExceptBlog = allAvailbleRoutes.filter(
route => !route.startsWith('blog')
);

const availablePagesMetadata = routesExceptBlog.map(async pathname => {
const { source, filename } = await dynamicRouter.getMarkdownFile(
defaultLocale.code,
pathname
);

// Gets the title and the Description from the Page Metadata
const { title, description } = await dynamicRouter.getPageMetadata(
defaultLocale.code,
pathname
);

// Gets the title and the Description from the Page Metadata
const { title, description } = await dynamicRouter.getPageMetadata(
defaultLocale.code,
pathname
);
// Parser the Markdown source with `gray-matter` and then only
// grabs the markdown content and cleanses it by removing HTML/JSX tags
// removing empty/blank lines or lines just with spaces and trims each line
// from leading and trailing paddings/spaces
const cleanedContent = parseRichTextIntoPlainText(matter(source).content);

// Parser the Markdown source with `gray-matter` and then only
// grabs the markdown content and cleanses it by removing HTML/JSX tags
// removing empty/blank lines or lines just with spaces and trims each line
// from leading and trailing paddings/spaces
const cleanedContent = parseRichTextIntoPlainText(matter(source).content);
// Deflates a String into a base64 string-encoded (zlib compressed)
const content = deflateSync(cleanedContent).toString('base64');

// Deflates a String into a base64 string-encoded (zlib compressed)
const content = deflateSync(cleanedContent).toString('base64');
// Returns metadata of each page available on the Website
return {
filename,
pathname,
title,
description,
content,
};
});

// Returns metadata of each page available on the Website
return {
filename,
pathname,
title,
description,
content,
};
});
const data = await Promise.all(availablePagesMetadata);

return Response.json(await Promise.all(availablePagesMetadata));
return Response.json(data);
};

// This function generates the static paths that come from the dynamic segments
Expand Down
31 changes: 0 additions & 31 deletions apps/site/app/[locale]/next-data/release-data/route.ts

This file was deleted.

2 changes: 2 additions & 0 deletions apps/site/app/[locale]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import { ArrowRightIcon } from '@heroicons/react/24/solid';
import Image from 'next/image';
import { useTranslations } from 'next-intl';
Expand Down
2 changes: 1 addition & 1 deletion apps/site/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type DynamicParams = { params: Promise<DynamicStaticPaths> };

// This is the default Viewport Metadata
// @see https://nextjs.org/docs/app/api-reference/functions/generate-viewport#generateviewport-function
export const generateViewport = async () => ({ ...PAGE_VIEWPORT });
export const generateViewport = () => ({ ...PAGE_VIEWPORT });

// This generates each page's HTML Metadata
// @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata
Expand Down
11 changes: 5 additions & 6 deletions apps/site/components/Downloads/DownloadReleasesTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Badge from '@node-core/ui-components/Common/Badge';
import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl';
import type { FC } from 'react';

import FormattedTime from '#site/components/Common/FormattedTime';
import DetailsButton from '#site/components/Downloads/DownloadReleasesTable/DetailsButton';
import getReleaseData from '#site/next-data/releaseData';
import provideReleaseData from '#site/next-data/providers/releaseData';

const BADGE_KIND_MAP = {
'End-of-life': 'warning',
Expand All @@ -14,10 +14,9 @@ const BADGE_KIND_MAP = {
Pending: 'default',
} as const;

const DownloadReleasesTable: FC = async () => {
const releaseData = await getReleaseData();

const t = await getTranslations();
const DownloadReleasesTable: FC = () => {
const releaseData = provideReleaseData();
const t = useTranslations();

return (
<table id="tbVersions" className="download-table full-width">
Expand Down
11 changes: 8 additions & 3 deletions apps/site/components/withBlogCrossLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import CrossLink from '#site/components/Common/CrossLink';
import getBlogData from '#site/next-data/blogData';
import type { BlogCategory } from '#site/types';

const WithBlogCrossLinks: FC = async () => {
const WithBlogCrossLinks: FC = () => {
const { pathname } = getClientContext();

// Extracts from the static URL the components used for the Blog Post slug
const [, , category, postname] = pathname.split('/');
const [, , category, postname] = pathname.split('/') as [
unknown,
unknown,
BlogCategory,
string,
];

const { posts } = await getBlogData(category as BlogCategory);
const { posts } = getBlogData(category);

const currentItem = posts.findIndex(
({ slug }) => slug === `/blog/${category}/${postname}`
Expand Down
17 changes: 9 additions & 8 deletions apps/site/components/withDownloadSection.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getLocale } from 'next-intl/server';
import { useLocale } from 'next-intl';
import type { FC, PropsWithChildren } from 'react';

import { getClientContext } from '#site/client-context';
import WithNodeRelease from '#site/components/withNodeRelease';
import getDownloadSnippets from '#site/next-data/downloadSnippets';
import getReleaseData from '#site/next-data/releaseData';
import provideDownloadSnippets from '#site/next-data/providers/downloadSnippets';
import provideReleaseData from '#site/next-data/providers/releaseData';
import { defaultLocale } from '#site/next.locales.mjs';
import {
ReleaseProvider,
Expand All @@ -13,12 +13,13 @@ import {

// By default the translated languages do not contain all the download snippets
// Hence we always merge any translated snippet with the fallbacks for missing snippets
const fallbackSnippets = await getDownloadSnippets(defaultLocale.code);
const fallbackSnippets = provideDownloadSnippets(defaultLocale.code);

const WithDownloadSection: FC<PropsWithChildren> = async ({ children }) => {
const locale = await getLocale();
const releases = await getReleaseData();
const snippets = await getDownloadSnippets(locale);
const WithDownloadSection: FC<PropsWithChildren> = ({ children }) => {
const locale = useLocale();
const releases = provideReleaseData();

const snippets = provideDownloadSnippets(locale);
const { pathname } = getClientContext();

// Some available translations do not have download snippets translated or have them partially translated
Expand Down
19 changes: 6 additions & 13 deletions apps/site/components/withFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BadgeGroup from '@node-core/ui-components/Common/BadgeGroup';
import Footer from '@node-core/ui-components/Containers/Footer';
import { getTranslations } from 'next-intl/server';
import { useTranslations } from 'next-intl';
import type { FC } from 'react';

import { getClientContext } from '#site/client-context';
Expand All @@ -9,26 +9,19 @@ import { siteNavigation } from '#site/next.json.mjs';

import WithNodeRelease from './withNodeRelease';

const WithFooter: FC = async () => {
const t = await getTranslations();
const WithFooter: FC = () => {
const t = useTranslations();
const { pathname } = getClientContext();

const { socialLinks, footerLinks } = siteNavigation;

const updatedFooterLinks = footerLinks
.slice(0, -1)
.map(link => ({ ...link, text: t(link.text) }));

// Add OpenJS link
updatedFooterLinks.push(footerLinks.at(-1)!);

const navigation = {
socialLinks: socialLinks,
footerLinks: updatedFooterLinks,
footerLinks: footerLinks.map(link => ({ ...link, text: t(link.text) })),
};

const primary = (
<>
<div className="flex flex-row gap-2">
<WithNodeRelease status="Active LTS">
{({ release }) => (
<BadgeGroup
Expand All @@ -53,7 +46,7 @@ const WithFooter: FC = async () => {
</BadgeGroup>
)}
</WithNodeRelease>
</>
</div>
);

return (
Expand Down
6 changes: 3 additions & 3 deletions apps/site/components/withNodeRelease.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { FC } from 'react';

import getReleaseData from '#site/next-data/releaseData';
import provideReleaseData from '#site/next-data/providers/releaseData';
import type { NodeRelease, NodeReleaseStatus } from '#site/types';

type WithNodeReleaseProps = {
Expand All @@ -11,11 +11,11 @@ type WithNodeReleaseProps = {
// This is a React Async Server Component
// Note that Hooks cannot be used in a RSC async component
// Async Components do not get re-rendered at all.
const WithNodeRelease: FC<WithNodeReleaseProps> = async ({
const WithNodeRelease: FC<WithNodeReleaseProps> = ({
status,
children: Component,
}) => {
const releaseData = await getReleaseData();
const releaseData = provideReleaseData();

const matchingRelease = releaseData.find(release =>
[status].flat().includes(release.status)
Expand Down
Loading
Loading