You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by we...@apache.org on 2026/07/23 03:52:31 UTC
(apisix-website) 01/01: feat: serve blog, learning center, and articles from the static build (wave 2)
This is an automated email from the ASF dual-hosted git repository.
moonming pushed a commit to branch feat/astro-wave2
in repository https://gitbox.apache.org/repos/asf/apisix-website.git
commit b8f16f193e4fa0e985c88da28ded7aff66e07558
Author: Ming Wen <we...@apache.org>
AuthorDate: Thu Jul 23 11:52:18 2026 +0800
feat: serve blog, learning center, and articles from the static build (wave 2)
Second wave of the incremental migration in next/MIGRATION.md. The
/blog/ (EN+ZH), /learning-center/, /articles/, and /events/archive/
subtrees are now produced by the zero-JS Astro build; every other URL is
still produced by Docusaurus.
Deploy pipeline:
- the Astro step syncs blog/learning-center/articles markdown from this
very checkout (WEBSITE_REPO env) before building — no external fetches
- a parity gate fails the deploy if any URL Docusaurus produced under a
migrated prefix is missing from the Astro build
- the overlay allowlist extends to the wave-2 subtrees; Docusaurus'
RSS/atom feeds for learning-center/articles are carried into the tree
so feed URLs stay alive
Astro pages:
- blog tag pages (10 EN + 6 ZH + index) and per-post tag links, matching
the production URL set exactly
- article pages emit og:type=article like production
Old homepage removal:
- the React homepage and its section components leave the website
workspace (the / route is produced by Astro since wave 1; keeping it
in the bundle showed the stale page on client-side navigations)
- all four workspaces' navbar logos use pathname:/// for a full-page
navigation to the static homepage
- update-sitemap-loc.js re-adds the / and /zh/ entries the website
workspace's sitemap no longer contains
Verified against the current asf-site tree: index.html count unchanged
(4306), wave-2 subtree URL sets byte-exact vs production (0 missing, 0
extra), 8/8 feeds byte-identical, all 8681 files outside the allowlist
untouched, sitemap.xml untouched, head parity on sampled posts
(canonical/title/og:type/JSON-LD/hreflang).
NOT for direct merge: needs the usual reviews.
---
.github/workflows/deploy.yml | 74 ++-
blog/en/docusaurus.config.js | 2 +
blog/zh/docusaurus.config.js | 2 +
doc/docusaurus.config.js | 2 +
next/scripts/sync-content.mjs | 7 +-
next/src/layouts/Article.astro | 2 +-
next/src/layouts/Base.astro | 5 +-
next/src/pages/blog/[...rest].astro | 2 +-
next/src/pages/blog/tags/[tag].astro | 21 +
next/src/pages/blog/tags/index.astro | 19 +
next/src/pages/zh/blog/[...rest].astro | 2 +-
next/src/pages/zh/blog/tags/[tag].astro | 21 +
next/src/pages/zh/blog/tags/index.astro | 19 +
scripts/update-sitemap-loc.js | 19 +
website/docusaurus.config.js | 4 +
website/src/components/ArrowAnim.tsx | 27 -
.../src/components/sections/AIGatewaySection.tsx | 123 -----
website/src/components/sections/Architecture.tsx | 56 ---
website/src/components/sections/Benefits.tsx | 550 ---------------------
website/src/components/sections/Comparison.tsx | 89 ----
website/src/components/sections/Endcta.tsx | 40 --
website/src/components/sections/Features.tsx | 28 --
website/src/components/sections/HeroSection.tsx | 50 --
.../src/components/sections/HomeEventsSection.tsx | 74 ---
website/src/components/sections/Integrations.tsx | 127 -----
.../src/components/sections/OpensourcePromo.tsx | 90 ----
website/src/components/sections/Pathways.tsx | 67 ---
.../src/css/landing-sections/ai-gateway-home.scss | 157 ------
website/src/css/landing-sections/architecture.scss | 114 -----
website/src/css/landing-sections/benefits.scss | 39 --
website/src/css/landing-sections/comparison.scss | 95 ----
.../src/css/landing-sections/endcta.module.scss | 71 ---
.../src/css/landing-sections/features.module.scss | 322 ------------
website/src/css/landing-sections/hero.scss | 249 ----------
.../css/landing-sections/home-events.module.scss | 146 ------
website/src/css/landing-sections/integrations.scss | 89 ----
.../src/css/landing-sections/os-promo.module.scss | 53 --
website/src/css/landing-sections/pathways.scss | 62 ---
website/src/pages/index.tsx | 154 ------
39 files changed, 180 insertions(+), 2893 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 4b09e6b13af..a4180a7d141 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -149,32 +149,69 @@ jobs:
run: |
yarn update-sitemap && git status
- # ---- Static homepage migration (wave 1) --------------------------------
- # The landing page (/ and /zh/) is served from a zero-JS Astro build in
- # next/; every other URL above is produced by Docusaurus. The Astro
- # homepage needs no synced docs, so this build skips the content sync.
- # Runs last, after every Node 16 Docusaurus step (build, canonical
- # assert, sitemap), so switching to Node 22 never touches the Docusaurus
- # toolchain. See next/MIGRATION.md.
+ # ---- Static migration (waves 1-2) --------------------------------------
+ # Wave 1: the landing pages (/ and /zh/). Wave 2: the content subtrees
+ # whose markdown lives in THIS repo — blog (EN+ZH), learning-center,
+ # articles, events/archive. Everything else is still produced by
+ # Docusaurus. Runs last, after every Node 16 Docusaurus step (build,
+ # canonical assert, sitemap), so switching to Node 22 never touches the
+ # Docusaurus toolchain. See next/MIGRATION.md.
- name: Set up Node.js 22 for the Astro build
uses: actions/setup-node@v4
with:
node-version: '22'
- - name: Build the Astro homepage
+ - name: Build the Astro pages
working-directory: next
run: |
npm ci
+ # Blog/learning-center/articles markdown is synced from this very
+ # checkout (WEBSITE_REPO); project docs stay un-synced until wave 3.
+ WEBSITE_REPO="$GITHUB_WORKSPACE" node scripts/sync-content.mjs
npx astro build
- - name: Overlay the Astro homepage onto the Docusaurus build
+ - name: Assert URL parity for the wave-2 subtrees
run: |
set -euo pipefail
- # File-level allowlist: only the two landing pages and the shared
- # Astro asset dir come from the Astro build. Everything else in
- # website/build (docs, blog, sitemaps, .htaccess, robots) is left as
- # Docusaurus produced it, so URLs stay byte-identical.
- for path in index.html zh/index.html _astro; do
+ # Every URL Docusaurus produced under a migrated prefix must exist in
+ # the Astro build too (same index.html path). Astro may add pages
+ # (blog tag pages are deliberately additive); it must never drop one.
+ ROOT="$PWD"
+ fail=0
+ for prefix in blog zh/blog learning-center zh/learning-center articles zh/articles events zh/events; do
+ [ -d "website/build/$prefix" ] || continue
+ missing=$(cd "website/build/$prefix" && find . -name index.html | sort | while read -r f; do
+ [ -f "$ROOT/next/dist/$prefix/$f" ] || echo "$prefix/$f"
+ done)
+ if [ -n "$missing" ]; then
+ echo "MISSING in Astro build:"; echo "$missing"; fail=1
+ fi
+ done
+ exit $fail
+
+ - name: Carry the Docusaurus RSS/atom feeds into the Astro tree
+ run: |
+ set -euo pipefail
+ # Docusaurus generates subscription feeds for these sections; the
+ # Astro build does not (yet). Copy them into the Astro tree so the
+ # subtree replacement below keeps the feed URLs alive.
+ for f in learning-center/atom.xml learning-center/rss.xml \
+ articles/atom.xml articles/rss.xml \
+ zh/learning-center/atom.xml zh/learning-center/rss.xml \
+ zh/articles/atom.xml zh/articles/rss.xml; do
+ cp "website/build/$f" "next/dist/$f"
+ done
+
+ - name: Overlay the Astro pages onto the Docusaurus build
+ run: |
+ set -euo pipefail
+ # Path allowlist: the landing pages, the wave-2 content subtrees, and
+ # the shared Astro asset dir come from the Astro build. Everything
+ # else in website/build (docs, plugins, sitemaps, .htaccess, robots)
+ # is left as Docusaurus produced it, so those URLs stay byte-identical.
+ for path in index.html zh/index.html _astro \
+ blog zh/blog learning-center zh/learning-center \
+ articles zh/articles events zh/events; do
rm -rf "website/build/$path"
mkdir -p "website/build/$(dirname "$path")"
cp -R "next/dist/$path" "website/build/$path"
@@ -185,6 +222,15 @@ jobs:
grep -q '同一个网关' website/build/zh/index.html
grep -q '/_astro/.*\.css' website/build/index.html
test -d website/build/_astro
+ # Wave-2 sanity: key subtree landmarks exist.
+ test -f website/build/blog/index.html
+ test -f website/build/zh/blog/index.html
+ test -f website/build/blog/tags/index.html
+ test -f website/build/learning-center/index.html
+ test -f website/build/learning-center/atom.xml
+ test -f website/build/articles/index.html
+ test -f website/build/zh/articles/rss.xml
+ test -f website/build/events/archive/index.html
# Merge the homepage's image assets (integration brand icons, feature
# infographics, architecture diagram) into the Docusaurus img tree.
# cp merges: it adds the new files and overwrites only same-named
diff --git a/blog/en/docusaurus.config.js b/blog/en/docusaurus.config.js
index 93003060185..8052d4dccd8 100644
--- a/blog/en/docusaurus.config.js
+++ b/blog/en/docusaurus.config.js
@@ -83,6 +83,8 @@ module.exports = {
title: 'Apache APISIX®',
logo: {
src: 'img/logo2.svg',
+ // Full-page navigation: / is produced by the static Astro build.
+ href: 'pathname:///',
},
items: require('../../config/navbar.js'),
},
diff --git a/blog/zh/docusaurus.config.js b/blog/zh/docusaurus.config.js
index 23d6b7b915b..e5880043e33 100644
--- a/blog/zh/docusaurus.config.js
+++ b/blog/zh/docusaurus.config.js
@@ -85,6 +85,8 @@ module.exports = {
title: 'Apache APISIX®',
logo: {
src: 'img/logo2.svg',
+ // Full-page navigation: / is produced by the static Astro build.
+ href: 'pathname:///',
},
items: require('../../config/navbar.js'),
},
diff --git a/doc/docusaurus.config.js b/doc/docusaurus.config.js
index ef8c7e8d008..565144d0fce 100644
--- a/doc/docusaurus.config.js
+++ b/doc/docusaurus.config.js
@@ -213,6 +213,8 @@ module.exports = {
title: 'Apache APISIX®',
logo: {
src: 'img/logo2.svg',
+ // Full-page navigation: / is produced by the static Astro build.
+ href: 'pathname:///',
},
items: require('../config/navbar.js'),
},
diff --git a/next/scripts/sync-content.mjs b/next/scripts/sync-content.mjs
index 258b7c7a6a9..d14b7dcf354 100644
--- a/next/scripts/sync-content.mjs
+++ b/next/scripts/sync-content.mjs
@@ -16,9 +16,10 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
const root = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
-// Clean export of apache/apisix-website origin/master (populated via
-// `git archive`), decoupled from the mutable working checkout next door.
-const WEBSITE_REPO = path.join(root, '.sync/website');
+// Clean export of apache/apisix-website (populated via `git archive`),
+// decoupled from any mutable working checkout. In CI, WEBSITE_REPO points at
+// the checked-out repo root itself.
+const WEBSITE_REPO = process.env.WEBSITE_REPO || path.join(root, '.sync/website');
const OUT = path.join(root, 'content');
const stats = { copied: 0, tabsFlattened: 0, importsStripped: 0, codeTitles: 0, canonicals: 0 };
diff --git a/next/src/layouts/Article.astro b/next/src/layouts/Article.astro
index 10d123a81b2..b14562fb60c 100644
--- a/next/src/layouts/Article.astro
+++ b/next/src/layouts/Article.astro
@@ -27,7 +27,7 @@ const jsonLd = [{
mainEntityOfPage: `${SITE}${locale === 'zh' ? '/zh' : ''}${path}`,
}];
---
-<Base title={post.title} description={post.description} locale={locale} path={path} image={post.image} jsonLd={jsonLd}>
+<Base title={post.title} description={post.description} locale={locale} path={path} image={post.image} jsonLd={jsonLd} ogType="article">
<div class="container article-wrap">
<article class="prose">
<h1>{post.title}</h1>
diff --git a/next/src/layouts/Base.astro b/next/src/layouts/Base.astro
index 553a8d0b2bd..82b5544f5d8 100644
--- a/next/src/layouts/Base.astro
+++ b/next/src/layouts/Base.astro
@@ -14,6 +14,8 @@ interface Props {
jsonLd?: object[];
/** Set false for pages that exist in only one locale. */
hasAlternate?: boolean;
+ /** Open Graph object type; article pages pass "article". */
+ ogType?: 'website' | 'article';
noindex?: boolean;
/** Cross-site canonical embedded in upstream docs (docs.api7.ai hub pages). */
canonicalOverride?: string;
@@ -32,6 +34,7 @@ const {
noindex = false,
canonicalOverride,
titleSuffix = true,
+ ogType = 'website',
} = Astro.props;
const enUrl = `${SITE}${path}`;
@@ -55,7 +58,7 @@ const allJsonLd = [...ORG_JSONLD, ...jsonLd];
{hasAlternate && <link rel="alternate" hreflang="x-default" href={enUrl} />}
<link rel="icon" href={FAVICON} />
<link rel="sitemap" type="application/xml" href={locale === 'zh' ? '/zh/sitemap.xml' : '/sitemap.xml'} />
- <meta property="og:type" content="website" />
+ <meta property="og:type" content={ogType} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={desc} />
<meta property="og:url" content={canonical} />
diff --git a/next/src/pages/blog/[...rest].astro b/next/src/pages/blog/[...rest].astro
index 24baea576df..a4b224eba38 100644
--- a/next/src/pages/blog/[...rest].astro
+++ b/next/src/pages/blog/[...rest].astro
@@ -10,4 +10,4 @@ export function getStaticPaths() {
}
const { post } = Astro.props;
---
-<Article post={post} locale="en" path={post.url} schemaType="BlogPosting" />
+<Article post={post} locale="en" path={post.url} tagBase="/blog" schemaType="BlogPosting" />
diff --git a/next/src/pages/blog/tags/[tag].astro b/next/src/pages/blog/tags/[tag].astro
new file mode 100644
index 00000000000..626ebae3869
--- /dev/null
+++ b/next/src/pages/blog/tags/[tag].astro
@@ -0,0 +1,21 @@
+---
+import ListPage from '../../../layouts/ListPage.astro';
+import { getBlogPosts, groupByTag } from '../../../lib/content';
+
+export function getStaticPaths() {
+ const tags = groupByTag(getBlogPosts('en'));
+ return [...tags.entries()].map(([slug, group]) => ({ params: { tag: slug }, props: group }));
+}
+const { label, posts } = Astro.props;
+const tag = Astro.params.tag;
+---
+<ListPage
+ title={`${label} | Blog`}
+ heading={`Tag: ${label}`}
+ locale="en"
+ path={`/blog/tags/${tag}/`}
+ base={`/blog/tags/${tag}/`}
+ posts={posts}
+ current={1}
+ total={1}
+/>
diff --git a/next/src/pages/blog/tags/index.astro b/next/src/pages/blog/tags/index.astro
new file mode 100644
index 00000000000..b79411a4e61
--- /dev/null
+++ b/next/src/pages/blog/tags/index.astro
@@ -0,0 +1,19 @@
+---
+import Base from '../../../layouts/Base.astro';
+import { getBlogPosts, groupByTag } from '../../../lib/content';
+
+const tags = groupByTag(getBlogPosts('en'));
+const sorted = [...tags.entries()].sort((a, b) => a[0].localeCompare(b[0]));
+---
+<Base title="Tags | Blog" locale="en" path="/blog/tags/">
+ <div class="container">
+ <div class="page-title"><h1>Blog tags</h1></div>
+ <div class="archive-list">
+ <ul>
+ {sorted.map(([slug, { label, posts }]) => (
+ <li><a href={`/blog/tags/${slug}/`}>{label}</a> ({posts.length})</li>
+ ))}
+ </ul>
+ </div>
+ </div>
+</Base>
diff --git a/next/src/pages/zh/blog/[...rest].astro b/next/src/pages/zh/blog/[...rest].astro
index 106ef8d2c65..fb02d06f972 100644
--- a/next/src/pages/zh/blog/[...rest].astro
+++ b/next/src/pages/zh/blog/[...rest].astro
@@ -11,4 +11,4 @@ export function getStaticPaths() {
const { post } = Astro.props;
const path = post.url.replace(/^\/zh/, '');
---
-<Article post={post} locale="zh" path={path} schemaType="BlogPosting" />
+<Article post={post} locale="zh" path={path} tagBase="/zh/blog" schemaType="BlogPosting" />
diff --git a/next/src/pages/zh/blog/tags/[tag].astro b/next/src/pages/zh/blog/tags/[tag].astro
new file mode 100644
index 00000000000..446531af817
--- /dev/null
+++ b/next/src/pages/zh/blog/tags/[tag].astro
@@ -0,0 +1,21 @@
+---
+import ListPage from '../../../../layouts/ListPage.astro';
+import { getBlogPosts, groupByTag } from '../../../../lib/content';
+
+export function getStaticPaths() {
+ const tags = groupByTag(getBlogPosts('zh'));
+ return [...tags.entries()].map(([slug, group]) => ({ params: { tag: slug }, props: group }));
+}
+const { label, posts } = Astro.props;
+const tag = Astro.params.tag;
+---
+<ListPage
+ title={`${label} | 博客`}
+ heading={`标签:${label}`}
+ locale="zh"
+ path={`/blog/tags/${tag}/`}
+ base={`/zh/blog/tags/${tag}/`}
+ posts={posts}
+ current={1}
+ total={1}
+/>
diff --git a/next/src/pages/zh/blog/tags/index.astro b/next/src/pages/zh/blog/tags/index.astro
new file mode 100644
index 00000000000..0051b9167b4
--- /dev/null
+++ b/next/src/pages/zh/blog/tags/index.astro
@@ -0,0 +1,19 @@
+---
+import Base from '../../../../layouts/Base.astro';
+import { getBlogPosts, groupByTag } from '../../../../lib/content';
+
+const tags = groupByTag(getBlogPosts('zh'));
+const sorted = [...tags.entries()].sort((a, b) => a[0].localeCompare(b[0]));
+---
+<Base title="标签 | 博客" locale="zh" path="/blog/tags/">
+ <div class="container">
+ <div class="page-title"><h1>博客标签</h1></div>
+ <div class="archive-list">
+ <ul>
+ {sorted.map(([slug, { label, posts }]) => (
+ <li><a href={`/zh/blog/tags/${slug}/`}>{label}</a> ({posts.length})</li>
+ ))}
+ </ul>
+ </div>
+ </div>
+</Base>
diff --git a/scripts/update-sitemap-loc.js b/scripts/update-sitemap-loc.js
index b4c772238bc..00f9f847249 100644
--- a/scripts/update-sitemap-loc.js
+++ b/scripts/update-sitemap-loc.js
@@ -111,6 +111,22 @@ function filterSitemapUrls(sitemap) {
return before - sitemap.urlset.url.length;
}
+/**
+ * Ensure the homepage entry exists. The landing page is produced by the
+ * static Astro build (next/), not by the website workspace, so the merged
+ * Docusaurus sitemaps no longer contain it.
+ */
+function ensureHomepage(sitemap, url) {
+ const urls = sitemap.urlset.url;
+ if (urls.some((entry) => entry.loc && entry.loc._text === url)) return;
+ urls.unshift({
+ loc: { _text: url },
+ lastmod: { _text: new Date().toISOString().split('T')[0] },
+ priority: { _text: getPriority(url) },
+ changefreq: { _text: getChangefreq(url) },
+ });
+}
+
const tasks = new Listr([
{
title: `Check sitemap.xml files exist`,
@@ -140,6 +156,9 @@ const tasks = new Listr([
}
const removed = filterSitemapUrls(res);
console.log(` Filtered out ${removed} URLs from ${group[0]}`);
+ ensureHomepage(res, group[0].includes('/zh/')
+ ? 'https://apisix.apache.org/zh/'
+ : 'https://apisix.apache.org/');
return res;
})
.then((sitemap) => writeFile(group[0], js2xml(sitemap, { compact: true }, 'utf-8'))),
diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index 8061dc83066..e9915ed804b 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -117,6 +117,10 @@ module.exports = {
title: 'Apache APISIX®',
logo: {
src: 'img/logo2.svg',
+ // Full-page navigation: the homepage is produced by the static Astro
+ // build (next/), not by this SPA — a client-side route to / would
+ // render the removed React homepage.
+ href: 'pathname:///',
},
items: require('../config/navbar.js'),
},
diff --git a/website/src/components/ArrowAnim.tsx b/website/src/components/ArrowAnim.tsx
deleted file mode 100644
index ca0be2c8a37..00000000000
--- a/website/src/components/ArrowAnim.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Link from '@docusaurus/Link';
-import useBaseUrl from '@docusaurus/useBaseUrl';
-
-import Translate from '@docusaurus/Translate';
-
-const ArrowAnim: FC = () => (
- <Link
- target="_blank"
- rel="noopener noreferrer"
- to={useBaseUrl('/blog/')}
- className="btn-docs"
- >
- <div className="goto">
- <Translate id="arrowAnim.component.link.btn">Read Blog</Translate>
- </div>
- <div className="arrow">
- <svg width="70%" height="50%" viewBox="0 0 256 256">
- <polygon points="208,128 80,0 52.8,27.2 140.3,128 53,228.9 80,256" />
- <rect x="-256" y="115" width="256" height="30" />
- </svg>
- </div>
- </Link>
-);
-
-export default ArrowAnim;
diff --git a/website/src/components/sections/AIGatewaySection.tsx b/website/src/components/sections/AIGatewaySection.tsx
deleted file mode 100644
index 29c250b67b0..00000000000
--- a/website/src/components/sections/AIGatewaySection.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Link from '@docusaurus/Link';
-import Translate from '@docusaurus/Translate';
-
-import '../../css/landing-sections/ai-gateway-home.scss';
-
-interface Capability {
- title: JSX.Element;
- desc: JSX.Element;
- href: string;
-}
-
-const CAPABILITIES: Capability[] = [
- {
- title: <Translate id="home.ai.cap.proxy.t">Multi-LLM proxy</Translate>,
- desc: (
- <Translate id="home.ai.cap.proxy.d">
- Route to OpenAI, Anthropic, AWS Bedrock, DeepSeek, Ollama and 20+ providers through one endpoint.
- </Translate>
- ),
- href: '/docs/apisix/plugins/ai-proxy/',
- },
- {
- title: <Translate id="home.ai.cap.lb.t">LLM load balancing</Translate>,
- desc: (
- <Translate id="home.ai.cap.lb.d">
- Distribute traffic across providers and models for throughput and resilience.
- </Translate>
- ),
- href: '/docs/apisix/plugins/ai-proxy-multi/',
- },
- {
- title: <Translate id="home.ai.cap.fallback.t">Retry & fallback</Translate>,
- desc: (
- <Translate id="home.ai.cap.fallback.d">
- Fail over to a backup model or provider automatically when one is unavailable.
- </Translate>
- ),
- href: '/docs/apisix/plugins/ai-proxy-multi/',
- },
- {
- title: <Translate id="home.ai.cap.token.t">Token rate limiting</Translate>,
- desc: (
- <Translate id="home.ai.cap.token.d">
- Cap usage and cost with token-based rate limits per consumer.
- </Translate>
- ),
- href: '/docs/apisix/plugins/ai-rate-limiting/',
- },
- {
- title: <Translate id="home.ai.cap.security.t">Prompt security</Translate>,
- desc: (
- <Translate id="home.ai.cap.security.d">
- Guardrails, content moderation, and prompt decoration before requests reach the model.
- </Translate>
- ),
- href: '/docs/apisix/plugins/ai-prompt-guard/',
- },
- {
- title: <Translate id="home.ai.cap.mcp.t">MCP support</Translate>,
- desc: (
- <Translate id="home.ai.cap.mcp.d">
- Expose and govern Model Context Protocol tools through the gateway.
- </Translate>
- ),
- href: '/ai-gateway/',
- },
-];
-
-const PROVIDERS = ['OpenAI', 'Anthropic', 'AWS Bedrock', 'DeepSeek', 'Ollama'];
-
-const AIGatewaySection: FC = () => (
- <section className="ai-home">
- <div className="ai-home__inner">
- <span className="ai-home__eyebrow">
- <Translate id="home.ai.eyebrow">AI Gateway</Translate>
- </span>
- <h2 className="ai-home__title">
- <Translate id="home.ai.title">The same gateway, now for your LLM traffic</Translate>
- </h2>
- <p className="ai-home__subtitle">
- <Translate id="home.ai.subtitle">
- Proxy, secure, and govern traffic to 20+ LLM providers — with the performance, plugins,
- and observability you already run for your APIs.
- </Translate>
- </p>
-
- <div className="ai-home__flow">
- <span className="ai-home__node">
- <Translate id="home.ai.flow.apps">AI apps & agents</Translate>
- </span>
- <span className="ai-home__arrow" aria-hidden="true">→</span>
- <span className="ai-home__node ai-home__node--apisix">Apache APISIX</span>
- <span className="ai-home__arrow" aria-hidden="true">→</span>
- <span className="ai-home__providers">
- {PROVIDERS.map((provider) => (
- <span className="ai-home__provider" key={provider}>{provider}</span>
- ))}
- <span className="ai-home__provider ai-home__provider--more">
- <Translate id="home.ai.flow.more">+ more</Translate>
- </span>
- </span>
- </div>
-
- <div className="ai-home__grid">
- {CAPABILITIES.map((capability) => (
- <Link className="ai-home__card" to={capability.href} key={capability.title.props.id} target="_blank" rel="noopener noreferrer">
- <h3 className="ai-home__card-title">{capability.title}</h3>
- <p className="ai-home__card-desc">{capability.desc}</p>
- </Link>
- ))}
- </div>
-
- <Link className="ai-home__cta" to="/ai-gateway/" target="_blank" rel="noopener noreferrer">
- <Translate id="home.ai.cta">Explore the AI Gateway</Translate>
- {' →'}
- </Link>
- </div>
- </section>
-);
-
-export default AIGatewaySection;
diff --git a/website/src/components/sections/Architecture.tsx b/website/src/components/sections/Architecture.tsx
deleted file mode 100644
index 3f3a0695ede..00000000000
--- a/website/src/components/sections/Architecture.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-
-import Translate from '@docusaurus/Translate';
-
-import HLDesign from '../../assets/images/infographs/Architecture-min.svg';
-import Pattern from '../../assets/images/PatternGrouped-min.svg';
-import '../../css/landing-sections/architecture.scss';
-
-const Architecture: FC = () => (
- <div className="arch">
- <Pattern
- className="arch-scale-svg"
- width="100vw"
- style={{
- strokeWidth: '2px',
- opacity: '0.25',
- strokeDasharray: '10000',
- position: 'absolute',
- margin: '0 auto',
- bottom: 0,
- zIndex: -10,
- }}
- />
- <h3 className="arch-head">
- <Translate id="architecture.component.title.name">
- Building for large-scale, high value systems
- </Translate>
- </h3>
- <div className="arch-subtitle">
- <p>
- <Translate id="architecture.component.title.subtitle">
- Apache APISIX provides open source API Gateway to help you manage microservices,
- delivering the ultimate performance, security, and scalable platform for all your APIs and
- microservices.
- </Translate>
- </p>
- </div>
- <div className="arch-card" style={{ position: 'relative' }}>
- <div className="hldesign">
- <HLDesign className="hldesign-graphic" />
- </div>
- <div className="arch-card-caption">
- <p>
- <Translate id="architecture.component.card.caption">
- Apache APISIX is based on NGINX and etcd. Compared with traditional API Gateways, APISIX
- has features like dynamic routing and hot-loading plugins, etc.
- </Translate>
- </p>
- </div>
- <div className="arch-card-border" />
- </div>
- </div>
-);
-
-export default Architecture;
diff --git a/website/src/components/sections/Benefits.tsx b/website/src/components/sections/Benefits.tsx
deleted file mode 100644
index d89226ceb11..00000000000
--- a/website/src/components/sections/Benefits.tsx
+++ /dev/null
@@ -1,550 +0,0 @@
-import type { FC } from 'react';
-import React, { useRef, useEffect } from 'react';
-import Link from '@docusaurus/Link';
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import gsap from 'gsap';
-import { ScrollTrigger } from 'gsap/ScrollTrigger';
-
-import Translate from '@docusaurus/Translate';
-
-import Performance from '../../assets/images/infographs/performance.svg';
-import Security from '../../assets/images/infographs/security.svg';
-import Scale from '../../assets/images/infographs/scale.svg';
-import Dynamic from '../../assets/images/infographs/dynamic.svg';
-import Multiplatform from '../../assets/images/infographs/multiplatform.svg';
-import useWindowSize from '../../hooks/useWindowSize';
-
-import '../../css/landing-sections/benefits.scss';
-
-const Benefits: FC = () => {
- const triggerDiv = useRef(null);
- const performance = useRef(null);
- const security = useRef(null);
- const scale = useRef(null);
- const dynamic = useRef(null);
- const multiplatform = useRef(null);
- const [screenWidth] = useWindowSize();
-
- gsap.registerPlugin(ScrollTrigger);
-
- useEffect(() => {
- const tweenTls = [];
- const observers = [];
-
- for (let i = 0; i < 5; i += 1) {
- tweenTls.push(
- gsap.timeline({
- paused: true,
- yoyo: true,
- yoyoEase: 'power3.out',
- repeat: -1,
- defaults: {
- yoyo: true,
- ease: 'power3.inOut',
- yoyoEase: 'power3.out',
- },
- }),
- );
- }
-
- const circles = [];
- const links = [];
- const colors = ['#FE7F80', 'white', 'red'];
- const pathColors = ['#FE7F80', 'black'];
-
- for (let i = 1; i < 28; i += 1) {
- circles.push(`.scale_svg__cir${i}`);
- links.push(`.scale_svg__n${i}`);
- }
-
- // Performance anim
- tweenTls[0]
- .fromTo(
- '.performance_svg__network',
- {
- strokeDashoffset: 1000,
- stroke: 'black',
- },
- {
- strokeDashoffset: 0,
- duration: 1,
- strokeWidth: 5,
- stroke: 'orange',
- ease: 'power2.in',
- yoyoEase: 'power2.out',
- repeat: -1,
- },
- )
- .fromTo(
- '.performance_svg__lightning',
- {
- fill: 'orange',
- },
- {
- fill: 'red',
- duration: 1,
- repeat: -1,
- },
- '-=1',
- );
-
- // Security anim
- tweenTls[1].fromTo(
- ['.security_svg__malWarn-square', '.security_svg__malConn'],
- {
- fill: '#FA5252',
- },
- {
- fill: 'yellow',
- duration: 0.5,
- repeat: -1,
- repeatDelay: 0.1,
- },
- );
- for (let i = 1; i < 4; i += 1) {
- tweenTls[1].fromTo(
- `.security_svg__conn${i}`,
- {
- strokeWidth: 4,
- strokeDasharray: 25,
- strokeDashoffset: 200,
- },
- {
- strokeDashoffset: 0,
- duration: 2.5,
- repeat: -1,
- ease: 'linear',
- yoyoEase: 'linear',
- },
- );
- }
-
- // Scaling anim
- for (let i = 0; i < 27; i += 1) {
- tweenTls[2].fromTo(
- circles[i],
- {
- fill: gsap.utils.random(colors),
- },
- {
- fill: gsap.utils.random(colors),
- duration: 0.3,
- repeat: -1,
- repeatDelay: 0.1,
- },
- );
- tweenTls[2].fromTo(
- links[i],
- {
- stroke: gsap.utils.random(pathColors),
- },
- {
- stroke: gsap.utils.random(pathColors),
- duration: 0.3,
- repeat: -1,
- repeatDelay: 0.1,
- },
- );
- }
-
- // Dynamic anim
- tweenTls[3].repeatDelay(1.5);
- tweenTls[3]
- .fromTo(
- ['.dynamic_svg__rcard'],
- {
- x: -400,
- opacity: 0,
- },
- {
- opacity: 1,
- x: 0,
- ease: 'sin.inOut',
- duration: 1.5,
- },
- )
- .fromTo(
- '.dynamic_svg__arrow',
- {
- opacity: 0,
- },
- {
- opacity: 1,
- ease: 'power3.out',
- duration: 0.5,
- },
- )
- .fromTo(
- '.dynamic_svg__lightning',
- {
- opacity: 0,
- y: 10,
- },
- {
- opacity: 1,
- y: 0,
- duration: 1,
- ease: 'power2.inOut',
- },
- );
-
- // Multiplatform anim
- for (let i = 1; i < 4; i += 1) {
- tweenTls[4].fromTo(
- `.multiplatform_svg__server-port${i}`,
- {
- fill: '#60E0F2',
- },
- {
- fill: '#ffdc21',
- duration: 0.5,
- },
- );
- }
-
- const standloneObserver = new IntersectionObserver(onIntersection, {
- root: null,
- threshold: 0.4,
- });
-
- let rot = 0;
- const tweenArrow = gsap.fromTo(
- '.multiplatform_svg__arrows',
- {
- rotation: rot,
- },
- {
- rotation: -360 + rot,
- transformOrigin: '50% 50%',
- ease: 'power3.inOut',
- duration: 3,
- repeat: -1,
- paused: true,
- onComplete: () => {
- rot -= 360;
- },
- },
- );
- const tweenFloat = gsap.fromTo(
- '.multiplatform_svg__lightning',
- {
- y: -2.5,
- },
- {
- y: 5,
- duration: 1,
- ease: 'linear',
- repeat: -1,
- yoyo: true,
- paused: true,
- yoyoEase: 'linear',
- },
- );
-
- function onIntersection(entries) {
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- tweenArrow.paused(false);
- tweenFloat.paused(false);
- } else {
- tweenArrow.paused(true);
- tweenFloat.paused(true);
- }
- });
- }
-
- standloneObserver.observe(multiplatform.current);
-
- const elems = [
- performance.current,
- security.current,
- scale.current,
- dynamic.current,
- multiplatform.current,
- ];
- for (let i = 0; i < 5; i += 1) {
- observers.push(
- new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- tweenTls[i].paused(false);
- } else {
- tweenTls[i].paused(true);
- }
- });
- },
- {
- root: null,
- threshold: 0.2,
- },
- ),
- );
- }
-
- observers.forEach((it, index) => {
- it.observe(elems[index]);
- });
-
- return () => {
- observers.forEach((it) => {
- it.disconnect();
- });
- tweenTls.forEach((it) => {
- it.pause(0).kill(true);
- });
- };
- }, []);
-
- useEffect(() => {
- ScrollTrigger.saveStyles([
- performance.current,
- security.current,
- scale.current,
- dynamic.current,
- multiplatform.current,
- ]);
-
- ScrollTrigger.matchMedia({
- '(max-width: 1100px)': () => {
- const tl = gsap.timeline({
- defaults: {
- ease: 'linear',
- },
- scrollTrigger: {
- id: 'benefits-scrolltrigger',
- trigger: triggerDiv.current,
- start: 'top top',
- pin: triggerDiv.current,
- scrub: 1,
- end: '+=500%',
- },
- });
- tl.fromTo(
- performance.current,
- {
- opacity: 1,
- },
- {
- opacity: 0,
- },
- )
- .fromTo(
- security.current,
- {
- opacity: 0,
- },
- {
- opacity: 1,
- },
- )
- .to(security.current, {
- opacity: 0,
- })
- .fromTo(
- scale.current,
- {
- opacity: 0,
- },
- {
- opacity: 1,
- },
- )
- .to(scale.current, {
- opacity: 0,
- })
- .fromTo(
- dynamic.current,
- {
- opacity: 0,
- },
- {
- opacity: 1,
- },
- )
- .to(dynamic.current, {
- opacity: 0,
- })
- .fromTo(
- multiplatform.current,
- {
- opacity: 0,
- },
- {
- opacity: 1,
- },
- );
- },
- '(min-width: 1101px)': () => {
- const tl = gsap.timeline();
- tl.to(performance.current, {
- opacity: 1,
- })
- .to(security.current, {
- opacity: 1,
- })
- .to(scale.current, {
- opacity: 1,
- })
- .to(dynamic.current, {
- opacity: 1,
- })
- .to(multiplatform.current, {
- opacity: 1,
- });
- },
- });
- }, []);
-
- return (
- <div ref={triggerDiv} className="benefit" style={{ position: 'relative' }}>
- <div ref={performance} className="row-benefit">
- <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
- <h3 className="feat-head-desc">
- <Translate id="benefits.component.performance.title">Performance</Translate>
- </h3>
- <h2 className="feat-head add-left-margin">
- <Translate id="benefits.component.performance.subtitle">Ultimate performance</Translate>
- </h2>
- <p className="feat-desc add-left-margin">
- <strong>
- <Translate id="benefits.component.performance.message">
- Apache APISIX Gateway uses radixtree-route-matching and etcd under the hood to
- provide you the ability to create high speed synchronized systems. From routing to
- built-in plugins, all these are designed and implemented to be uber performant with
- the minimum latency possible.
- </Translate>
- </strong>
- </p>
- </div>
- <div className="benefit-infograph">
- <Performance style={{ width: screenWidth >= 768 ? '35%' : '40%' }} />
- </div>
- </div>
-
- <div ref={security} className="row-benefit row-reverse row-hidden">
- <div className="benefit-infograph">
- <Security
- style={{
- width: screenWidth >= 768 ? '75%' : '100%',
- position: 'relative',
- left: screenWidth >= 768 ? '3%' : '0',
- }}
- />
- </div>
- <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
- <h3 className="feat-head-desc">
- <Translate id="benefits.component.security.title">Security</Translate>
- </h3>
- <h2 className="feat-head add-left-margin">
- <Translate id="benefits.component.security.subtitle">
- Shield against the malicious
- </Translate>
- </h2>
- <p className="feat-desc add-left-margin">
- <strong>
- <Translate id="benefits.component.security.message">
- Apache APISIX Gateway provides multiple security plugins for identity authentication
- and API verification, including CORS, JWT, Key Auth, OpenID Connect (OIDC),
- Keycloak, etc. We put stability and security first. For more information, check
- </Translate>
- {' '}
- <Link
- style={{ color: '#e8433e' }}
- to={useBaseUrl('docs/apisix/plugins/cors/')}
- target="_blank"
- rel="noopener noreferrer"
- >
- <Translate id="benefits.component.security.link.here">here</Translate>
- </Link>
- <Translate id="common.punctuation.anEnd">.</Translate>
- </strong>
- </p>
- </div>
- </div>
-
- <div ref={scale} className="row-benefit row-hidden">
- <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
- <h3 className="feat-head-desc">
- <Translate id="benefits.component.scalability.title">
- Scalability and availability
- </Translate>
- </h3>
- <h2 className="feat-head add-left-margin">
- <Translate id="benefits.component.scalability.subtitle">
- Scales with your users
- </Translate>
- </h2>
- <p className="feat-desc add-left-margin">
- <strong>
- <Translate id="benefits.component.scalability.message">
- Apache APISIX Gateway provides the ability to write your own custom plugins, use
- custom Load Balancing Algorithms during the balancer phase for scaling and custom
- Routing algorithms for fine control on routing.
- </Translate>
- </strong>
- </p>
- </div>
- <div className="benefit-infograph">
- <Scale style={{ width: screenWidth >= 768 ? '50%' : '60%' }} />
- </div>
- </div>
-
- <div ref={dynamic} className="row-benefit row-reverse row-hidden">
- <div className="benefit-infograph">
- <Dynamic style={{ width: screenWidth >= 768 ? '50%' : '70%' }} />
- </div>
- <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
- <h3 className="feat-head-desc">
- <Translate id="benefits.component.fullyDynamic.title">Fully dynamic</Translate>
- </h3>
- <h2 className="feat-head add-left-margin">
- <Translate id="benefits.component.fullyDynamic.subtitle">
- Save dev-time, design what matters
- </Translate>
- </h2>
- <p className="feat-desc add-left-margin">
- <strong>
- <Translate id="benefits.component.fullyDynamic.message">
- As API Gateway, Apache APISIX provides Hot updates and Hot plugins, which
- continuously update configurations without restarts, saving development time and
- stress. In addition, health checks, circuit breakers, and many more features keep
- the system balanced.
- </Translate>
- </strong>
- </p>
- </div>
- </div>
-
- <div ref={multiplatform} className="row-benefit row-hidden">
- <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
- <h3 className="feat-head-desc">
- <Translate id="benefits.component.multiPlatform.title">
- Multi-platform and protocol
- </Translate>
- </h3>
- <h2 className="feat-head add-left-margin">
- <Translate id="benefits.component.multiPlatform.subtitle">
- Create once, run anywhere
- </Translate>
- </h2>
- <p className="feat-desc add-left-margin">
- <strong>
- <Translate id="benefits.component.multiPlatform.message">
- Platform agnostic, no vendor lock-in. Apache APISIX as API Management solution, can
- run from bare-metal to Kubernetes. It supports HTTP to gRPC transcoding, websockets,
- gRPC, Dubbo, MQTT proxy and multiple platforms including ARM64, don't worry
- about the lock-in of the infra technology.
- </Translate>
- </strong>
- </p>
- </div>
- <div className="benefit-infograph">
- <Multiplatform style={{ width: screenWidth >= 768 ? '50%' : '80%' }} />
- </div>
- </div>
- </div>
- );
-};
-
-export default Benefits;
diff --git a/website/src/components/sections/Comparison.tsx b/website/src/components/sections/Comparison.tsx
deleted file mode 100644
index c01aedd7ac3..00000000000
--- a/website/src/components/sections/Comparison.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Translate from '@docusaurus/Translate';
-
-import Cross from '../../assets/icons/cross.svg';
-import Tick from '../../assets/icons/tick.svg';
-
-import '../../css/landing-sections/comparison.scss';
-
-interface Row {
- feature: JSX.Element;
- apisix: JSX.Element | string;
- other: JSX.Element | string;
-}
-
-const ROWS: Row[] = [
- {
- feature: <Translate id="comparison.row.throughput">Single-core throughput</Translate>,
- apisix: '18,000 QPS',
- other: '~1,700 QPS',
- },
- {
- feature: <Translate id="comparison.row.latency">Added latency</Translate>,
- apisix: '0.2 ms',
- other: '~2 ms',
- },
- {
- feature: <Translate id="comparison.row.ai">AI gateway / LLM proxy</Translate>,
- apisix: <Tick title="Supported" />,
- other: <Cross title="Not supported" />,
- },
- {
- feature: <Translate id="comparison.row.oss">Fully open-source, no paywalled features</Translate>,
- apisix: <Tick title="Supported" />,
- other: <Cross title="Not supported" />,
- },
- {
- feature: <Translate id="comparison.row.dynamic">Dynamic, real-time configuration</Translate>,
- apisix: <Tick title="Supported" />,
- other: <Cross title="Not supported" />,
- },
- {
- feature: <Translate id="comparison.row.hotreload">Hot plugin reload, no restart</Translate>,
- apisix: <Tick title="Supported" />,
- other: <Cross title="Not supported" />,
- },
-];
-
-const Comparison: FC = () => (
- <section className="compare">
- <h2 className="compare-head">
- <Translate id="comparison.component.title">Among the best, and always improving</Translate>
- </h2>
- <p className="compare-subtitle">
- <Translate id="comparison.component.subtitle">
- Apache APISIX is an open-source API gateway and AI gateway — here is how it compares on
- performance and core capabilities.
- </Translate>
- </p>
- <div className="compare-table-wrap">
- <table className="compare-table">
- <thead>
- <tr>
- <th className="compare-col-feature">
- <Translate id="comparison.col.feature">Feature</Translate>
- </th>
- <th className="compare-col-apisix">Apache APISIX</th>
- <th className="compare-col-other">
- <Translate id="comparison.col.other">Other gateways</Translate>
- </th>
- </tr>
- </thead>
- <tbody>
- {ROWS.map((row, index) => (
- <tr key={index}>
- <th scope="row" className="compare-col-feature">
- {row.feature}
- </th>
- <td className="compare-apisix-cell">{row.apisix}</td>
- <td className="compare-other-cell">{row.other}</td>
- </tr>
- ))}
- </tbody>
- </table>
- </div>
- </section>
-);
-
-export default Comparison;
diff --git a/website/src/components/sections/Endcta.tsx b/website/src/components/sections/Endcta.tsx
deleted file mode 100644
index 8a2221fe4ca..00000000000
--- a/website/src/components/sections/Endcta.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Link from '@docusaurus/Link';
-import Translate from '@docusaurus/Translate';
-import { LazyLoadImage } from 'react-lazy-load-image-component';
-import useWindowType from '@theme/hooks/useWindowSize';
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import ArrowAnim from '../ArrowAnim';
-import style from '../../css/landing-sections/endcta.module.scss';
-
-const EndCTA: FC = () => {
- const windowType = useWindowType();
-
- return (
- <div className={style.endcta}>
- <p className={style.text}>
- <span>Try </span>
- <span className={style.apisix}>Apache APISIX </span>
- <span>today.</span>
- {windowType === 'desktop' && (
- <LazyLoadImage
- className={style.rocket}
- src="https://static.apiseven.com/202202/rocket.gif"
- alt="Rocket"
- width="6vw"
- height="6vw"
- />
- )}
- </p>
- <div className={style.links}>
- <Link target="_blank" rel="noopener noreferrer" to={useBaseUrl('docs/apisix/getting-started')} className="btn btn-download">
- <Translate id="hero.component.download.btn">Getting Started</Translate>
- </Link>
- <ArrowAnim />
- </div>
- </div>
- );
-};
-
-export default EndCTA;
diff --git a/website/src/components/sections/Features.tsx b/website/src/components/sections/Features.tsx
deleted file mode 100644
index eac61ef5389..00000000000
--- a/website/src/components/sections/Features.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Translate from '@docusaurus/Translate';
-
-import styles from '../../css/landing-sections/features.module.scss';
-
-const Features: FC = () => (
- <div className={styles.features}>
- <section className={styles.head}>
- <h2>
- <Translate id="features.component.why.title">Why APISIX API Gateway?</Translate>
- </h2>
- <h3>
- <Translate id="features.component.why.subtitle">
- Reduce time fighting bugs, focus on designing world-class systems with API Gateway
- </Translate>
- </h3>
- <p>
- <Translate id="features.component.why.message">
- APISIX API Gateway offers nearly 100 open-source plugins, comprehensive API management
- capabilities, and advanced technical advantages.
- </Translate>
- </p>
- </section>
- </div>
-);
-
-export default Features;
diff --git a/website/src/components/sections/HeroSection.tsx b/website/src/components/sections/HeroSection.tsx
deleted file mode 100644
index 3d0e3df83c0..00000000000
--- a/website/src/components/sections/HeroSection.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Link from '@docusaurus/Link';
-import Translate from '@docusaurus/Translate';
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import '../../css/landing-sections/hero.scss';
-
-const STATS: { value: string; label: JSX.Element }[] = [
- { value: '100+', label: <Translate id="hero.stats.plugins">plugins</Translate> },
- { value: '~18k', label: <Translate id="hero.stats.qps">QPS / core</Translate> },
- { value: '0.2 ms', label: <Translate id="hero.stats.latency">added latency</Translate> },
- { value: 'Apache 2.0', label: <Translate id="hero.stats.license">licensed</Translate> },
-];
-
-const HeroSection: FC = () => (
- <header className="hero-sec-wrap">
- <div className="hero-text">
- <span className="hero-eyebrow">
- <Translate id="hero.component.eyebrow">Apache Software Foundation top-level project</Translate>
- </span>
- <h1 className="hero-title">
- <Translate id="hero.component.title.main">The open-source API Gateway & AI Gateway</Translate>
- </h1>
- <p className="hero-subtitle">
- <Translate id="hero.component.subtitle.main">
- High-performance traffic management for APIs, microservices, and LLM workloads —
- dynamic routing, load balancing, authentication, observability, and 100+ plugins.
- </Translate>
- </p>
- <div className="hero-ctas">
- <Link target="_blank" rel="noopener noreferrer" to={useBaseUrl('docs/apisix/getting-started')} className="btn btn-download">
- <Translate id="hero.component.download.btn">Get started</Translate>
- </Link>
- <Link target="_blank" rel="noopener noreferrer" to={useBaseUrl('plugins/')} className="btn btn-secondary">
- <Translate id="hero.component.plugins.btn">Browse 100+ plugins</Translate>
- </Link>
- </div>
- <ul className="hero-stats">
- {STATS.map((stat) => (
- <li className="hero-stats__item" key={stat.value}>
- <span className="hero-stats__value">{stat.value}</span>
- <span className="hero-stats__label">{stat.label}</span>
- </li>
- ))}
- </ul>
- </div>
- </header>
-);
-
-export default HeroSection;
diff --git a/website/src/components/sections/HomeEventsSection.tsx b/website/src/components/sections/HomeEventsSection.tsx
deleted file mode 100644
index 88b975414b5..00000000000
--- a/website/src/components/sections/HomeEventsSection.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
-
-import Translate from '@docusaurus/Translate';
-
-import style from '../../css/landing-sections/home-events.module.scss';
-
-interface EventInfo {
- title: string;
- fileName: string;
-}
-
-const Events: FC = () => {
- const { siteConfig, i18n: { currentLocale } } = useDocusaurusContext();
-
- const currentEvent = (siteConfig.customFields.events[currentLocale]
- || siteConfig.customFields.events.en) as EventInfo[];
- const events = currentEvent.slice(0, 4).map((event) => {
- const publishTime = event.fileName.slice(0, 10);
- const fileNameArr = event.fileName.split('-');
- const url = `/blog/${fileNameArr.slice(0, 3).join('/')}/${fileNameArr.slice(3).join('-')}`;
- return (
- <a className={style.eventCard} key={event.title} href={url} target="_blank" rel="noreferrer">
- <time dateTime={publishTime}>{publishTime}</time>
- <h4>{event.title}</h4>
- <div>
- <Translate id="homeEventsSection.component.readMore">Read More</Translate>
- <div className={style.arrow}>
- <svg width="50%" height="100%" viewBox="0 0 256 256">
- <polygon
- fill="currentcolor"
- points="208,128 80,0 52.8,27.2 140.3,128 53,228.9 80,256"
- />
- <rect fill="currentcolor" x="-256" y="115" width="256" height="30" />
- </svg>
- </div>
- </div>
- </a>
- );
- });
-
- return <div className={style.events}>{events}</div>;
-};
-
-const HomeEventsSection: FC = () => (
- <div className={style.homeEvents}>
- <h3>
- <Translate id="homeEventsSection.component.title">Stay updated about APISIX</Translate>
- </h3>
- <p>
- <Translate id="homeEventsSection.component.subtitle">Some Recent events</Translate>
- </p>
- <Events />
- <div className={style.newsletter}>
- <p>
- <Translate id="homeEventsSection.component.message.news">
- Stay up to date about all Apache APISIX® News,
- </Translate>
- {' '}
- <a href="/docs/general/join/">
- <Translate id="homeEventsSection.component.link.newsletter">
- subscribe to our newsletter.
- </Translate>
- </a>
- </p>
- <a className={style.newsButton} href="/docs/general/join">
- <Translate id="homeEventsSection.component.link.Subscribe">Subscribe Now</Translate>
- </a>
- </div>
- </div>
-);
-
-export default HomeEventsSection;
diff --git a/website/src/components/sections/Integrations.tsx b/website/src/components/sections/Integrations.tsx
deleted file mode 100644
index fc9ebcb9068..00000000000
--- a/website/src/components/sections/Integrations.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Head from '@docusaurus/Head';
-import Link from '@docusaurus/Link';
-import Translate from '@docusaurus/Translate';
-
-import '../../css/landing-sections/integrations.scss';
-
-interface Integration {
- name: string;
- /** Plugin name whose brand-colored icon lives in the shared plugin sprite. */
- icon?: string;
- /** Colored logo served from /img/integrations/ (for non-plugin ecosystem logos). */
- logo?: string;
- /** Doc link. Falls back to the plugin doc derived from `icon`. */
- href?: string;
-}
-
-const GROUPS: { title: string; items: Integration[] }[] = [
- {
- title: 'Observability & tracing',
- items: [
- { name: 'Prometheus', icon: 'prometheus' },
- { name: 'Grafana', logo: '/img/integrations/grafana.svg', href: '/docs/apisix/plugins/prometheus/' },
- { name: 'Datadog', icon: 'datadog' },
- { name: 'OpenTelemetry', logo: '/img/integrations/opentelemetry.svg', href: '/docs/apisix/plugins/opentelemetry/' },
- { name: 'Apache SkyWalking', icon: 'skywalking' },
- { name: 'Zipkin', icon: 'zipkin' },
- ],
- },
- {
- title: 'Logging & data',
- items: [
- { name: 'Elasticsearch', logo: '/img/integrations/elasticsearch.svg', href: '/docs/apisix/plugins/elasticsearch-logger/' },
- { name: 'ClickHouse', logo: '/img/integrations/clickhouse.svg', href: '/docs/apisix/plugins/clickhouse-logger/' },
- { name: 'Google Cloud', icon: 'google-cloud-logging' },
- ],
- },
- {
- title: 'Streaming & protocols',
- items: [
- { name: 'Apache Kafka', icon: 'kafka-logger' },
- { name: 'gRPC', icon: 'grpc-transcode' },
- ],
- },
- {
- title: 'Service discovery & runtime',
- items: [
- { name: 'Kubernetes', logo: '/img/integrations/kubernetes.svg', href: '/docs/apisix/discovery/kubernetes/' },
- { name: 'Consul', logo: '/img/integrations/consul.svg', href: '/docs/apisix/discovery/consul/' },
- { name: 'NGINX', logo: '/img/integrations/nginx.svg', href: '/docs/apisix/architecture-design/apisix/' },
- { name: 'Redis', logo: '/img/integrations/redis.svg', href: '/docs/apisix/plugins/limit-count/' },
- ],
- },
- {
- title: 'Security & secrets',
- items: [
- { name: 'OpenID Connect', icon: 'openid-connect' },
- { name: 'Keycloak', icon: 'authz-keycloak' },
- { name: 'Casbin', icon: 'authz-casbin' },
- { name: 'HashiCorp Vault', logo: '/img/integrations/vault.svg', href: '/docs/apisix/terminology/secret/' },
- ],
- },
- {
- title: 'AI & LLM providers',
- items: [
- { name: 'OpenAI', href: '/docs/apisix/plugins/ai-proxy/' },
- { name: 'Anthropic', href: '/docs/apisix/plugins/ai-proxy/' },
- { name: 'AWS Bedrock', href: '/docs/apisix/plugins/ai-proxy/' },
- { name: 'DeepSeek', href: '/docs/apisix/plugins/ai-proxy/' },
- { name: 'Ollama', href: '/docs/apisix/plugins/ai-proxy/' },
- ],
- },
-];
-
-const IntegrationTile: FC<{ item: Integration }> = ({ item }) => {
- const href = item.href ?? (item.icon ? `/docs/apisix/plugins/${item.icon}/` : undefined);
- const inner = (
- <>
- {item.logo ? (
- <img className="integrations__img" src={item.logo} alt={item.name} loading="lazy" width={30} height={30} />
- ) : item.icon ? (
- <svg className="integrations__icon" aria-hidden="true">
- <use xlinkHref={`#icon${item.icon}`} />
- </svg>
- ) : null}
- <span className="integrations__name">{item.name}</span>
- </>
- );
- return href ? (
- <Link className="integrations__tile" to={href} title={item.name} target="_blank" rel="noopener noreferrer">
- {inner}
- </Link>
- ) : (
- <div className="integrations__tile" title={item.name}>
- {inner}
- </div>
- );
-};
-
-const Integrations: FC = () => (
- <section className="integrations" aria-labelledby="integrations-heading">
- <Head>
- {/* Injects the shared plugin icon sprite used by #icon<name> references. */}
- <script src="/js/plugin-icon.js" defer />
- </Head>
- <h2 id="integrations-heading" className="integrations__heading">
- <Translate id="home.integrations.title">Integrates with your stack</Translate>
- </h2>
- <p className="integrations__subtitle">
- <Translate id="home.integrations.subtitle">
- Connect APISIX to your observability, security, service discovery, and AI tools through 100+ plugins.
- </Translate>
- </p>
- <div className="integrations__tiles">
- {GROUPS.flatMap((group) => group.items).map((item) => (
- <IntegrationTile item={item} key={item.name} />
- ))}
- </div>
- <Link className="integrations__cta" to="/plugins/" target="_blank" rel="noopener noreferrer">
- <Translate id="home.integrations.cta">Explore all 100+ plugins</Translate>
- {' →'}
- </Link>
- </section>
-);
-
-export default Integrations;
diff --git a/website/src/components/sections/OpensourcePromo.tsx b/website/src/components/sections/OpensourcePromo.tsx
deleted file mode 100644
index 5ebca9d5b69..00000000000
--- a/website/src/components/sections/OpensourcePromo.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Link from '@docusaurus/Link';
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
-import Translate from '@docusaurus/Translate';
-
-import BrowserOnly from '@docusaurus/BrowserOnly';
-import type { VideoProps } from '../Video';
-import style from '../../css/landing-sections/os-promo.module.scss';
-
-const VideoChannel: FC = () => {
- const {
- i18n: { currentLocale },
- } = useDocusaurusContext();
-
- if (currentLocale.startsWith('zh')) {
- return <a href="https://space.bilibili.com/551921247" target="_blank" rel="noopener noreferrer">哔哩哔哩官方账号</a>;
- }
-
- return (
- <a href="https://www.youtube.com/channel/UCgPD18cMhOg5rmPVnQhAC8g" target="_blank" rel="noopener noreferrer">
- <Translate id="openSourcePromo.component.link.Youtube">YouTube channel</Translate>
- </a>
- );
-};
-
-const videoOptions: VideoProps['options'] = {
- controls: true,
- fluid: true,
- preload: 'none',
- poster: 'https://static.apiseven.com/202202/apisix-video-poster.jpeg',
- sources: [
- {
- src: 'https://static.apiseven.com/apisix-website/videos/apisix-video/apisix-bobur.m3u8',
- type: 'application/x-mpegURL',
- },
- ],
- width: 640,
- height: 360,
-};
-
-const LazyLoadVideo = () => (
- <BrowserOnly>
- {() => {
- // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
- const Video = require('../Video').default;
- return <Video options={videoOptions} />;
- }}
- </BrowserOnly>
-);
-
-const OpensourcePromo: FC = () => (
- <div className={style.osPromotion}>
- <div className={style.docsPromo}>
- <div className={style.docsPromoHead}>
- <h3>
- <Translate id="openSourcePromo.component.title">New to Apache APISIX?</Translate>
- </h3>
- <div className={style.docsPromoSubtitle}>
- <p>
- <Translate id="openSourcePromo.component.subtitle.fragment1">
- New to microservices or API gateways? Get up and running with our
- </Translate>
- {' '}
- <Link style={{ color: '#e8433e' }} to={useBaseUrl('docs')} target="_blank" rel="noopener noreferrer">
- <Translate id="openSourcePromo.component.link.docs">Docs.</Translate>
- </Link>
- </p>
- <p>
- <Translate id="openSourcePromo.component.subtitle.fragment2">
- Prefer to learn by watching? Head to our
- </Translate>
- {' '}
- <VideoChannel />
- {' '}
- <Translate id="openSourcePromo.component.subtitle.fragment3">
- for step-by-step video tutorials.
- </Translate>
- </p>
- </div>
- </div>
- <div className={style.docsPromoVideo}>
- <LazyLoadVideo />
- </div>
- </div>
- </div>
-);
-
-export default OpensourcePromo;
diff --git a/website/src/components/sections/Pathways.tsx b/website/src/components/sections/Pathways.tsx
deleted file mode 100644
index 270292fc6e2..00000000000
--- a/website/src/components/sections/Pathways.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import type { FC } from 'react';
-import React from 'react';
-import Link from '@docusaurus/Link';
-import Translate from '@docusaurus/Translate';
-
-import '../../css/landing-sections/pathways.scss';
-
-interface Pathway {
- id: string;
- title: JSX.Element;
- description: JSX.Element;
- cta: JSX.Element;
- to: string;
-}
-
-const PATHWAYS: Pathway[] = [
- {
- id: 'build',
- to: '/docs/apisix/getting-started/',
- title: <Translate id="home.pathways.build.title">Get started</Translate>,
- description: (
- <Translate id="home.pathways.build.desc">
- Install APISIX and configure your first route in minutes.
- </Translate>
- ),
- cta: <Translate id="home.pathways.build.cta">Read the docs</Translate>,
- },
- {
- id: 'learn',
- to: '/learning-center/',
- title: <Translate id="home.pathways.learn.title">Learn the concepts</Translate>,
- description: (
- <Translate id="home.pathways.learn.desc">
- API gateway, AI gateway, rate limiting, mTLS, Kubernetes and more.
- </Translate>
- ),
- cta: <Translate id="home.pathways.learn.cta">Explore the learning center</Translate>,
- },
- {
- id: 'case-studies',
- to: '/blog/tags/case-studies/',
- title: <Translate id="home.pathways.cases.title">Case studies</Translate>,
- description: (
- <Translate id="home.pathways.cases.desc">
- See how teams run Apache APISIX in production at scale.
- </Translate>
- ),
- cta: <Translate id="home.pathways.cases.cta">Read case studies</Translate>,
- },
-];
-
-const Pathways: FC = () => (
- <section className="pathways" aria-label="Get started with Apache APISIX">
- {PATHWAYS.map((pathway) => (
- <Link className="pathways__card" to={pathway.to} key={pathway.id} target="_blank" rel="noopener noreferrer">
- <h3 className="pathways__title">{pathway.title}</h3>
- <p className="pathways__desc">{pathway.description}</p>
- <span className="pathways__cta">
- {pathway.cta}
- {' →'}
- </span>
- </Link>
- ))}
- </section>
-);
-
-export default Pathways;
diff --git a/website/src/css/landing-sections/ai-gateway-home.scss b/website/src/css/landing-sections/ai-gateway-home.scss
deleted file mode 100644
index 8bb5ccd459b..00000000000
--- a/website/src/css/landing-sections/ai-gateway-home.scss
+++ /dev/null
@@ -1,157 +0,0 @@
-.ai-home {
- background: #faf7f7;
- padding: 4rem var(--ifm-spacing-horizontal);
-}
-
-.ai-home__inner {
- max-width: 1000px;
- margin: 0 auto;
- text-align: center;
-}
-
-.ai-home__eyebrow {
- display: inline-block;
- font-size: 0.82rem;
- font-weight: 600;
- letter-spacing: 0.05em;
- text-transform: uppercase;
- color: #a32d2d;
- background: #fcebeb;
- padding: 5px 14px;
- border-radius: 20px;
- margin-bottom: 1rem;
-}
-
-.ai-home__title {
- font-size: clamp(1.6rem, 1rem + 2vw, 2.25rem);
- font-weight: 700;
- margin-bottom: 0.5rem;
-}
-
-.ai-home__subtitle {
- color: #6b6b6b;
- max-width: 680px;
- margin: 0 auto 2.25rem;
- font-size: 1rem;
- line-height: 1.6;
-}
-
-.ai-home__flow {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 0.75rem;
- flex-wrap: wrap;
- margin-bottom: 2.5rem;
-}
-
-.ai-home__node {
- background: #fff;
- border: 1px solid #e6e6e6;
- border-radius: 8px;
- padding: 8px 14px;
- font-size: 0.9rem;
- font-weight: 500;
- color: #2c2c2a;
-}
-
-.ai-home__node--apisix {
- background: #e8433e;
- border-color: #e8433e;
- color: #fff;
- font-weight: 700;
-}
-
-.ai-home__arrow {
- color: #e8433e;
- font-weight: 700;
-}
-
-.ai-home__providers {
- display: flex;
- gap: 6px;
- flex-wrap: wrap;
- justify-content: center;
-}
-
-.ai-home__provider {
- background: #fff;
- border: 1px solid #e6e6e6;
- border-radius: 20px;
- padding: 6px 12px;
- font-size: 0.82rem;
- color: #444;
-}
-
-.ai-home__provider--more {
- color: #888;
-}
-
-.ai-home__grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 1rem;
- text-align: left;
-}
-
-@media (max-width: 820px) {
- .ai-home__grid {
- grid-template-columns: 1fr;
- }
-}
-
-.ai-home__card {
- display: block;
- background: #fff;
- border: 1px solid #ececec;
- border-radius: 12px;
- padding: 1.25rem 1.3rem;
- color: inherit;
- text-decoration: none;
- transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
-
- &:hover {
- transform: translateY(-3px);
- border-color: #f3b6b3;
- box-shadow: 0 6px 18px rgb(232 67 62 / 8%);
- color: inherit;
- text-decoration: none;
- }
-
- &:hover .ai-home__card-title {
- color: #e8433e;
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .ai-home__card:hover {
- transform: none;
- }
-}
-
-.ai-home__card-title {
- font-size: 1.05rem;
- font-weight: 700;
- margin: 0 0 0.4rem;
- color: #1c1c1c;
-}
-
-.ai-home__card-desc {
- font-size: 0.9rem;
- line-height: 1.55;
- color: #6b6b6b;
- margin: 0;
-}
-
-.ai-home__cta {
- display: inline-block;
- margin-top: 2rem;
- font-size: 1rem;
- font-weight: 600;
- color: #e8433e;
-
- &:hover {
- color: #c7352f;
- text-decoration: none;
- }
-}
diff --git a/website/src/css/landing-sections/architecture.scss b/website/src/css/landing-sections/architecture.scss
deleted file mode 100644
index 51bc3642e4e..00000000000
--- a/website/src/css/landing-sections/architecture.scss
+++ /dev/null
@@ -1,114 +0,0 @@
-@import '../util';
-
-.hldesign {
- height: 100%;
- display: flex;
- justify-content: center;
-}
-
-.hldesign-graphic {
- width: 60%;
- height: auto;
-}
-
-.Architecture_svg__architecture {
- font-family: MaisonNeue-Medium, sans-serif;
-}
-
-.arch {
- background: linear-gradient(180deg, #e2ecff 15%, #fff 90%);
- position: relative;
- z-index: 1;
- padding: 50px 0;
- overflow: hidden;
-}
-
-.arch-card-caption {
- height: 100%;
- display: flex;
- justify-content: center;
- color: #615d5d;
-}
-
-.arch-card-caption > p {
- width: 90%;
- letter-spacing: 0.2px;
- font-family: MaisonNeue-Light, sans-serif;
- font-weight: 700;
- text-align: center;
- position: relative;
- bottom: -15px;
- font-size: 1rem;
-}
-
-.arch-card-border {
- z-index: -10;
- position: absolute;
- width: 66%;
- height: 100%;
- border-style: solid;
- top: 15px;
- left: 17%;
- border-color: white;
- background: white;
- filter: drop-shadow(0 4px 10px rgb(0 0 0 / 25%));
-}
-
-.arch-head,
-.testimonials-head,
-.docs-promo-head {
- font-size: 2.4rem;
- position: relative;
- left: 16.8%;
- width: 83.2%;
-}
-
-.arch-subtitle,
-.testimonials-subtitle,
-.docs-promo-subtitle {
- font-size: 1.13rem;
- position: relative;
- left: 16.8%;
- width: 70%;
- color: #615d5d;
- letter-spacing: 0.2px;
- font-family: MaisonNeue-Light, sans-serif;
- font-weight: 700;
-}
-
-.add-left-margin {
- position: relative;
- left: 16.8%;
-}
-
-@include respond-between(sm, md) {
- .hldesign-graphic {
- width: 100%;
- }
-
- .arch-scale-svg {
- display: none;
- }
-
- .arch-card-border {
- width: 100%;
- left: 0;
- top: 10px;
- }
-
- .arch-head,
- .testimonials-head,
- .docs-promo-head,
- .oss-promo-head {
- left: 7%;
- width: 83%;
- }
-
- .arch-subtitle,
- .testimonials-subtitle,
- .docs-promo-subtitle,
- .oss-promo-subtitle {
- left: 7%;
- width: 85%;
- }
-}
diff --git a/website/src/css/landing-sections/benefits.scss b/website/src/css/landing-sections/benefits.scss
deleted file mode 100644
index 8e51831be71..00000000000
--- a/website/src/css/landing-sections/benefits.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-.row-benefit {
- margin: 100px 5px;
- display: flex;
- justify-content: center;
- align-items: center;
- height: fit-content;
-}
-
-.benefit {
- background: #fff8f6;
- padding: 50px 0;
-}
-
-.benefit-infograph {
- width: 50%;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.feat-head-desc {
- font-size: 1.4rem;
- color: #363130;
- opacity: 0.5;
- position: relative;
- left: 17%;
- margin: 0;
- line-height: 1.8;
- width: fit-content;
-}
-
-.feat-desc {
- margin: 10px 0;
- font-size: 1.13rem;
- color: #615d5d;
- font-family: MaisonNeue-Light, sans-serif;
- width: 65%;
- left: 17%;
-}
diff --git a/website/src/css/landing-sections/comparison.scss b/website/src/css/landing-sections/comparison.scss
deleted file mode 100644
index 9131ed9ffb8..00000000000
--- a/website/src/css/landing-sections/comparison.scss
+++ /dev/null
@@ -1,95 +0,0 @@
-.compare {
- max-width: 900px;
- margin: 0 auto;
- padding: 3.5rem var(--ifm-spacing-horizontal);
- text-align: center;
-}
-
-.compare-head {
- font-size: clamp(1.6rem, 1rem + 2vw, 2.25rem);
- font-weight: 700;
- max-width: 760px;
- margin: 0 auto 0.5rem;
-}
-
-.compare-subtitle {
- color: #6b6b6b;
- max-width: 640px;
- margin: 0 auto 2.25rem;
- font-size: 1rem;
- line-height: 1.6;
-}
-
-.compare-table-wrap {
- overflow-x: auto;
-}
-
-.compare-table {
- width: fit-content;
- max-width: 100%;
- margin: 0 auto;
- border-collapse: separate;
- border-spacing: 0;
- background: #fff;
- border: 1px solid #ececec;
- border-radius: 12px;
- overflow: hidden;
- font-size: 1rem;
-}
-
-.compare-table th,
-.compare-table td {
- padding: 0.95rem 1.1rem;
- text-align: center;
- border-bottom: 1px solid #f0f0f0;
-}
-
-.compare-table tbody tr:last-child th,
-.compare-table tbody tr:last-child td {
- border-bottom: none;
-}
-
-.compare-table thead th {
- font-weight: 700;
- font-size: 1.02rem;
- background: #fafafa;
- border-bottom: 1px solid #ececec;
-}
-
-.compare-table tbody th[scope="row"] {
- font-weight: 500;
- color: #2c2c2a;
-}
-
-.compare-col-feature {
- text-align: left;
-}
-
-.compare-col-apisix,
-.compare-apisix-cell {
- background: #fff5f4;
-}
-
-.compare-col-apisix {
- color: #e8433e;
-}
-
-.compare-col-apisix,
-.compare-col-other {
- min-width: 160px;
-}
-
-.compare-apisix-cell {
- font-weight: 700;
- color: #1c1c1c;
-}
-
-.compare-other-cell {
- color: #8a8a8a;
-}
-
-.compare-table svg {
- width: 22px;
- height: 22px;
- vertical-align: middle;
-}
diff --git a/website/src/css/landing-sections/endcta.module.scss b/website/src/css/landing-sections/endcta.module.scss
deleted file mode 100644
index e8a0f320456..00000000000
--- a/website/src/css/landing-sections/endcta.module.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-@import "../util";
-
-$apisix-color: #e8433e;
-
-.endcta {
- padding: max(14vh, 100px) 2rem;
- margin: 4em 10% 0;
- background-color: #f8f8f8;
- display: flex;
- flex-direction: column;
- align-items: center;
- overflow: hidden;
- border-radius: 1em;
-
- & .text {
- display: flex;
- justify-content: center;
- align-items: center;
- white-space: pre;
- text-transform: capitalize;
- font-size: 4.5rem;
- font-weight: bolder;
- font-family: MaisonNeue-ExtraBold, sans-serif;
- position: relative;
- width: fit-content;
-
- & .apisix {
- color: $apisix-color;
- }
-
- & .rocket {
- $size: 10rem;
-
- position: absolute;
- right: -#{$size};
- width: $size;
- height: $size;
- bottom: 0.3em;
- transform: rotate(45deg);
- }
- }
-
- & .links {
- display: flex;
- }
-
- @include respond-below(lg) {
- & .text {
- & .rocket {
- display: none;
- }
- }
- }
-
- @include respond-below(sm) {
- min-height: 50vh;
- margin: 4rem 1rem 0;
- align-items: flex-start;
- padding: 100px 2rem;
-
- & .text {
- flex-direction: column;
- font-size: 2.5rem;
- align-items: flex-start;
-
- & .apisix {
- margin: -1rem 0;
- }
- }
- }
-}
diff --git a/website/src/css/landing-sections/features.module.scss b/website/src/css/landing-sections/features.module.scss
deleted file mode 100644
index 9694c585167..00000000000
--- a/website/src/css/landing-sections/features.module.scss
+++ /dev/null
@@ -1,322 +0,0 @@
-@import "../util";
-
-.dashboardLink {
- color: hsl(0deg 0% 80%);
- width: fit-content;
-
- &:hover {
- color: hsl(0deg 0% 80%);
- }
-}
-
-.dashboard {
- background-color: hsl(0deg 100% 0%);
- font-family: MaisonNeue-Bold, sans-serif;
- margin-left: -9px;
-
- --height: 130px;
- --width: calc(var(--height) * 2.048);
- --radius: calc(var(--height) * 0.168);
-
- height: var(--height);
- width: var(--width);
- border-radius: var(--radius);
- padding: calc(var(--radius) - 6px);
- display: flex;
- flex-direction: column;
- position: relative;
- overflow: hidden;
- transform: scale3d(0.95, 0.95, 1);
- transition: all 200ms cubic-bezier(0.65, 0.05, 0.36, 1);
-
- &::before {
- content: "";
- width: calc(100% - 6px);
- height: calc(100% - 6px);
- border-radius: inherit;
- position: absolute;
- top: 3px;
- left: 3px;
- backdrop-filter: blur(2px);
- opacity: 0;
- transition: opacity 300ms ease-in-out;
- }
-
- &::after {
- content: "APISIX";
- position: absolute;
- top: 5px;
- left: -35%;
- font-size: 8.5rem;
- font-weight: bolder;
- line-height: 1;
- color: #fff;
- opacity: 0.1;
- }
-
- & .dashboardTitle {
- font-size: 1.35rem;
- font-family: MaisonNeue-ExtraBold, sans-serif;
- white-space: nowrap;
- flex-grow: 1;
- background-image:
- linear-gradient(
- 135deg,
- hsl(0deg 73% 50%),
- hsl(227deg 90% 65%)
- );
- background-clip: text;
- -webkit-text-fill-color: transparent;
- width: fit-content;
- position: relative;
- }
-
- & .dashboardAccount {
- font-variant: small-caps;
- line-height: normal;
- letter-spacing: 1px;
- position: relative;
- opacity: 0.8;
-
- &::after {
- content: "↑";
- font-family: MaisonNeue-Light, sans-serif;
- font-size: 2.5rem;
- line-height: 2rem;
- position: absolute;
- top: 2px;
- right: 8px;
- opacity: 0;
- color: hsl(0deg 0% 70%);
- transform: rotate(90deg);
- transition: opacity 300ms ease-in-out;
- }
- }
-
- &:hover {
- transform: scale3d(1, 1, 1);
- box-shadow:
- 0 0 0 1px hsl(213deg 26% 28% / 2%),
- 0 3px 2px hsl(0deg 0% 0% / 14%),
- 0 7px 5px hsl(0deg 0% 0% / 12%),
- 0 13px 10px hsl(0deg 0% 0% / 5%),
- 0 22px 17px hsl(0deg 0% 0% / 8%);
-
- & .dashboardTitle {
- animation: pulse 3s linear infinite;
- }
-
- & .dashboardAccount {
- opacity: 0.9;
-
- &::after {
- opacity: 0.6;
- animation: bounce 1.8s ease-in-out infinite;
- }
- }
- }
-
- &:active {
- transform: scale3d(0.95, 0.95, 1);
- }
-}
-
-@keyframes pulse {
- from {
- filter: hue-rotate(0);
- }
-
- to {
- filter: hue-rotate(360deg);
- }
-}
-
-@keyframes bounce {
- from,
- 20%,
- 53%,
- to {
- animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- transform: rotate(90deg) translate3d(0, 0, 0);
- }
-
- 40%,
- 43% {
- animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
- transform: rotate(90deg) translate3d(0, 30px, 0) scaleY(1.1);
- }
-
- 70% {
- animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
- transform: rotate(90deg) translate3d(0, 15px, 0) scaleY(1.05);
- }
-
- 80% {
- transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- transform: rotate(90deg) translate3d(0, 0, 0) scaleY(0.95);
- }
-
- 90% {
- transform: rotate(90deg) translate3d(0, 4px, 0) scaleY(1.02);
- }
-}
-
-.features {
- width: 100%;
- margin: 6rem 0 2rem;
- hyphens: auto;
- position: relative;
-
- & .head {
- padding: 0 10%;
- margin-bottom: 0;
-
- h2 {
- background-color: rgb(232 67 62);
- display: block;
- width: fit-content;
- color: white;
- padding: 6px 20px;
- border-radius: 50rem;
- }
-
- h3 {
- font-size: 3.25rem;
- }
-
- p {
- font-size: 1.5rem;
- color: hsl(0deg 0% 78%);
- }
- }
-
- & .container {
- display: flex;
- flex-direction: column;
-
- & .feat {
- display: flex;
- height: 100vh;
-
- & .left,
- & .right {
- display: flex;
- width: 50%;
- }
-
- & .left {
- padding-right: 5%;
- justify-content: flex-end;
- align-items: center;
-
- & > section {
- display: flex;
- flex-direction: column;
- width: 500px;
-
- h2 {
- font-size: 3.25rem;
- }
-
- & > div,
- & > p {
- font-size: 1.25rem;
- margin-bottom: 4em;
-
- & .action {
- display: flex;
- margin-top: 1em;
- }
- }
- }
- }
-
- & .right {
- flex-shrink: 0;
-
- img {
- object-position: left top;
- object-fit: cover;
- height: 80vh;
- align-self: center;
- border: 1px solid hsl(0deg 0% 0% / 12%);
- border-radius: 1rem 0 0 1rem;
- }
- }
- }
- }
-
- @include respond-below(md) {
- margin: 4rem 1rem;
- align-items: flex-start;
-
- & .container {
- & .feat {
- flex-direction: column;
- height: auto;
-
- & .left,
- & .right {
- width: 100%;
- justify-content: flex-start;
- padding: 0 10%;
- }
-
- & .left {
- & > section {
- width: auto;
-
- div {
- margin-bottom: 0;
- }
- }
- }
-
- & .right {
- img {
- height: 50vh;
- border-radius: 1rem;
- margin: 1rem 0 4rem;
- }
- }
- }
- }
- }
-
- @include respond-below(sm) {
- width: auto;
-
- & .head {
- padding: 0;
-
- h2 {
- font-size: 1.25rem;
- }
-
- h3 {
- font-size: 2.25rem;
- }
-
- p {
- font-size: 1rem;
- }
- }
-
- & .container {
- & .feat {
- & .left,
- & .right {
- padding: 0;
- }
-
- & .left {
- & > section {
- h2 {
- font-size: 2.25rem;
- }
- }
- }
- }
- }
- }
-}
diff --git a/website/src/css/landing-sections/hero.scss b/website/src/css/landing-sections/hero.scss
deleted file mode 100644
index 29fecfbbe81..00000000000
--- a/website/src/css/landing-sections/hero.scss
+++ /dev/null
@@ -1,249 +0,0 @@
-@import "../util";
-
-@keyframes fade-in-up {
- from {
- opacity: 0;
- transform: translate3d(0, 50%, 0);
- }
-
- to {
- opacity: 1;
- transform: translate3d(0, 0, 0);
- }
-}
-
-.hero-title,
-.hero-subtitle,
-.hero-ctas {
- animation-name: fade-in-up;
- animation-fill-mode: both;
- animation-delay: 0s;
- animation-duration: 1s;
-}
-
-.hero-subtitle {
- z-index: 100;
- font-size: 1.15rem;
- font-family: MaisonNeue-Light, sans-serif;
- position: relative;
- color: #5f5d5d;
- line-height: 1.6;
- letter-spacing: 0.2px;
- max-width: 620px;
- margin: 1.25rem 0 0;
- animation-delay: 0.2s;
-}
-
-.hero-ctas {
- display: flex;
- align-items: center;
- justify-content: center;
- flex-wrap: wrap;
- gap: 12px;
- margin-top: 1.75rem;
- animation-delay: 0.4s;
-}
-
-.hero-sec-wrap {
- display: flex;
- justify-content: center;
- background: #f7f7f8;
- padding: clamp(3rem, 9vh, 7rem) 24px clamp(2.5rem, 7vh, 5rem);
-}
-
-.hero-text {
- width: 100%;
- max-width: 780px;
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
-}
-
-.hero-title {
- font-family: MaisonNeue-Bold, sans-serif;
- color: #121212;
- max-width: 780px;
- font-size: clamp(2.4rem, 1rem + 4.2vw, 4rem);
- line-height: 1.08;
- letter-spacing: 0.2px;
- margin: 0;
-}
-
-.btn {
- background: #030c16;
- border-style: solid;
- border-width: 1px;
- border: none;
- color: white;
- padding: 5px 20px;
- border-radius: 20px;
- font-size: 1rem;
- text-decoration: none;
- margin: 0 10px 0 0;
- transition: all 0.3s;
-}
-
-.btn:hover {
- background: #9b9b9b;
- color: white;
- text-decoration: none;
-}
-
-.btn-docs {
- display: flex;
- flex-direction: row;
- align-items: center;
-}
-
-.btn-docs:hover {
- text-decoration: none;
-}
-
-.btn-docs .goto {
- color: #000;
-}
-
-.btn-docs:hover .goto,
-.btn-docs:active .goto {
- opacity: 0.8;
-}
-
-.btn-docs .arrow {
- width: 30px;
- height: 30px;
- position: relative;
-}
-
-.btn-docs .arrow svg {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-}
-
-.btn-docs .arrow polygon,
-.btn-docs .arrow rect {
- transition: all 250ms;
-}
-
-.btn-docs .arrow rect {
- opacity: 0;
-}
-
-.btn-docs:hover .arrow polygon {
- transform: translateX(100px);
-}
-
-.btn-docs:hover .arrow rect {
- transform: translateX(240px);
- opacity: 1;
-}
-
-@include respond-between(md, lg) {
- .hero-title {
- font-size: clamp(3rem, 1rem + 5vw, 4.5rem);
- }
-}
-
-@media (max-width: 996px) {
- .hero-title,
- .hero-subtitle,
- .hero-ctas {
- animation: none;
- }
-
- .hero-sec-wrap {
- min-height: calc(100svh - var(--ifm-navbar-height));
- height: auto;
- padding: 72px 0 48px;
- }
-
- .hero-text {
- width: 100%;
- padding: 0 24px;
- align-content: center;
- }
-
- .hero-title {
- width: 100%;
- max-width: 680px;
- font-size: clamp(2.4rem, 12vw, 4.2rem);
- line-height: 1.05;
- }
-
- .hero-subtitle {
- width: 100%;
- max-width: 680px;
- padding-right: 0;
- margin: 18px 0;
- }
-
- .hero-ctas {
- flex-wrap: wrap;
- gap: 12px;
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .hero-title,
- .hero-subtitle,
- .hero-ctas {
- animation: none;
- }
-}
-
-.hero-eyebrow {
- display: inline-block;
- font-size: 0.82rem;
- font-weight: 600;
- color: #a32d2d;
- background: #fcebeb;
- padding: 5px 14px;
- border-radius: 20px;
- margin-bottom: 1.25rem;
-}
-
-.btn-secondary {
- background: #fff;
- color: #1c1c1c;
- border: 1px solid #d6d6d6;
-}
-
-.btn-secondary:hover {
- background: #f1f1f1;
- color: #1c1c1c;
- border-color: #c0c0c0;
-}
-
-.hero-stats {
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- gap: 1.5rem 2.5rem;
- list-style: none;
- width: 100%;
- max-width: 640px;
- margin: 2.25rem 0 0;
- padding: 1.5rem 0 0;
- border-top: 1px solid #e6e6e6;
-}
-
-.hero-stats__item {
- display: flex;
- flex-direction: column;
- align-items: center;
-}
-
-.hero-stats__value {
- font-size: 1.5rem;
- font-weight: 700;
- color: #e8433e;
- line-height: 1.1;
-}
-
-.hero-stats__label {
- font-size: 0.85rem;
- color: #777;
- margin-top: 2px;
-}
diff --git a/website/src/css/landing-sections/home-events.module.scss b/website/src/css/landing-sections/home-events.module.scss
deleted file mode 100644
index f4cc5bb66ce..00000000000
--- a/website/src/css/landing-sections/home-events.module.scss
+++ /dev/null
@@ -1,146 +0,0 @@
-@import '../util';
-
-$transition-duration: 200ms;
-
-.arrow {
- $size: 25px;
-
- width: $size;
- height: $size;
- position: relative;
- margin-bottom: 0.5px;
-
- svg {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate3d(-50%, -50%, 0);
- overflow: visible;
- }
-
- polygon,
- rect {
- transition: all $transition-duration ease-in-out;
- }
-
- rect {
- opacity: 0;
- }
-}
-
-.homeEvents {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin: 8em 10%;
-
- h3 {
- font-size: 2.4rem;
- }
-
- p {
- color: #615d5d;
- font-size: 1.13rem;
- letter-spacing: 0.2px;
- font-family: MaisonNeue-Light, sans-serif;
- font-weight: 700;
- }
-
- & .events {
- display: flex;
- justify-content: center;
-
- & .eventCard {
- display: flex;
- flex-direction: column;
- font-size: 0.9rem;
- height: 200px;
- width: 282px;
- transition: all $transition-duration ease-in-out;
- margin: 0 1rem;
- border-radius: 1rem;
- border: 1px solid hsl(210deg 26% 28% / 14%);
- padding: 1rem;
-
- & > time {
- color: hsl(0deg 0% 78%);
- }
-
- & > h4 {
- flex-shrink: 0;
- flex-grow: 1;
- color: hsl(0deg 0% 30%);
- }
-
- & > div {
- color: hsl(0deg 0% 60%);
- display: flex;
- align-items: center;
- }
-
- &:hover {
- transform: scale3d(1.03, 1.03, 1);
-
- polygon {
- transform: translateX(100px) !important;
- }
-
- rect {
- transform: translateX(240px) !important;
- opacity: 1 !important;
- }
- }
- }
- }
-
- .newsletter {
- display: flex;
- font-family: MaisonNeue-Light, sans-serif;
- font-size: 0.95rem;
- color: #615d5d;
- letter-spacing: 0.2px;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- margin: 25px 0;
-
- p {
- margin: 2rem 0 1rem;
- }
- }
-
- .newsButton {
- border: none;
- padding: 5px 30px;
- border-style: solid;
- border-radius: 20px;
- background: #030c16;
- color: white;
- margin: 0;
- text-decoration: none;
- transition: all 0.3s;
-
- &:hover {
- background: #9b9b9b;
- color: white;
- text-decoration: none;
- }
- }
-
- @include respond-below(sm) {
- margin: 4rem 1rem;
- align-items: flex-start;
-
- & .events {
- overflow-x: scroll;
- width: 100%;
- display: flex;
- justify-content: flex-start;
- padding-bottom: 1rem;
-
- & .eventCard {
- flex-shrink: 0;
- }
- }
- }
-}
diff --git a/website/src/css/landing-sections/integrations.scss b/website/src/css/landing-sections/integrations.scss
deleted file mode 100644
index 1d1cfb64469..00000000000
--- a/website/src/css/landing-sections/integrations.scss
+++ /dev/null
@@ -1,89 +0,0 @@
-.integrations {
- max-width: 960px;
- margin: 0 auto;
- padding: 3.5rem var(--ifm-spacing-horizontal) 1rem;
- text-align: center;
-}
-
-.integrations__heading {
- font-size: clamp(1.6rem, 1rem + 2vw, 2.25rem);
- font-weight: 700;
- margin-bottom: 0.5rem;
-}
-
-.integrations__subtitle {
- color: #6b6b6b;
- max-width: 620px;
- margin: 0 auto 2.25rem;
- font-size: 1rem;
- line-height: 1.6;
-}
-
-.integrations__tiles {
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- gap: 0.75rem;
- max-width: 860px;
- margin: 0 auto;
-}
-
-.integrations__tile {
- display: flex;
- align-items: center;
- gap: 0.6rem;
- padding: 0.65rem 1.1rem;
- border: 1px solid #ececec;
- border-radius: 0.75rem;
- background: #fff;
- color: inherit;
- text-decoration: none;
- transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
-
- &:hover {
- transform: translateY(-3px);
- border-color: #f3b6b3;
- box-shadow: 0 6px 18px rgb(232 67 62 / 8%);
- color: inherit;
- text-decoration: none;
- }
-}
-
-.integrations__icon {
- width: 30px;
- height: 30px;
- flex-shrink: 0;
-}
-
-.integrations__img {
- width: 30px;
- height: 30px;
- object-fit: contain;
- flex-shrink: 0;
-}
-
-.integrations__name {
- font-size: 0.95rem;
- font-weight: 500;
- color: #2c2c2a;
- white-space: nowrap;
-}
-
-.integrations__cta {
- display: inline-block;
- margin-top: 2rem;
- font-size: 1rem;
- font-weight: 600;
- color: #e8433e;
-
- &:hover {
- color: #c7352f;
- text-decoration: none;
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .integrations__tile:hover {
- transform: none;
- }
-}
diff --git a/website/src/css/landing-sections/os-promo.module.scss b/website/src/css/landing-sections/os-promo.module.scss
deleted file mode 100644
index 5ea407059b7..00000000000
--- a/website/src/css/landing-sections/os-promo.module.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-@import "../util";
-
-.osPromotion {
- margin: 4rem 10%;
-
- a {
- color: #e8433e;
- }
-
- & .docsPromo {
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- align-items: center;
- background-color: #f8f8f8;
- padding: 60px 40px;
- border-radius: 1rem;
-
- & .docsPromoHead {
- display: flex;
- flex-flow: column;
- max-width: 760px;
- margin-bottom: 2rem;
- text-align: center;
-
- h3 {
- font-size: 2.4rem;
- }
- }
-
- & .docsPromoSubtitle {
- font-size: 1.13rem;
- position: relative;
- color: #615d5d;
- letter-spacing: 0.2px;
- font-family: MaisonNeue-Light, sans-serif;
- font-weight: 700;
- }
-
- & .docsPromoVideo {
- width: 100%;
- max-width: 720px;
- }
- }
-
- @include respond-below(sm) {
- margin: 3rem 1rem;
-
- & .docsPromo {
- padding: 40px 20px;
- }
- }
-}
diff --git a/website/src/css/landing-sections/pathways.scss b/website/src/css/landing-sections/pathways.scss
deleted file mode 100644
index 01312e5d666..00000000000
--- a/website/src/css/landing-sections/pathways.scss
+++ /dev/null
@@ -1,62 +0,0 @@
-.pathways {
- max-width: 1000px;
- margin: 0 auto;
- padding: 1rem var(--ifm-spacing-horizontal) 1.5rem;
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 1.25rem;
-}
-
-@media (max-width: 820px) {
- .pathways {
- grid-template-columns: 1fr;
- }
-}
-
-.pathways__card {
- display: flex;
- flex-direction: column;
- background: #fff;
- border: 1px solid #ececec;
- border-top: 3px solid #e8433e;
- border-radius: 0.75rem;
- padding: 1.6rem 1.4rem;
- color: inherit;
- transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
-
- &:hover {
- transform: translateY(-4px);
- box-shadow: 0 10px 28px rgba(0, 0, 0, 0.07);
- border-color: #f3b6b3;
- border-top-color: #e8433e;
- color: inherit;
- text-decoration: none;
- }
-}
-
-.pathways__title {
- font-size: 1.25rem;
- font-weight: 700;
- margin: 0 0 0.5rem;
- color: #1c1c1c;
-}
-
-.pathways__desc {
- font-size: 0.95rem;
- line-height: 1.55;
- color: #6b6b6b;
- margin: 0 0 1rem;
- flex: 1;
-}
-
-.pathways__cta {
- font-size: 0.95rem;
- font-weight: 600;
- color: #e8433e;
-}
-
-@media (prefers-reduced-motion: reduce) {
- .pathways__card:hover {
- transform: none;
- }
-}
diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx
deleted file mode 100644
index 65a89d98656..00000000000
--- a/website/src/pages/index.tsx
+++ /dev/null
@@ -1,154 +0,0 @@
-import type { FC } from 'react';
-import React, { useEffect } from 'react';
-import useThemeContext from '@theme/hooks/useThemeContext';
-import Layout from '@theme/Layout';
-import Head from '@docusaurus/Head';
-import { translate } from '@docusaurus/Translate';
-import useWindowType from '@theme/hooks/useWindowSize';
-
-import HeroSection from '../components/sections/HeroSection';
-import Architecture from '../components/sections/Architecture';
-import Features from '../components/sections/Features';
-import Benefits from '../components/sections/Benefits';
-import Comparison from '../components/sections/Comparison';
-import OpensourcePromo from '../components/sections/OpensourcePromo';
-import EndCTA from '../components/sections/Endcta';
-import Pathways from '../components/sections/Pathways';
-import Integrations from '../components/sections/Integrations';
-import AIGatewaySection from '../components/sections/AIGatewaySection';
-
-// Structured data for the homepage. Organization + WebSite are already injected
-// globally by config/schema-org.js; these add product-level (SoftwareApplication)
-// and FAQ markup to improve rich results and AI-answer eligibility.
-const SOFTWARE_APPLICATION_SCHEMA = {
- '@context': 'https://schema.org',
- '@type': 'SoftwareApplication',
- name: 'Apache APISIX',
- applicationCategory: 'DeveloperApplication',
- applicationSubCategory: 'API Gateway',
- operatingSystem: 'Linux, Docker, Kubernetes',
- description:
- 'Apache APISIX is a dynamic, high-performance, open-source API gateway and AI gateway with load balancing, authentication, rate limiting, observability, and 100+ plugins.',
- url: 'https://apisix.apache.org/',
- license: 'https://www.apache.org/licenses/LICENSE-2.0',
- isAccessibleForFree: true,
- offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
- author: {
- '@type': 'Organization',
- name: 'The Apache Software Foundation',
- url: 'https://www.apache.org/',
- },
-};
-
-const HOMEPAGE_FAQ_SCHEMA = {
- '@context': 'https://schema.org',
- '@type': 'FAQPage',
- mainEntity: [
- {
- '@type': 'Question',
- name: 'What is Apache APISIX?',
- acceptedAnswer: {
- '@type': 'Answer',
- text: 'Apache APISIX is an open-source, high-performance API gateway and AI gateway. It is a top-level project of the Apache Software Foundation and provides load balancing, authentication, rate limiting, observability, and 100+ plugins for managing API and LLM traffic at scale.',
- },
- },
- {
- '@type': 'Question',
- name: 'Is Apache APISIX free and open source?',
- acceptedAnswer: {
- '@type': 'Answer',
- text: 'Yes. Apache APISIX is licensed under the Apache License 2.0 and is completely free and open source, with no open-core paywall — all plugins and features are available in the open-source project.',
- },
- },
- {
- '@type': 'Question',
- name: 'What is the difference between an API gateway and an AI gateway?',
- acceptedAnswer: {
- '@type': 'Answer',
- text: 'An API gateway manages traffic for general APIs, while an AI gateway adds capabilities optimized for LLM workloads such as multi-provider AI proxying, LLM load balancing, token-based rate limiting, retries and fallback, and prompt security. Apache APISIX provides both.',
- },
- },
- {
- '@type': 'Question',
- name: 'Does Apache APISIX support Kubernetes?',
- acceptedAnswer: {
- '@type': 'Answer',
- text: 'Yes. Apache APISIX runs on Kubernetes and provides an Ingress Controller, along with Helm charts and a Docker image for cloud-native deployments.',
- },
- },
- ],
-};
-
-const ThemeResetComponent = () => {
- const { isDarkTheme, setLightTheme } = useThemeContext();
- const windowType = useWindowType();
-
- useEffect(() => {
- if (windowType === 'mobile') {
- // remove mode switch at navbar-sidebar
- const sidebarModeSwitch = document.querySelector('div.navbar-sidebar__brand > div') as HTMLDivElement;
- if (sidebarModeSwitch) {
- sidebarModeSwitch.style.display = 'none';
- }
- } else {
- // remove mode switch at navbar
- const navbarModeSwitch = document.querySelector('div.navbar__items.navbar__items--right > div.react-toggle') as HTMLDivElement;
- if (navbarModeSwitch) {
- navbarModeSwitch.style.display = 'none';
- }
- }
- }, [windowType]);
-
- useEffect(() => {
- if (isDarkTheme) {
- setLightTheme();
- }
- }, [isDarkTheme]);
-
- return (null);
-};
-
-const Index: FC = () => (
- <Layout>
- <ThemeResetComponent />
- <Head>
- <title>{translate({ id: 'homepage.meta.title', message: 'Apache APISIX - Open Source API Gateway & AI Gateway' })}</title>
- <link rel="canonical" href="https://apisix.apache.org/" />
- <meta
- name="description"
- content="Apache APISIX is a dynamic, high-performance, open-source API gateway and AI gateway. Features include load balancing, authentication, rate limiting, AI proxying, LLM load balancing, and 100+ plugins."
- />
- <meta
- property="og:title"
- content="Apache APISIX - Open Source API Gateway & AI Gateway"
- />
- <meta
- property="og:description"
- content="Apache APISIX is a dynamic, high-performance, open-source API gateway and AI gateway. Features include load balancing, authentication, rate limiting, AI proxying, LLM load balancing, and 100+ plugins."
- />
- <meta property="og:url" content="https://apisix.apache.org/" />
- <meta
- name="twitter:title"
- content="Apache APISIX - Open Source API Gateway & AI Gateway"
- />
- <meta
- name="twitter:description"
- content="Apache APISIX is a dynamic, high-performance, open-source API gateway and AI gateway. Features include load balancing, authentication, rate limiting, AI proxying, LLM load balancing, and 100+ plugins."
- />
- <script type="application/ld+json">{JSON.stringify(SOFTWARE_APPLICATION_SCHEMA)}</script>
- <script type="application/ld+json">{JSON.stringify(HOMEPAGE_FAQ_SCHEMA)}</script>
- </Head>
- <HeroSection />
- <Pathways />
- <AIGatewaySection />
- <Architecture />
- <Features />
- <Integrations />
- <Benefits />
- <Comparison />
- <OpensourcePromo />
- <EndCTA />
- </Layout>
-);
-
-export default Index;