diff --git a/packages/web/docs/src/app/compare/gateway/[comparison]/apollo-router.json b/packages/web/docs/src/app/compare/gateway/[comparison]/apollo-router.json
new file mode 100644
index 0000000000..0e3a62158c
--- /dev/null
+++ b/packages/web/docs/src/app/compare/gateway/[comparison]/apollo-router.json
@@ -0,0 +1,22 @@
+{
+ "name": "Apollo Router",
+ "logo": "apollo",
+ "sections": [
+ {
+ "title": "Features Set 1",
+ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "rows": [
+ { "feature": "Feature 1", "values": [false, true] },
+ { "feature": "Feature 2", "values": [false, true] },
+ { "feature": "Feature 3", "values": [false, true] },
+ { "feature": "Feature 4", "values": [true, false] },
+ { "feature": "Feature ...", "values": [true, false] }
+ ]
+ },
+ {
+ "title": "Features Set 2",
+ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "rows": [{ "feature": "Feature 1", "values": [false, true] }]
+ }
+ ]
+}
diff --git a/packages/web/docs/src/app/compare/gateway/[comparison]/page.tsx b/packages/web/docs/src/app/compare/gateway/[comparison]/page.tsx
new file mode 100644
index 0000000000..7a09ab71e1
--- /dev/null
+++ b/packages/web/docs/src/app/compare/gateway/[comparison]/page.tsx
@@ -0,0 +1,141 @@
+import { readdir, readFile } from 'node:fs/promises';
+import { dirname, join } from 'node:path';
+import { CommunitySection } from '#components/community-section';
+import { CompanyTestimonialsSection } from '#components/company-testimonials';
+import { ErrorBoundary } from '#components/error-boundary';
+import { LandingPageContainer } from '#components/landing-page-container';
+import { TrustedBySection } from '#components/trusted-by-section';
+import {
+ CallToAction,
+ GetYourAPIGameRightSection,
+ Hero,
+ HeroLogo,
+ HiveGatewayIcon,
+ NextPageProps,
+} from '@theguild/components';
+import { FederationCompatibleBenchmarksSection } from '../../../gateway/federation-compatible-benchmarks';
+import { GatewayHeroDecoration } from '../../../gateway/gateway-hero-decoration';
+import { otherLogos } from '../../../gateway/other-logos';
+import { metadata as rootMetadata } from '../../../layout';
+import { ComparisonSection, ComparisonTable } from '../comparison-table';
+
+const __dirname = dirname(new URL(import.meta.url).pathname)
+ .replace('%5B', '[')
+ .replace('%5D', ']');
+
+const DESCRIPTION =
+ 'See why teams choose a fully open-source gateway instead of other closed solutions';
+
+export default async function ComparisonPage(props: NextPageProps<'comparison'>) {
+ const comparison = JSON.parse(
+ await readFile(join(__dirname, `${(await props.params).comparison}.json`), 'utf-8'),
+ ) as Comparison; /* we don't really need to parse this because it's a static build */
+
+ const Logo = otherLogos[comparison.logo as keyof typeof otherLogos];
+
+ return (
+
+
+
+
+ }
+ className="bg-beige-100 mx-4 max-sm:mt-2 md:mx-6"
+ heading={`Hive Gateway vs. ${comparison.name}`}
+ checkmarks={['Fully open source', 'No vendor lock-in', 'Can be self-hosted!']}
+ text={DESCRIPTION}
+ >
+
+ Get Started
+
+
+ GitHub
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ },
+ {
+ name: 'Hive Gateway',
+ icon: ,
+ },
+ ]}
+ sections={comparison.sections}
+ />
+
+
+
+
+ {/* todo: smaller Community-driven open-source section */}
+
+
+
+ );
+}
+
+export async function generateStaticParams() {
+ const dir = await readdir(__dirname);
+ const jsonFiles = dir.filter(file => file.endsWith('.json'));
+ return jsonFiles.map(file => ({ comparison: file.replace('.json', '') }));
+}
+
+export async function generateMetadata({ params }: NextPageProps<'comparison'>) {
+ const file = join(__dirname, `${(await params).comparison}.json`);
+
+ const comparison = JSON.parse(
+ await readFile(file, 'utf-8'),
+ ) as Comparison; /* we don't really need to parse this because it's a static build */
+
+ return {
+ title: `Hive Gateway vs. ${comparison.name}`,
+ description: DESCRIPTION,
+ alternates: {
+ // to remove leading slash
+ canonical: '.',
+ },
+ openGraph: rootMetadata!.openGraph,
+ };
+}
+
+interface Comparison {
+ name: string;
+ logo: string;
+ sections: ComparisonSection[];
+}
diff --git a/packages/web/docs/src/app/compare/gateway/comparison-table.tsx b/packages/web/docs/src/app/compare/gateway/comparison-table.tsx
new file mode 100644
index 0000000000..16c3616b52
--- /dev/null
+++ b/packages/web/docs/src/app/compare/gateway/comparison-table.tsx
@@ -0,0 +1,118 @@
+'use client';
+
+import { Fragment, ReactNode } from 'react';
+import { cn, Heading, ComparisonTable as Table } from '@theguild/components';
+import { CheckmarkIcon, XIcon } from '../../../components/icons';
+import { NestedSticky } from '../../../components/nested-sticky';
+import { TableSubheaderRow } from '../../../components/pricing/table-subheader-row';
+
+const NO = ;
+const YES = ;
+
+export type ComparisonColumn = {
+ name: string;
+ icon?: ReactNode;
+};
+
+export type ComparisonSection = {
+ title: string;
+ description: ReactNode;
+ icon?: ReactNode;
+ rows: ComparisonRow[];
+};
+
+export type ComparisonRow = {
+ feature: string;
+ values: (ReactNode | boolean)[];
+};
+
+export type ComparisonTableProps = {
+ className?: string;
+ columns: ComparisonColumn[];
+ sections: ComparisonSection[];
+};
+
+export function ComparisonTable({ className, columns, sections }: ComparisonTableProps) {
+ return (
+
+
+ Hive Gateway allows you to do so much more. On your own terms.
+
+
+ Part of the Hive ecosystem, Hive Gateway is a fully-fledged solution that you can easily
+ tailor to your needs.
+
+
+
+
+
+
+ Compare features
+
+ {columns.map(column => (
+
+
+ {column.icon &&
{column.icon}
}
+
{column.name}
+
+
+ ))}
+
+
+
+
+
+
+ Compare features |
+ {columns.map((column, i) => (
+ {column.name} |
+ ))}
+
+
+
+ {sections.map((section, sectionIndex) => (
+
+
+ {section.rows.map((row, rowIndex) => (
+
+
+ {row.feature}
+
+ {row.values.map((value, columnIndex) => (
+
+ {typeof value === 'boolean' ? (value ? YES : NO) : value}
+
+ ))}
+
+ ))}
+
+ ))}
+
+
+
+
+ );
+}
+
+function ComparisonTableCell({ children, className }: { children: ReactNode; className?: string }) {
+ return (
+
&:last-child]:rounded-tr-3xl [.subheader+tr>&]:border-t [.subheader+tr>&]:first:rounded-tl-3xl [tr:is(:has(+.subheader),:last-child)>&:last-child]:rounded-br-3xl [tr:is(:last-child,:has(+.subheader))>&]:first:rounded-bl-3xl',
+ className,
+ )}
+ >
+ {children}
+ |
+ );
+}
diff --git a/packages/web/docs/src/app/gateway/federation-compatible-benchmarks/index.tsx b/packages/web/docs/src/app/gateway/federation-compatible-benchmarks/index.tsx
index c39793a9fe..fe1bcc74f7 100644
--- a/packages/web/docs/src/app/gateway/federation-compatible-benchmarks/index.tsx
+++ b/packages/web/docs/src/app/gateway/federation-compatible-benchmarks/index.tsx
@@ -39,7 +39,7 @@ export function FederationCompatibleBenchmarksSection({
-
+
diff --git a/packages/web/docs/src/app/gateway/gateway-hero-decoration.tsx b/packages/web/docs/src/app/gateway/gateway-hero-decoration.tsx
new file mode 100644
index 0000000000..07ccba9caa
--- /dev/null
+++ b/packages/web/docs/src/app/gateway/gateway-hero-decoration.tsx
@@ -0,0 +1,19 @@
+import { ReactNode } from 'react';
+import { DecorationIsolation, HiveGatewayIcon } from '@theguild/components';
+
+export function GatewayHeroDecoration({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/packages/web/docs/src/app/gateway/orchestrate-your-way.tsx b/packages/web/docs/src/app/gateway/orchestrate-your-way.tsx
index 5a572a5ade..636e7e8957 100644
--- a/packages/web/docs/src/app/gateway/orchestrate-your-way.tsx
+++ b/packages/web/docs/src/app/gateway/orchestrate-your-way.tsx
@@ -1,5 +1,6 @@
import { ReactNode } from 'react';
import { Anchor, Heading, InfoCard } from '@theguild/components';
+import { ApolloLogo } from './other-logos';
export function OrchestrateYourWay({ className, ...rest }: React.HTMLAttributes) {
return (
@@ -39,8 +40,16 @@ export function OrchestrateYourWay({ className, ...rest }: React.HTMLAttributes<
- } text="Apollo Federation V1" />
- } text="Apollo Federation V2" />
+ }
+ text="Apollo Federation V1"
+ />
+ }
+ text="Apollo Federation V2"
+ />
}
@@ -97,21 +106,6 @@ function LinkCard({ href, text, logo }: { href: string; text: ReactNode; logo: R
);
}
-function ApolloLogo() {
- return (
-
- );
-}
-
function StitchingLogo() {
return (