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
2 changes: 1 addition & 1 deletion website/build/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions website/lib/blog-list-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,14 @@ export function BlogListPage({
path: post.slug,
title: post.title,
author: post.author || undefined,
authorImageUrl: undefined,
date: post.date,
authorImageUrl: post.authorImageUrl || undefined,
date: post.date
? new Date(post.date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "2-digit",
})
: "",
Comment on lines +40 to +46
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toLocaleDateString is being called during render to format post.date. In Next.js this can cause SSR/client hydration mismatches and off-by-one dates depending on server vs client timezone. Consider formatting dates in the data layer (when building posts) or specify a fixed timeZone (e.g. UTC) when formatting here to keep the output deterministic.

Copilot uses AI. Check for mistakes.
},
fields: {
readingTime: {
Expand Down
14 changes: 14 additions & 0 deletions website/lib/doc-page-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ export function DocPageView({

const product = useMemo(() => {
const selectedProduct = docsConfig.find((p) => p.path === productPath);
const activeVersion = selectedProduct?.versions?.find(
(v) => v.path === versionPath
);
return {
path: productPath,
name: selectedProduct?.title ?? "",
version: versionPath,
stableVersion: selectedProduct?.latestStableVersion ?? "",
description: selectedProduct?.metaDescription || null,
isPreview: !!activeVersion?.preview,
};
}, [docsConfig, productPath, versionPath]);

Expand Down Expand Up @@ -101,6 +105,7 @@ interface ProductInformation {
readonly version: string;
readonly stableVersion: string;
readonly description: string | null;
readonly isPreview: boolean;
}

const DocumentationVersionWarning = styled.div`
Expand Down Expand Up @@ -188,5 +193,14 @@ function DocumentationNotes({ product, slug }: DocumentationNotesProps) {
}
}

if (product.isPreview) {
return (
<DocumentationVersionWarning>
This is documentation for <strong>{product.version}</strong>, which is
currently in preview.
</DocumentationVersionWarning>
);
}

return null;
}
1 change: 1 addition & 0 deletions website/lib/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface DocsProduct {
export interface DocsVersion {
path: string;
title: string;
preview?: boolean;
items: DocsNavItem[];
}

Expand Down
35 changes: 28 additions & 7 deletions website/scripts/sync-doc-assets.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import fs from "fs/promises";
import path from "path";

const sourceRoot = path.join(process.cwd(), "src/docs");
const targetRoot = path.join(process.cwd(), "public/docs");
const markdownExtensions = new Set([".md", ".mdx"]);

async function copyDocAssets(relativeDir = ""): Promise<number> {
interface SyncTarget {
source: string;
target: string;
}

const targets: SyncTarget[] = [
{
source: path.join(process.cwd(), "src/docs"),
target: path.join(process.cwd(), "public/docs"),
},
{
source: path.join(process.cwd(), "src/blog"),
target: path.join(process.cwd(), "public/images/blog"),
},
];

async function copyAssets(
sourceRoot: string,
targetRoot: string,
relativeDir = ""
): Promise<number> {
const sourceDir = path.join(sourceRoot, relativeDir);
const entries = await fs.readdir(sourceDir, { withFileTypes: true });
let copied = 0;
Expand All @@ -16,7 +34,7 @@ async function copyDocAssets(relativeDir = ""): Promise<number> {
const targetPath = path.join(targetRoot, relativePath);

if (entry.isDirectory()) {
copied += await copyDocAssets(relativePath);
copied += await copyAssets(sourceRoot, targetRoot, relativePath);
continue;
}

Expand All @@ -38,11 +56,14 @@ async function copyDocAssets(relativeDir = ""): Promise<number> {
}

async function main() {
const copied = await copyDocAssets();
console.log(`synced ${copied} doc asset files`);
let total = 0;
for (const { source, target } of targets) {
total += await copyAssets(source, target);
}
console.log(`synced ${total} asset files`);
}

main().catch((error) => {
console.error("failed to sync doc assets", error);
console.error("failed to sync assets", error);
process.exitCode = 1;
});
14 changes: 11 additions & 3 deletions website/src/components/articles/doc-article-navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,14 @@ export const DocArticleNavigation: FC<DocArticleNavigationProps> = ({
fullWidth={!hasVersions}
onClick={toggleProductSwitcher}
>
{activeProduct?.title}
<ProductSwitcherLabel>{activeProduct?.title}</ProductSwitcherLabel>
<IconContainer $size={14}>
<Icon {...Grid2IconSvg} />
</IconContainer>
</ProductSwitcherButton>
{hasVersions && (
<ProductSwitcherButton onClick={toggleVersionSwitcher}>
{activeVersion?.title}
<ProductSwitcherLabel>{activeVersion?.title}</ProductSwitcherLabel>
<IconContainer $size={14}>
{versionSwitcherOpen ? (
<Icon {...ChevronUpIconSvg} />
Expand Down Expand Up @@ -319,6 +319,14 @@ type EnhancedItem = Item & {
fullpath: string;
};

const ProductSwitcherLabel = styled.span`
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;

const ProductSwitcherButton = styled.button<{ readonly fullWidth?: boolean }>`
display: flex;
flex: 0 0 auto;
Expand All @@ -328,7 +336,7 @@ const ProductSwitcherButton = styled.button<{ readonly fullWidth?: boolean }>`
box-sizing: border-box;
border-radius: var(--button-border-radius);
border: 2px solid ${THEME_COLORS.primaryButtonBorder};
min-width: 62px;
min-width: 0;
height: 38px;
Comment on lines 322 to 340
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version titles now include longer strings like "v16 (preview)", but only the switcher button label gets ellipsis styling. The version dropdown (ProductVersionDialog) still uses a fixed narrow width, so these titles are likely to wrap/overflow and degrade the UI. Consider widening the dropdown or applying truncation/auto-sizing styles there as well.

Copilot uses AI. Check for mistakes.
padding-right: 8px;
padding-left: 8px;
Expand Down
23 changes: 23 additions & 0 deletions website/src/components/articles/doc-article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@ interface DocArticleMdx {
} | null>;
}

interface ProductVersion {
path?: string;
title?: string;
preview?: boolean;
}

interface Product {
path?: string;
title?: string;
description?: string;
metaDescription?: string;
latestStableVersion?: string;
versions?: Array<ProductVersion | null>;
}

interface DocArticleData {
Expand Down Expand Up @@ -118,6 +125,7 @@ interface ProductInformation {
readonly version: string;
readonly stableVersion: string;
readonly description: string | null;
readonly isPreview: boolean;
}

export function useProductInformation(
Expand All @@ -137,11 +145,16 @@ export function useProductInformation(
const selectedPath = result[1] || "";
const selectedVersion = result[2] || "";
let stableVersion = "";
let isPreview = false;

const selectedProduct = products?.find((p) => p?.path === selectedPath);

if (selectedProduct) {
stableVersion = selectedProduct.latestStableVersion || "";
const activeVersion = selectedProduct.versions?.find(
(v) => v?.path === selectedVersion
);
isPreview = !!activeVersion?.preview;
}

return {
Expand All @@ -150,6 +163,7 @@ export function useProductInformation(
version: selectedVersion,
stableVersion,
description: selectedProduct?.metaDescription || null,
isPreview,
};
}

Expand Down Expand Up @@ -238,5 +252,14 @@ const DocumentationNotes: FC<DocumentationNotesProps> = ({ product, slug }) => {
}
}

if (product.isPreview) {
return (
<DocumentationVersionWarning>
This is documentation for <strong>{product.version}</strong>, which is
currently in preview.
</DocumentationVersionWarning>
);
}

return null;
};
20 changes: 12 additions & 8 deletions website/src/docs/docs.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"path": "nitro",
"title": "Nitro (fka Banana Cake Pop)",
"title": "Nitro",
"description": "GraphQL API Management",
"metaDescription": "Nitro is a performant, feature-rich GraphQL IDE that helps developers and data scientists to explore, share, and test any GraphQL API.",
"latestStableVersion": "",
Expand Down Expand Up @@ -166,11 +166,12 @@
"title": "Fusion",
"description": "Federated GraphQL Gateway",
"metaDescription": "Fusion is a powerful, open-source GraphQL gateway that helps developers to build a unified API for their services.",
"latestStableVersion": "v16",
"latestStableVersion": "v15",
"versions": [
{
"path": "v16",
"title": "v16",
"title": "v16 (preview)",
"preview": true,
"items": [
{
"path": "index",
Expand Down Expand Up @@ -349,11 +350,12 @@
"title": "Hot Chocolate",
"description": "GraphQL Server / Gateway",
"metaDescription": "Hot Chocolate is the most efficient, feature-rich, open-source GraphQL server in the .NET ecosystem, that helps developers to build powerful APIs.",
"latestStableVersion": "v16",
"latestStableVersion": "v15",
"versions": [
{
"path": "v16",
"title": "v16",
"title": "v16 (preview)",
"preview": true,
"items": [
{ "path": "index", "title": "Overview" },
{
Expand Down Expand Up @@ -2351,11 +2353,12 @@
"title": "Strawberry Shake",
"description": "GraphQL Client for .NET",
"metaDescription": "Strawberry Shake is an incredible GraphQL client for the .NET ecosystem, that helps developers to build awesome UIs in Blazor, Maui, and more.",
"latestStableVersion": "v16",
"latestStableVersion": "v15",
"versions": [
{
"path": "v16",
"title": "v16",
"title": "v16 (preview)",
"preview": true,
"items": [
{
"path": "index",
Expand Down Expand Up @@ -2870,7 +2873,8 @@
"versions": [
{
"path": "v16",
"title": "v16",
"title": "v16 (preview)",
"preview": true,
"items": [
{
"path": "index",
Expand Down
Loading