Skip to content
Draft
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 next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
import "./.next/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
36 changes: 36 additions & 0 deletions src/app/-/about/api/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
contentType,
OpenGraphImage,
size,
} from "^/app/_components/OpenGraphImage";

export const alt = "API – npm-diff.app";
export { size, contentType };

export default async function Image() {
return OpenGraphImage({
tag: "Documentation",
title: "API",
icon: (
<svg
width="300"
height="300"
viewBox="0 0 24 24"
fill="none"
stroke="rgba(59, 130, 246, 0.8)"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
style={{
position: "absolute",
right: 80,
top: "50%",
transform: "translateY(-50%)",
}}
>
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
),
});
}
15 changes: 14 additions & 1 deletion src/app/-/about/api/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,20 @@ const EXAMPLE_ABSOLUTE_URL = `${DOMAIN}${EXAMPLE_RELATIVE_LINK}` as const;

export const metadata: Metadata = {
title: "API",
description: "API documentation for npm-diff.app",
description:
"API documentation for npm-diff.app. Access programmatic diff capabilities for npm packages using the same API that powers the web interface.",
openGraph: {
title: "npm-diff.app API",
description:
"API documentation for npm-diff.app. Access programmatic diff capabilities for npm packages.",
url: "https://npm-diff.app/-/about/api",
},
twitter: {
card: "summary_large_image",
title: "npm-diff.app API",
description:
"API documentation for npm-diff.app. Access programmatic diff capabilities for npm packages.",
},
};

const AboutApiPage = async () => {
Expand Down
37 changes: 37 additions & 0 deletions src/app/-/about/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
contentType,
OpenGraphImage,
size,
} from "^/app/_components/OpenGraphImage";

export const alt = "About – npm-diff.app";
export { size, contentType };

export default async function Image() {
return OpenGraphImage({
tag: "About",
title: "npm-diff.app",
icon: (
<svg
width="300"
height="300"
viewBox="0 0 24 24"
fill="none"
stroke="rgba(59, 130, 246, 0.8)"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
style={{
position: "absolute",
right: 80,
top: "50%",
transform: "translateY(-50%)",
}}
>
<circle cx="12" cy="12" r="10" />
<path d="M12 16v-4" />
<path d="M12 8h.01" />
</svg>
),
});
}
14 changes: 14 additions & 0 deletions src/app/-/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ import {

export const metadata: Metadata = {
title: "About",
description:
"Learn how npm-diff.app works. Compare npm packages using the official libnpmdiff library, visualize differences, and analyze bundle sizes with bundlephobia and packagephobia integrations.",
openGraph: {
title: "About npm-diff.app",
description:
"Learn how npm-diff.app compares npm packages using the official libnpmdiff library and visualizes the differences for safer dependency upgrades.",
url: "https://npm-diff.app/-/about",
},
twitter: {
card: "summary_large_image",
title: "About npm-diff.app",
description:
"Learn how npm-diff.app compares npm packages using the official libnpmdiff library and visualizes the differences for safer dependency upgrades.",
},
};

export default function AboutPage() {
Expand Down
108 changes: 12 additions & 96 deletions src/app/-/about/source-trust/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,86 +1,17 @@
import { ImageResponse } from "next/og";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import {
contentType,
OpenGraphImage,
size,
} from "^/app/_components/OpenGraphImage";

export const alt = "Source & Trust – npm-diff.app";
export const size = {
width: 1200,
height: 630,
};

export const contentType = "image/png";
export { size, contentType };

export default async function Image() {
const logoData = await readFile(join(process.cwd(), "src/app/icon.png"));
const logoSrc = Uint8Array.from(logoData).buffer;

return new ImageResponse(
<div
style={{
height: "100%",
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
backgroundColor: "#0d1117",
backgroundImage:
"radial-gradient(circle at bottom left, rgba(18, 39, 74, 1), transparent 70%), radial-gradient(circle at top right, rgba(18, 39, 74, 1), transparent 70%), linear-gradient(rgba(55, 65, 81, 0.3) 2px, transparent 2px), linear-gradient(90deg, rgba(55, 65, 81, 0.3) 2px, transparent 2px)",
backgroundSize: "100% 100%, 100% 100%, 50px 50px, 50px 50px",
position: "relative",
}}
>
<img
src={logoSrc as unknown as string}
width={80}
height={80}
style={{
position: "absolute",
top: 40,
left: 40,
}}
alt="npm-diff.app icon"
/>
<div
style={{
display: "flex",
alignItems: "flex-start",
width: "100%",
padding: "0 80px",
position: "absolute",
top: "50%",
transform: "translateY(-50%)",
flexDirection: "column",
gap: "20px",
}}
>
<div
style={{
display: "flex",
alignItems: "center",
backgroundColor: "rgba(59, 130, 246, 0.2)",
border: "2px solid rgba(59, 130, 246, 0.5)",
borderRadius: "8px",
padding: "8px 16px",
color: "rgba(147, 197, 253, 1)",
fontSize: "24px",
fontWeight: 600,
}}
>
Feature
</div>
<h1
style={{
fontSize: "72px",
fontWeight: 700,
color: "white",
margin: 0,
lineHeight: 1.1,
}}
>
Source & Trust
</h1>
</div>
return OpenGraphImage({
tag: "Feature",
title: "Source & Trust",
icon: (
<svg
width="300"
height="300"
Expand All @@ -100,21 +31,6 @@ export default async function Image() {
<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" />
<path d="m9 12 2 2 4-4" />
</svg>
<div
style={{
position: "absolute",
bottom: 40,
left: 80,
fontSize: "32px",
fontWeight: 600,
color: "rgba(156, 163, 175, 1)",
}}
>
npm-diff.app
</div>
</div>,
{
...size,
},
);
),
});
}
32 changes: 30 additions & 2 deletions src/app/[...parts]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,41 @@ export async function generateMetadata({
params,
}: DiffPageProps): Promise<Metadata> {
const { parts } = await params;
const partsStr = Array.isArray(parts) ? parts.join("/") : parts;
const specs = splitParts(decodeParts(parts));

const [a, b] = specs.map((spec) => createSimplePackageSpec(spec));

const packageNameA = simplePackageSpecToString(a);
const packageNameB = simplePackageSpecToString(b);
const title = `Comparing ${packageNameA}...${packageNameB}`;
const description = `View the detailed diff between npm packages ${packageNameA} and ${packageNameB}. See file changes, additions, deletions, bundle size comparisons, and trust signals including provenance and trusted publishing information.`;

// Generate OpenGraph image URL
const ogImageUrl = `/api/-/og?parts=${encodeURIComponent(partsStr)}`;

return {
title: `Comparing ${simplePackageSpecToString(a)}...${simplePackageSpecToString(b)}`,
description: `A diff between the npm packages "${simplePackageSpecToString(a)}" and "${simplePackageSpecToString(b)}"`,
title,
description,
openGraph: {
title,
description,
type: "article",
images: [
{
url: ogImageUrl,
width: 1200,
height: 630,
alt: `Diff between ${packageNameA} and ${packageNameB}`,
},
],
},
twitter: {
card: "summary_large_image",
title,
description,
images: [ogImageUrl],
},
};
}

Expand Down
Loading