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:30 UTC
(apisix-website) branch feat/astro-wave2 created (now b8f16f193e4)
This is an automated email from the ASF dual-hosted git repository.
moonming pushed a change to branch feat/astro-wave2
in repository https://gitbox.apache.org/repos/asf/apisix-website.git
at b8f16f193e4 feat: serve blog, learning center, and articles from the static build (wave 2)
This branch includes the following new commits:
new b8f16f193e4 feat: serve blog, learning center, and articles from the static build (wave 2)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(apisix-website) 01/01: feat: serve blog, learning center, and articles from the static build (wave 2)
Posted by we...@apache.org.
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;