This is an automated email from the ASF dual-hosted git repository.
bzp2010 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-website.git
The following commit(s) were added to refs/heads/master by this push:
new 9b95d48a4ae refactor: optimize landing page (#1170)
9b95d48a4ae is described below
commit 9b95d48a4ae8d657b0d48ddfe5a01ab31e26a8cd
Author: Young <[email protected]>
AuthorDate: Wed Jun 29 18:14:29 2022 +0800
refactor: optimize landing page (#1170)
---
package.json | 3 +-
website/config/ssrTemplate.js | 10 +-
website/i18n/zh/code.json | 9 +-
website/src/components/HeroCanvas.tsx | 56 ++-
website/src/components/OssCanvas.tsx | 142 ------
website/src/components/sections/Features.tsx | 513 ++++++++++-----------
website/src/components/sections/HeroSection.tsx | 24 +-
.../src/components/sections/OpensourcePromo.tsx | 35 +-
website/src/css/customTheme.css | 43 +-
9 files changed, 360 insertions(+), 475 deletions(-)
diff --git a/package.json b/package.json
index 236af8760a5..1eeda13fa22 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"update-sitemap": "yarn workspace scripts update-sitemap",
"start": "yarn workspace website start",
"build": "yarn workspace website build",
+ "preview-build": "preview=true yarn workspace website build",
"docusaurus": "yarn workspace website docusaurus",
"serve": "yarn docusaurus serve",
"prepare": "husky install",
@@ -38,4 +39,4 @@
"*.{yml,yaml}": "eslint --cache --fix",
"*.css": "stylelint --cache --fix"
}
-}
\ No newline at end of file
+}
diff --git a/website/config/ssrTemplate.js b/website/config/ssrTemplate.js
index ba9c8e3f42d..1cba3d83886 100644
--- a/website/config/ssrTemplate.js
+++ b/website/config/ssrTemplate.js
@@ -13,11 +13,11 @@ module.exports = {
<% it.metaAttributes.forEach((metaAttribute) => { %>
<%~ metaAttribute %>
<% }); %>
- <% it.stylesheets.forEach((stylesheet) => { %>
- <link rel="stylesheet"
href="https://apisix-website-static.apiseven.com<%= it.baseUrl %><%= stylesheet
%>" />
- <% }); %>
<% it.scripts.forEach((script) => { %>
- <link rel="preload"
href="https://apisix-website-static.apiseven.com<%= it.baseUrl %><%= script %>"
as="script">
+ <link rel="preload" href="<%= process.env.preview ? '' :
'https://apisix-website-static.apiseven.com' %><%= it.baseUrl %><%= script %>"
as="script">
+ <% }); %>
+ <% it.stylesheets.forEach((stylesheet) => { %>
+ <link rel="stylesheet" href="<%= process.env.preview ? '' :
'https://apisix-website-static.apiseven.com' %><%= it.baseUrl %><%= stylesheet
%>" />
<% }); %>
<!-- Matomo from the ASF -->
<script>
@@ -45,7 +45,7 @@ module.exports = {
<%~ it.appHtml %>
</div>
<% it.scripts.forEach((script) => { %>
- <script src="https://apisix-website-static.apiseven.com<%= it.baseUrl
%><%= script %>"></script>
+ <script src="<%= process.env.preview ? '' :
'https://apisix-website-static.apiseven.com' %><%= it.baseUrl %><%= script
%>"></script>
<% }); %>
<%~ it.postBodyTags %>
</body>
diff --git a/website/i18n/zh/code.json b/website/i18n/zh/code.json
index 933de43ebe0..335a37e42e8 100644
--- a/website/i18n/zh/code.json
+++ b/website/i18n/zh/code.json
@@ -291,8 +291,11 @@
"openSourcePromo.component.ossPromo.title": {
"message": "为 Apache APISIX 贡献你的力量!"
},
- "openSourcePromo.component.ossPromo.subtitle": {
- "message": "Apache APISIX 完全开放源码并在不断发展!我们欢迎任何形式的贡献,请在 GitHub 上与社区互动。"
+ "openSourcePromo.component.ossPromo.subtitle1": {
+ "message": "Apache APISIX 完全开放源码并在不断发展!"
+ },
+ "openSourcePromo.component.ossPromo.subtitle2": {
+ "message": "我们欢迎任何形式的贡献,请在 GitHub 上与社区互动。"
},
"openSourcePromo.component.link.Github": {
"message": "立即访问",
@@ -331,4 +334,4 @@
"message": "立即体验",
"description": "Download"
}
-}
\ No newline at end of file
+}
diff --git a/website/src/components/HeroCanvas.tsx
b/website/src/components/HeroCanvas.tsx
index f1b9b45389c..d9c2c88df3d 100644
--- a/website/src/components/HeroCanvas.tsx
+++ b/website/src/components/HeroCanvas.tsx
@@ -1,7 +1,20 @@
import type { FC } from 'react';
import React, { useRef, useEffect } from 'react';
-import * as THREE from 'three';
-import gsap from 'gsap';
+import {
+ Vector2,
+ Color,
+ ShaderMaterial,
+ Points,
+ PlaneBufferGeometry,
+ Mesh,
+ MeshBasicMaterial,
+ WebGLRenderer,
+ PerspectiveCamera,
+ BufferAttribute,
+ Scene,
+ DoubleSide,
+} from 'three';
+import { gsap } from 'gsap/gsap-core';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
@@ -61,7 +74,8 @@ const HeroCanvas: FC = () => {
ctx.x = ((ctx.x - canvasOffset.left) / canvasWidth);
ctx.y = ((ctx.y - canvasOffset.top) / canvasHeight);
- gsap.to(mouse, 2, {
+ gsap.to(mouse, {
+ duration: 2,
x: ctx.x * (canvasWidth / canvasHeight) - (canvasWidth / canvasHeight)
/ 2,
y: (1.0 - ctx.y) - 0.5,
onUpdate: () => {
@@ -70,7 +84,8 @@ const HeroCanvas: FC = () => {
},
});
- gsap.to(fragMouse, 2, {
+ gsap.to(fragMouse, {
+ duration: 2,
x: ctx.x,
y: (1.0 - ctx.y),
onUpdate: () => {
@@ -113,20 +128,20 @@ const HeroCanvas: FC = () => {
function init(width: number, height: number) {
const ctx = canvasRef.current;
- renderer = new THREE.WebGLRenderer({ canvas: ctx });
+ renderer = new WebGLRenderer({ canvas: ctx });
renderer.autoClearColor = false;
- camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100);
+ camera = new PerspectiveCamera(45, width / height, 0.1, 100);
controls = new OrbitControls(camera, renderer.domElement);
controls.enableZoom = false;
controls.enablePan = false;
controls.enabled = false;
- geometry = new THREE.PlaneBufferGeometry(width / height, 1, 250, 250);
+ geometry = new PlaneBufferGeometry(width / height, 1, 250, 250);
const { count } = geometry.attributes.position;
- const arrSize = new THREE.BufferAttribute(new Float32Array(count), 1);
+ const arrSize = new BufferAttribute(new Float32Array(count), 1);
for (let i = 0; i < arrSize.count; i += 1) {
arrSize.array[i] = getRandom(0, 1);
@@ -135,7 +150,7 @@ const HeroCanvas: FC = () => {
geometry.scale(2.0, 1.0, 1.0);
- scene = new THREE.Scene();
+ scene = new Scene();
renderer.setSize(canvasWidth, canvasHeight);
const uniforms = {
@@ -145,36 +160,36 @@ const HeroCanvas: FC = () => {
},
u_resolution: {
type: 'v2',
- value: new THREE.Vector2(),
+ value: new Vector2(),
},
u_mouse: {
type: 'v2',
- value: new THREE.Vector2(0.5, 0.5),
+ value: new Vector2(0.5, 0.5),
},
u_fragMouse: {
type: 'v2',
- value: new THREE.Vector2(0.5, 0.5),
+ value: new Vector2(0.5, 0.5),
},
};
- scene.background = new THREE.Color('red');
+ scene.background = new Color('red');
camera.position.z = 5;
controls.update();
- material = new THREE.ShaderMaterial({
+ material = new ShaderMaterial({
uniforms,
vertexShader: vertex,
fragmentShader: fragment,
wireframe: true,
- side: THREE.DoubleSide,
+ side: DoubleSide,
});
- mesh = new THREE.Points(geometry, material);
+ mesh = new Points(geometry, material);
- const backGeometry = new THREE.PlaneBufferGeometry(width / height, 1,
200, 200);
- const bgMaterial = new THREE.MeshBasicMaterial({ color: 0x121212,
wireframe: false });
- const background = new THREE.Mesh(backGeometry, bgMaterial);
+ const backGeometry = new PlaneBufferGeometry(width / height, 1, 200,
200);
+ const bgMaterial = new MeshBasicMaterial({ color: 0x121212, wireframe:
false });
+ const background = new Mesh(backGeometry, bgMaterial);
backGeometry.scale(50, 50, 1);
background.position.set(10, 10, -10);
@@ -233,8 +248,7 @@ const HeroCanvas: FC = () => {
useEffect(() => {
gsap.to(overlayRef.current, {
height: 0,
- delay: window.innerWidth >= 768 ? 0 : 0.3,
- duration: 2.1,
+ duration: 2,
ease: 'Expo.easeInOut',
});
}, []);
diff --git a/website/src/components/OssCanvas.tsx
b/website/src/components/OssCanvas.tsx
deleted file mode 100644
index e2d0bd015ef..00000000000
--- a/website/src/components/OssCanvas.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-import type { FC } from 'react';
-import React, { useRef, useEffect } from 'react';
-import * as THREE from 'three';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
-
-import '../css/customTheme.css';
-
-const OssCanvas: FC = () => {
- let screenWidth: number;
- let canvasHeight: number;
- let canvasWidth: number;
-
- const canvasRef = useRef(null);
-
- useEffect(() => {
- let camera;
- let scene;
- let renderer;
- let material;
- let mesh;
-
- screenWidth = window.innerWidth;
- window.addEventListener('resize', onWindowResize, false);
-
- let controls;
- let isLoaded = false; let isRendering = false; let
- animationFrame;
-
- if (screenWidth > 1100) {
- canvasHeight = 500;
- canvasWidth = screenWidth / 2;
- } else {
- canvasHeight = 500;
- canvasWidth = screenWidth;
- }
-
- function onWindowResize() {
- screenWidth = window.innerWidth;
-
- if (screenWidth > 1100) {
- canvasHeight = 500;
- canvasWidth = screenWidth / 2;
- } else {
- canvasHeight = 500;
- canvasWidth = screenWidth;
- }
-
- renderer.setSize(canvasWidth, canvasHeight);
- }
-
- const ossCanvasObserver = new
IntersectionObserver(onOssCanvasIntersection, {
- root: null,
- threshold: 0.01,
- });
-
- function init(width, height) {
- const ctx = canvasRef.current;
- renderer = new THREE.WebGLRenderer({ canvas: ctx });
-
- camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
-
- controls = new OrbitControls(camera, renderer.domElement);
- controls.enableZoom = false;
-
- const radius = window.innerWidth > 768 ? 5 : 4.5;
- const detail = 8;
-
- const geometry = new THREE.IcosahedronGeometry(radius, detail);
-
- camera.position.z = 2;
- camera.position.x = 3;
-
- controls.update();
-
- scene = new THREE.Scene();
- renderer.setSize(canvasWidth, canvasHeight);
-
- scene.background = new THREE.Color(0x000000);
-
- material = new THREE.MeshNormalMaterial({ wireframe: false, flatShading:
true });
-
- mesh = new THREE.Mesh(geometry, material);
-
- scene.add(mesh);
- mesh.position.set(3, 0, -9.5);
-
- controls.target.copy(mesh.position);
-
- controls.update();
- renderer.setPixelRatio(window.devicePixelRatio);
-
- onWindowResize();
-
- isLoaded = true;
- }
-
- function animate() {
- animationFrame = requestAnimationFrame(animate);
-
- mesh.rotation.x += 0.005;
- mesh.rotation.y += 0.005;
-
- controls.update();
-
- renderer.render(scene, camera);
- isRendering = true;
- }
-
- init(canvasWidth, canvasHeight);
-
- function onOssCanvasIntersection(entries) {
- entries.forEach((entry) => {
- if (entry.isIntersecting && isLoaded) {
- if (isLoaded && !isRendering) {
- animate();
- } else {
- console.log('Loading');
- }
- } else {
- if (animationFrame) {
- cancelAnimationFrame(animationFrame);
- isRendering = false;
- }
- }
- });
- }
-
- ossCanvasObserver.observe(canvasRef.current);
-
- return () => {
- // eslint-disable-next-line prefer-spread
- scene.remove.apply(scene, scene.children);
- ossCanvasObserver.disconnect();
- };
- }, []);
-
- return (
- <canvas ref={canvasRef} width={canvasWidth} height={canvasHeight}
className="ossCanvas" />
- );
-};
-
-export default OssCanvas;
diff --git a/website/src/components/sections/Features.tsx
b/website/src/components/sections/Features.tsx
index 1f8a4bb24dd..dbffbbcdb7c 100644
--- a/website/src/components/sections/Features.tsx
+++ b/website/src/components/sections/Features.tsx
@@ -1,11 +1,12 @@
import type { FC } from 'react';
-import React, { useEffect, useRef, useState } from 'react';
+import React, { useEffect, useRef, memo } from 'react';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
-import gsap from 'gsap';
+import { gsap } from 'gsap/gsap-core';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import Translate from '@docusaurus/Translate';
+import useWindowType from '@theme/hooks/useWindowSize';
import ArrowAnim from '../ArrowAnim';
import '../../css/customTheme.css';
@@ -34,253 +35,57 @@ const DashboardPlayground = () => (
</Link>
);
-const Features: FC = () => {
+const FeatDesktop: FC = () => {
const dashboardDiv = useRef(null);
const userfDiv = useRef(null);
const pluginDiv = useRef(null);
const triggerDiv = useRef(null);
- const triggerDivCol = useRef(null);
const pinDiv = useRef(null);
const img1 = useRef(null);
- const img1col = useRef(null);
const img2 = useRef(null);
- const img2col = useRef(null);
const img3 = useRef(null);
- const img3col = useRef(null);
- const featPin = useRef(null);
-
- gsap.registerPlugin(ScrollTrigger);
-
- const [screenWidth, setScreenWidth] = useState(
- typeof window !== 'undefined' && window.innerWidth,
- );
- const [, setScreenHeight] = useState(
- typeof window !== 'undefined' && window.innerWidth,
- );
-
- useEffect(() => {
- setScreenHeight(window.innerHeight);
- setScreenWidth(window.innerWidth);
- window.addEventListener('resize', resizeEvent, false);
-
- function resizeEvent() {
- setScreenHeight(window.innerHeight);
- setScreenWidth(window.innerWidth);
- }
-
- return () => {
- window.removeEventListener('resize', resizeEvent);
- };
- }, []);
useEffect(() => {
const value = window.innerHeight * 2;
- let tl;
- const observers = [];
+ const tl = gsap.timeline({
+ defaults: {
+ ease: 'linear',
+ },
+ scrollTrigger: {
+ id: 'feat',
+ trigger: triggerDiv.current,
+ start: 'top top',
+ pin: pinDiv.current,
+ scrub: 1.5,
+ end: `${value}px`,
+ },
+ });
- if (screenWidth > 1100) {
- tl = gsap.timeline({
- defaults: {
- ease: 'linear',
- },
- scrollTrigger: {
- id: 'feat',
- trigger: triggerDiv.current,
- start: 'top top',
- pin: pinDiv.current,
- scrub: 1.5,
- end: `${value}px`,
- },
- });
-
- tl.to(img1.current, {
+ tl.to(img1.current, {
+ opacity: 0,
+ })
+ .to(img2.current, {
+ opacity: 1,
+ })
+ .to(img2.current, {
opacity: 0,
})
- .to(img2.current, {
- opacity: 1,
- })
- .to(img2.current, {
- opacity: 0,
- })
- .to(img3.current, {
- opacity: 1,
- });
- } else {
- // Mobile
-
- const elems = [img1col.current, img2col.current, img3col.current];
- for (let i = 1; i < 4; i += 1) {
- observers.push(
- new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- observers[i - 1].disconnect();
- gsap.fromTo(
- elems[i - 1],
- {
- opacity: 0,
- y: 90,
- },
- {
- opacity: 1,
- y: 0,
- duration: 0.5,
- ease: 'power3.out',
- yoyo: true,
- yoyoEase: 'power3.inOut',
- },
- );
- }
- });
- },
- {
- root: null,
- threshold: 0.2,
- },
- ),
- );
- }
-
- observers.forEach((it, index) => {
- it.observe(elems[index]);
+ .to(img3.current, {
+ opacity: 1,
});
- }
});
-
return (
- <>
- <div ref={featPin} className="feat-top" style={{ padding: '50px 0' }}>
- <h3 className="feat-head-desc"><Translate
id="features.component.why.title">Why APISIX Gateway?</Translate></h3>
- <h2 className="feat-head add-left-margin">
- <Translate id="features.component.why.subtitle">
- Reduce time fighting bugs, focus on designing world-class systems
with API Gateway
- </Translate>
- </h2>
- <p className="feat-desc add-left-margin">
- <Translate id="features.component.why.message">
- Apache APISIX is the first open-source API Gateway
- that includes a built-in low-code Dashboard,
- which offers a powerful and flexible UI for developers to use.
- </Translate>
- </p>
- </div>
- <div className="feat-container-d" ref={triggerDiv}>
- {/* Desktop */}
- <div className="left-pane" style={{ width: '50%', height: '100%' }}>
- <div ref={dashboardDiv} style={{ position: 'relative' }}>
- <div className="text-div" style={{ height: '100vh' }}>
- <h2 className="i-text add-left-margin-feat">
- <Translate id="features.component.easyDashboard.title">
- Easy-to-use Dashboard
- </Translate>
- </h2>
- <p className="i-text-desc add-left-margin-feat">
- <Translate id="features.component.easyDashboard.message">
- The Apache APISIX Dashboard is designed to make it as easy as
- possible for users to operate Apache APISIX through a
frontend
- interface. It’s opensource and ever evolving, feel free to
- contribute.
- </Translate>
- </p>
- <div className="hero-ctas add-left-margin-feat bottom-pos">
- <Link to={useBaseUrl('downloads')} className="btn
btn-download">
- <Translate
id="features.component.easyDashboard.downloadBtn">Downloads</Translate>
- </Link>
- <ArrowAnim />
- </div>
- <DashboardPlayground />
- </div>
- </div>
-
- <div ref={userfDiv} style={{ position: 'relative' }}>
- <div className="text-div" style={{ height: '100vh' }}>
- <h2 className="i-text add-left-margin-feat">
- <Translate id="features.component.userFlexible.title">User
Flexible</Translate>
- </h2>
- <p className="i-text-desc add-left-margin-feat">
- <Translate id="features.component.userFlexible.message">
- The Apache APISIX dashboard is flexible to User demand,
- providing option to create custom modules through code
matching
- your requirements, alongside the existing no-code toolchain.
- </Translate>
- </p>
- </div>
- </div>
-
- <div ref={pluginDiv} style={{ position: 'relative' }}>
- <div className="text-div" style={{ height: '100vh' }}>
- <h2 className="i-text add-left-margin-feat">
- <Translate id="features.component.pluginised.title">Pluginised
Workflow</Translate>
- </h2>
- <p className="i-text-desc add-left-margin-feat">
- <Translate id="features.component.pluginised.message">
- No need to reinvent the wheel again and again. Use inbuilt
- plugins to create high performance systems in tight
deadlines.
- For something custom, there is option of building custom
- plugins.
- </Translate>
- </p>
- </div>
- </div>
- </div>
-
- <div
- ref={pinDiv}
- className="right-pane"
- style={{
- width: '50%',
- height: '100vh',
- position: 'relative',
- overflow: 'hidden',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- }}
- >
- <img
- ref={img1}
- className="i-image imagePosition"
- src="https://static.apiseven.com/202202/apisix-dashboard.png"
- loading="lazy"
- alt="apisix-dashboard"
- />
- <img
- ref={img2}
- className="n-image imagePosition"
- src="https://static.apiseven.com/202202/code-sample.png"
- loading="lazy"
- alt="code-snippet"
- />
- <img
- ref={img3}
- className="n-image imagePosition"
- src="https://static.apiseven.com/202202/pluginised.png"
- loading="lazy"
- alt="plugin-workflow"
- />
- </div>
- </div>
- <div
- className="feat-container-m"
- ref={triggerDivCol}
- style={{ width: '100%' }}
- >
- {/* Mobile */}
- <div
- ref={img1col}
- className="hiddenDiv-col"
- style={{ height: 'fit-content', padding: '0 0 40px 0' }}
- >
- <div style={{ position: 'relative', height: '100%' }}>
- <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
+ <div className="feat-container-d" ref={triggerDiv}>
+ <div className="left-pane" style={{ width: '50%', height: '100%' }}>
+ <div ref={dashboardDiv} style={{ position: 'relative' }}>
+ <div className="text-div" style={{ height: '100vh' }}>
+ <h2 className="i-text add-left-margin-feat">
<Translate id="features.component.easyDashboard.title">
- Easy-to-use dashboard
+ Easy-to-use Dashboard
</Translate>
</h2>
- <img className="i-image-col"
src="https://static.apiseven.com/202202/apisix-dashboard.png" alt="Dashboard" />
- <p className="i-text-desc-col add-left-margin">
+ <p className="i-text-desc add-left-margin-feat">
<Translate id="features.component.easyDashboard.message">
The Apache APISIX Dashboard is designed to make it as easy as
possible for users to operate Apache APISIX through a frontend
@@ -288,54 +93,244 @@ const Features: FC = () => {
contribute.
</Translate>
</p>
- <div
- className="hero-ctas add-left-margin"
- style={{ width: 'fit-content' }}
- >
+ <div className="hero-ctas add-left-margin-feat bottom-pos">
<Link to={useBaseUrl('downloads')} className="btn btn-download">
<Translate
id="features.component.easyDashboard.downloadBtn">Downloads</Translate>
</Link>
<ArrowAnim />
</div>
+ <DashboardPlayground />
</div>
</div>
- <div
- ref={img2col}
- className="hiddenDiv-col"
- style={{ height: 'fit-content', padding: '20px 0' }}
- >
- <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
- <Translate id="features.component.userFlexible.title">User
Flexible</Translate>
- </h2>
- <img className="i-image-col"
src="https://static.apiseven.com/202202/code-sample.png" alt="code-sample" />
- <p className="i-text-desc-col add-left-margin">
- <Translate id="features.component.userFlexible.message">
- The Apache APISIX dashboard is flexible to User demand, providing
- option to create custom modules through code matching your
- requirements, alongside the existing no-code toolchain.
- </Translate>
- </p>
+ <div ref={userfDiv} style={{ position: 'relative' }}>
+ <div className="text-div" style={{ height: '100vh' }}>
+ <h2 className="i-text add-left-margin-feat">
+ <Translate id="features.component.userFlexible.title">User
Flexible</Translate>
+ </h2>
+ <p className="i-text-desc add-left-margin-feat">
+ <Translate id="features.component.userFlexible.message">
+ The Apache APISIX dashboard is flexible to User demand,
+ providing option to create custom modules through code matching
+ your requirements, alongside the existing no-code toolchain.
+ </Translate>
+ </p>
+ </div>
</div>
- <div
- ref={img3col}
- className="hiddenDiv-col"
- style={{ height: 'fit-content', padding: '20px 0' }}
- >
+ <div ref={pluginDiv} style={{ position: 'relative' }}>
+ <div className="text-div" style={{ height: '100vh' }}>
+ <h2 className="i-text add-left-margin-feat">
+ <Translate id="features.component.pluginised.title">Pluginised
Workflow</Translate>
+ </h2>
+ <p className="i-text-desc add-left-margin-feat">
+ <Translate id="features.component.pluginised.message">
+ No need to reinvent the wheel again and again. Use inbuilt
+ plugins to create high performance systems in tight deadlines.
+ For something custom, there is option of building custom
+ plugins.
+ </Translate>
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <div
+ ref={pinDiv}
+ className="right-pane"
+ style={{
+ width: '50%',
+ height: '100vh',
+ position: 'relative',
+ overflow: 'hidden',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ }}
+ >
+ <img
+ ref={img1}
+ className="i-image imagePosition"
+ src="https://static.apiseven.com/202202/apisix-dashboard.png"
+ loading="lazy"
+ alt="apisix-dashboard"
+ />
+ <img
+ ref={img2}
+ className="n-image imagePosition"
+ src="https://static.apiseven.com/202202/code-sample.png"
+ loading="lazy"
+ alt="code-snippet"
+ />
+ <img
+ ref={img3}
+ className="n-image imagePosition"
+ src="https://static.apiseven.com/202202/pluginised.png"
+ loading="lazy"
+ alt="plugin-workflow"
+ />
+ </div>
+ </div>
+ );
+};
+
+const FeatMobile: FC = () => {
+ const observers = [];
+ const triggerDivCol = useRef(null);
+ const img1col = useRef(null);
+ const img2col = useRef(null);
+ const img3col = useRef(null);
+
+ useEffect(() => {
+ const elems = [img1col.current, img2col.current, img3col.current];
+ for (let i = 1; i < 4; i += 1) {
+ observers.push(
+ new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ observers[i - 1].disconnect();
+ gsap.fromTo(
+ elems[i - 1],
+ {
+ opacity: 0,
+ y: 90,
+ },
+ {
+ opacity: 1,
+ y: 0,
+ duration: 0.5,
+ ease: 'power3.out',
+ yoyo: true,
+ yoyoEase: 'power3.inOut',
+ },
+ );
+ }
+ });
+ },
+ {
+ root: null,
+ threshold: 0.2,
+ },
+ ),
+ );
+ }
+
+ observers.forEach((it, index) => {
+ it.observe(elems[index]);
+ });
+ }, []);
+
+ return (
+ <div
+ className="feat-container-m"
+ ref={triggerDivCol}
+ style={{ width: '100%' }}
+ >
+ <div
+ ref={img1col}
+ className="hiddenDiv-col"
+ style={{ height: 'fit-content', padding: '0 0 40px 0' }}
+ >
+ <div style={{ position: 'relative', height: '100%' }}>
<h2 className="add-left-margin" style={{ width: 'fit-content' }}>
- <Translate id="features.component.pluginised.title">Pluginised
Workflow</Translate>
+ <Translate id="features.component.easyDashboard.title">
+ Easy-to-use dashboard
+ </Translate>
</h2>
- <img className="i-image-col"
src="https://static.apiseven.com/202202/pluginised.png" alt="Plugin" />
+ <img className="i-image-col"
src="https://static.apiseven.com/202202/apisix-dashboard.png" alt="Dashboard" />
<p className="i-text-desc-col add-left-margin">
- <Translate id="features.component.pluginised.message">
- No need to reinvent the wheel again and again. Use inbuilt
plugins
- to create high performance systems in tight deadlines. For
something
- custom, there is option of building custom plugins.
+ <Translate id="features.component.easyDashboard.message">
+ The Apache APISIX Dashboard is designed to make it as easy as
+ possible for users to operate Apache APISIX through a frontend
+ interface. It’s opensource and ever evolving, feel free to
+ contribute.
</Translate>
</p>
+ <div
+ className="hero-ctas add-left-margin"
+ style={{ width: 'fit-content' }}
+ >
+ <Link to={useBaseUrl('downloads')} className="btn btn-download">
+ <Translate
id="features.component.easyDashboard.downloadBtn">Downloads</Translate>
+ </Link>
+ <ArrowAnim />
+ </div>
</div>
</div>
+
+ <div
+ ref={img2col}
+ className="hiddenDiv-col"
+ style={{ height: 'fit-content', padding: '20px 0' }}
+ >
+ <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
+ <Translate id="features.component.userFlexible.title">User
Flexible</Translate>
+ </h2>
+ <img className="i-image-col"
src="https://static.apiseven.com/202202/code-sample.png" alt="code-sample" />
+ <p className="i-text-desc-col add-left-margin">
+ <Translate id="features.component.userFlexible.message">
+ The Apache APISIX dashboard is flexible to User demand, providing
+ option to create custom modules through code matching your
+ requirements, alongside the existing no-code toolchain.
+ </Translate>
+ </p>
+ </div>
+
+ <div
+ ref={img3col}
+ className="hiddenDiv-col"
+ style={{ height: 'fit-content', padding: '20px 0' }}
+ >
+ <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
+ <Translate id="features.component.pluginised.title">Pluginised
Workflow</Translate>
+ </h2>
+ <img className="i-image-col"
src="https://static.apiseven.com/202202/pluginised.png" alt="Plugin" />
+ <p className="i-text-desc-col add-left-margin">
+ <Translate id="features.component.pluginised.message">
+ No need to reinvent the wheel again and again. Use inbuilt plugins
+ to create high performance systems in tight deadlines. For
something
+ custom, there is option of building custom plugins.
+ </Translate>
+ </p>
+ </div>
+ </div>
+ );
+};
+
+const FeatContainer: FC = () => {
+ gsap.registerPlugin(ScrollTrigger);
+ const windowType = useWindowType();
+
+ if (windowType === 'desktop') {
+ return <FeatDesktop />;
+ }
+
+ return <FeatMobile />;
+};
+const FeatContainerMemo = memo(FeatContainer);
+
+const Features: FC = () => {
+ const featPin = useRef(null);
+
+ return (
+ <>
+ <div ref={featPin} className="feat-top" style={{ padding: '50px 0' }}>
+ <h3 className="feat-head-desc"><Translate
id="features.component.why.title">Why APISIX Gateway?</Translate></h3>
+ <h2 className="feat-head add-left-margin">
+ <Translate id="features.component.why.subtitle">
+ Reduce time fighting bugs, focus on designing world-class systems
with API Gateway
+ </Translate>
+ </h2>
+ <p className="feat-desc add-left-margin">
+ <Translate id="features.component.why.message">
+ Apache APISIX is the first open-source API Gateway
+ that includes a built-in low-code Dashboard,
+ which offers a powerful and flexible UI for developers to use.
+ </Translate>
+ </p>
+ </div>
+ <FeatContainerMemo />
</>
);
};
diff --git a/website/src/components/sections/HeroSection.tsx
b/website/src/components/sections/HeroSection.tsx
index 0583c256737..9b98c405f1e 100644
--- a/website/src/components/sections/HeroSection.tsx
+++ b/website/src/components/sections/HeroSection.tsx
@@ -6,17 +6,23 @@ import Translate from '@docusaurus/Translate';
import '../../css/customTheme.css';
import BrowserOnly from '@docusaurus/BrowserOnly';
+import useWindowType from '@theme/hooks/useWindowSize';
import ArrowAnim from '../ArrowAnim';
-const LazyLoadHeroCanvas = () => (
- <BrowserOnly>
- {() => {
- // eslint-disable-next-line @typescript-eslint/no-var-requires,
global-require
- const HeroCanvas = require('../HeroCanvas').default;
- return <HeroCanvas />;
- }}
- </BrowserOnly>
-);
+const LazyLoadHeroCanvas = () => {
+ const windowType = useWindowType();
+ if (windowType === 'mobile') return (null);
+
+ return (
+ <BrowserOnly>
+ {() => {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires,
global-require
+ const HeroCanvas = require('../HeroCanvas').default;
+ return <HeroCanvas />;
+ }}
+ </BrowserOnly>
+ );
+};
const HeroSection: FC = () => (
<div className="hero-sec-wrap" style={{ width: '100%' }}>
diff --git a/website/src/components/sections/OpensourcePromo.tsx
b/website/src/components/sections/OpensourcePromo.tsx
index 373dedeb4dc..c6f63552d8d 100644
--- a/website/src/components/sections/OpensourcePromo.tsx
+++ b/website/src/components/sections/OpensourcePromo.tsx
@@ -5,10 +5,9 @@ import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Translate from '@docusaurus/Translate';
-import OssCanvas from '../OssCanvas';
+import BrowserOnly from '@docusaurus/BrowserOnly';
import GitHub from '../../assets/icons/github-logo.svg';
-import Video from '../Video';
import type { VideoProps } from '../Video';
const VideoChannel: FC = () => {
@@ -43,6 +42,16 @@ const videoOptions: VideoProps['options'] = {
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="ossPromotion">
<div className="docs-promo">
@@ -78,25 +87,26 @@ const OpensourcePromo: FC = () => (
</div>
</div>
<div className="docs-promo-video">
- <Video options={videoOptions} />
+ <LazyLoadVideo />
</div>
</div>
<div className="oss-promo">
- <div className="oss-promo-text">
+ <div className="oss-promo-inwrapper">
<h3 className="oss-promo-head">
<Translate id="openSourcePromo.component.ossPromo.title">
- Building API Gateway together
+ Building API Gateway Together
</Translate>
</h3>
<div className="oss-promo-subtitle" style={{ color: 'rgb(199, 199,
199)' }}>
<p>
- <strong>
- <Translate id="openSourcePromo.component.ossPromo.subtitle">
- Apache APISIX is open source and ever-growing.
- Contributors are always welcome. Reach out to us on GitHub
- </Translate>
- </strong>
+ <Translate id="openSourcePromo.component.ossPromo.subtitle1">
+ Apache APISIX is open source and ever-growing.
+ </Translate>
+ <br />
+ <Translate id="openSourcePromo.component.ossPromo.subtitle2">
+ Contributors are always welcome, reach out to us on GitHub.
+ </Translate>
</p>
<div className="oss-promo-cta">
<GitHub style={{ width: '20px', margin: '0 10px 0 0' }} />
@@ -108,9 +118,6 @@ const OpensourcePromo: FC = () => (
</div>
</div>
</div>
- <div className="oss-promo-infograph">
- <OssCanvas />
- </div>
</div>
</div>
);
diff --git a/website/src/css/customTheme.css b/website/src/css/customTheme.css
index bd654f96fe7..257b55283b7 100644
--- a/website/src/css/customTheme.css
+++ b/website/src/css/customTheme.css
@@ -528,8 +528,7 @@ a:hover {
.arch-head,
.compare-head,
.testimonials-head,
-.docs-promo-head,
-.oss-promo-head {
+.docs-promo-head {
font-size: 2.4rem;
position: relative;
left: 16.8%;
@@ -539,8 +538,7 @@ a:hover {
.arch-subtitle,
.compare-subtitle,
.testimonials-subtitle,
-.docs-promo-subtitle,
-.oss-promo-subtitle {
+.docs-promo-subtitle {
font-size: 1.13rem;
position: relative;
left: 16.8%;
@@ -986,29 +984,33 @@ a:hover {
.oss-promo {
display: flex;
- padding: 50px 0;
- flex-flow: row-reverse;
- color: black;
- background: #fff8f6;
+ padding: 80px 0;
+ justify-content: center;
+ background: #121010;
+ color: white;
}
-.oss-promo-text {
- width: 50%;
+.oss-promo-inwrapper {
display: flex;
- justify-content: center;
flex-direction: column;
- background: #121010;
- color: white;
+ text-align: left;
}
-.oss-promo-infograph {
- background: #0a0a0a;
- width: 50%;
- height: 100%;
- overflow: hidden;
+.oss-promo-head {
+ font-size: 2.4rem;
+}
+
+.oss-promo-subtitle {
+ font-size: 1.13rem;
+ color: #615d5d;
+ letter-spacing: 0.2px;
+ font-family: MaisonNeue-Light, sans-serif;
+ font-weight: 700;
+ text-align: center;
}
.oss-promo-cta {
+ margin: 0 auto;
background: #080808;
display: flex;
width: fit-content;
@@ -1025,12 +1027,11 @@ a:hover {
}
.oss-promo-cta:hover {
- background: #9b9b9b;
+ background: hsl(0deg 100% 100% / 80%);
color: #080808;
- border-style: solid;
}
-.oss-promo-cta > a:hover {
+.oss-promo-cta:hover > a {
color: #080808;
}