You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2022/04/08 09:46:28 UTC

[apisix-website] branch master updated: refactor: convert pages from JS to TS (#1010)

This is an automated email from the ASF dual-hosted git repository.

juzhiyuan 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 46b37b3fd1d refactor: convert pages from JS to TS (#1010)
46b37b3fd1d is described below

commit 46b37b3fd1dabac0d4b90ff21e9e5b19a9b60c5c
Author: SkyeYoung <is...@outlook.com>
AuthorDate: Fri Apr 8 17:46:22 2022 +0800

    refactor: convert pages from JS to TS (#1010)
---
 .eslintrc.js                                       |  26 +-
 website/package.json                               |   1 +
 .../{ContributeCard.js => ContributeCard.tsx}      | 102 ++--
 website/src/pages/contribute/index.js              | 104 ----
 website/src/pages/contribute/index.tsx             |  96 ++++
 website/src/pages/{docs.js => docs.tsx}            | 102 ++--
 .../downloads/{ProjectCard.js => ProjectCard.tsx}  | 540 ++++++++++++---------
 .../src/pages/downloads/{index.js => index.tsx}    |  47 +-
 website/src/pages/{help.js => help.tsx}            |  35 +-
 website/src/pages/index.js                         |  78 ---
 website/src/pages/index.tsx                        |  78 +++
 website/src/pages/{plugins.js => plugins.tsx}      |  60 ++-
 website/src/pages/sections/Architecture.tsx        | 104 ++++
 website/src/pages/sections/Benefits.tsx            | 413 ++++++++++++++++
 website/src/pages/sections/Comparison.tsx          |  79 +++
 website/src/pages/sections/Endcta.tsx              |  37 ++
 .../pages/sections/{features.jsx => Features.tsx}  | 149 +++---
 website/src/pages/sections/HeroSection.tsx         |  68 +++
 ...me-events-section.jsx => HomeEventsSection.tsx} |  39 +-
 website/src/pages/sections/OpensourcePromo.tsx     |  57 +++
 website/src/pages/sections/architecture.jsx        |  87 ----
 website/src/pages/sections/benefits.jsx            | 386 ---------------
 website/src/pages/sections/comparison.jsx          |  79 ---
 .../src/pages/sections/components/ArrowAnim.tsx    |  65 +++
 .../pages/sections/components/EventPosterCard.tsx  |  89 ++++
 .../src/pages/sections/components/HeroCanvas.tsx   | 248 ++++++++++
 .../components/{ossCanvas.jsx => OssCanvas.tsx}    | 107 ++--
 .../src/pages/sections/components/arrowAnim.jsx    |  56 ---
 .../pages/sections/components/eventPosterCard.jsx  |  73 ---
 .../src/pages/sections/components/heroCanvas.jsx   | 236 ---------
 website/src/pages/sections/endcta.jsx              |  30 --
 website/src/pages/sections/heroSection.jsx         |  63 ---
 website/src/pages/sections/opensourcePromo.jsx     |  47 --
 website/src/pages/showcase/index.js                |  81 ----
 website/src/pages/showcase/index.tsx               |  87 ++++
 website/src/pages/{team.js => team.tsx}            | 171 +++----
 website/tsconfig.json                              |   5 +-
 yarn.lock                                          |  21 +-
 38 files changed, 2221 insertions(+), 1925 deletions(-)

diff --git a/.eslintrc.js b/.eslintrc.js
index e647d7613e2..024760acc59 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -3,14 +3,16 @@ const WARNING = 1;
 const ERROR = 2;
 
 module.exports = {
+  root: true,
   env: {
     browser: true,
     es2021: true,
     node: true,
   },
   extends: [
-    'plugin:react/recommended',
     'airbnb',
+    'plugin:react/recommended',
+    'plugin:@typescript-eslint/recommended',
   ],
   parser: '@typescript-eslint/parser',
   parserOptions: {
@@ -19,11 +21,20 @@ module.exports = {
     },
     ecmaVersion: 'latest',
     sourceType: 'module',
+    tsconfigRootDir: `${__dirname}/website`,
+    projects: ['./tsconfig.json'],
   },
   plugins: [
     'react',
     '@typescript-eslint',
   ],
+  settings: {
+    'import/resolver': {
+      node: {
+        extensions: ['.js', '.jsx', '.ts', '.tsx', '.svg'],
+      },
+    },
+  },
   rules: {
     quotes: [ERROR, 'single', { allowTemplateLiterals: true }],
     'no-unused-vars': OFF,
@@ -73,6 +84,18 @@ module.exports = {
     ],
     'no-lonely-if': OFF,
     'no-lone-blocks': OFF,
+    'react/jsx-filename-extension': [
+      ERROR,
+      { extensions: ['.jsx', '.tsx'] },
+    ],
+    'import/extensions': [ERROR, { tsx: 'never', svg: 'always' }],
+    'react/jsx-props-no-spreading': OFF,
+    'react/function-component-definition': [
+      ERROR,
+      {
+        namedComponents: 'arrow-function',
+      },
+    ],
   },
   overrides: [
     {
@@ -92,6 +115,7 @@ module.exports = {
         'import/extensions': OFF,
         'import/no-extraneous-dependencies': OFF,
         '@typescript-eslint/no-shadow': OFF,
+        '@typescript-eslint/no-var-requires': OFF,
       },
     },
     {
diff --git a/website/package.json b/website/package.json
index 94fd1ab11c7..15f9a2cbce6 100644
--- a/website/package.json
+++ b/website/package.json
@@ -20,6 +20,7 @@
     "@types/react": "^17.0.20",
     "@types/react-helmet": "^6.1.2",
     "@types/react-router-dom": "^5.1.8",
+    "@types/styled-components": "^5.1.24",
     "babel-plugin-styled-components": "^2.0.6",
     "typescript": "^4.4.2"
   },
diff --git a/website/src/pages/contribute/ContributeCard.js b/website/src/pages/contribute/ContributeCard.tsx
similarity index 50%
rename from website/src/pages/contribute/ContributeCard.js
rename to website/src/pages/contribute/ContributeCard.tsx
index 475c4945601..399086e3add 100644
--- a/website/src/pages/contribute/ContributeCard.js
+++ b/website/src/pages/contribute/ContributeCard.tsx
@@ -1,8 +1,13 @@
-import React, { useState } from "react";
-import styled from "styled-components";
-import IconComment from "../../assets/icons/comment.svg";
+import type { FC } from 'react';
+import React, { useState } from 'react';
+import styled from 'styled-components';
+import IconComment from '../../assets/icons/comment.svg';
 
-const Card = styled.div`
+interface CommonStyleProps {
+  isShow: boolean
+}
+
+const Card = styled.div<CommonStyleProps>`
   @media (max-width: 700px) {
     width: 100%;
   }
@@ -21,7 +26,7 @@ const Card = styled.div`
     }
   }
 
-  background-color: ${(props) => (props.isShow ? "rgb(255,241,240,0.2)" : "")};
+  background-color: ${(props) => (props.isShow ? 'rgb(255,241,240,0.2)' : '')};
 `;
 
 const ProjectTitle = styled.div`
@@ -31,10 +36,11 @@ const ProjectTitle = styled.div`
   margin-left: 1.25rem;
   margin-right: 1.25rem;
 `;
-const Title = styled.p`
+
+const Title = styled.p<CommonStyleProps>`
   margin: 0;
   font-size: 1.5rem;
-  color: ${(props) => (props.isShow ? "rgb(232, 67, 62)" : "")};
+  color: ${(props) => (props.isShow ? 'rgb(232, 67, 62)' : '')};
 `;
 
 const Issue = styled.div`
@@ -47,19 +53,41 @@ const Issue = styled.div`
   font-size: 0.875rem;
 `;
 
-const ProjectDesc = styled.div`
+const ProjectDesc = styled.div<CommonStyleProps>`
   display: flex;
-  color: ${(props) => (props.isShow ? "rgb(232, 67, 62)" : "")};
+  color: ${(props) => (props.isShow ? 'rgb(232, 67, 62)' : '')};
 `;
-const List = styled.div`
-  display: ${(props) => (props.isShow ? "block" : "none")};
+
+const List = styled.div<CommonStyleProps>`
+  display: ${(props) => (props.isShow ? 'block' : 'none')};
 `;
+
 const ListItem = styled.li`
   list-style: none;
   display: flex;
 `;
 
-const ContributeCard = (props) => {
+interface IssueInfo {
+  number: number;
+  htmlUrl: string;
+  title: string;
+  comments: number
+}
+
+interface RepoInfo {
+  description: string;
+  star: number;
+  watch: number;
+  fork: number;
+}
+
+interface ContributeCardProps {
+  repoName: string;
+  issues: IssueInfo[];
+  info: RepoInfo;
+}
+
+const ContributeCard: FC<ContributeCardProps> = (props) => {
   const { repoName, issues = [], info } = props;
   const [isShow, setIsShow] = useState(false);
 
@@ -70,51 +98,69 @@ const ContributeCard = (props) => {
     <Card onClick={() => setIsShow(!isShow)} isShow={isShow}>
       <ProjectTitle>
         <Title isShow={isShow}>{repoName}</Title>
-        <Issue isShow={isShow}>{issues.length} issues</Issue>
+        <Issue>
+          {issues.length}
+          {' '}
+          issues
+        </Issue>
       </ProjectTitle>
       <div>{info.description}</div>
       <ProjectDesc isShow={isShow}>
-        <div style={{ marginRight: "1rem" }}>Star: {info.star}</div>
-        <div style={{ marginRight: "1rem" }}>Watch: {info.watch}</div>
-        <div style={{ marginRight: "1rem" }}>Fork: {info.fork}</div>
+        <div style={{ marginRight: '1rem' }}>
+          Star:
+          {info.star}
+        </div>
+        <div style={{ marginRight: '1rem' }}>
+          Watch:
+          {info.watch}
+        </div>
+        <div style={{ marginRight: '1rem' }}>
+          Fork:
+          {info.fork}
+        </div>
       </ProjectDesc>
       <List isShow={isShow}>
         <ul style={{ paddingLeft: 0 }}>
           {issues.map((item) => (
             <ListItem key={item.number}>
-              <div style={{ minWidth: "4rem" }}>#{item.number}</div>
+              <div style={{ minWidth: '4rem' }}>
+                #
+                {item.number}
+              </div>
               <a
                 target="_blank"
                 href={item.htmlUrl}
                 style={{
-                  flex: "1 1 auto",
-                  textDecoration: "none",
-                  overflow: "hidden",
+                  flex: '1 1 auto',
+                  textDecoration: 'none',
+                  overflow: 'hidden',
                 }}
+                rel="noreferrer"
               >
-                {item.title}{" "}
+                {item.title}
+                {' '}
               </a>
               {item.comments > 0 ? (
                 <div
                   style={{
-                    display: "flex",
-                    justifyContent: "center",
-                    alignItems: "center",
+                    display: 'flex',
+                    justifyContent: 'center',
+                    alignItems: 'center',
                   }}
                 >
                   <IconComment />
                   <div
                     style={{
-                      marginLeft: "0.25rem",
-                      fontSize: "0.5rem",
-                      color: "#333",
+                      marginLeft: '0.25rem',
+                      fontSize: '0.5rem',
+                      color: '#333',
                     }}
                   >
                     {item.comments}
                   </div>
                 </div>
               ) : (
-                ""
+                ''
               )}
             </ListItem>
           ))}
diff --git a/website/src/pages/contribute/index.js b/website/src/pages/contribute/index.js
deleted file mode 100644
index 42c1cdb1506..00000000000
--- a/website/src/pages/contribute/index.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-import Layout from "@theme/Layout";
-import ContributeCard from "./ContributeCard";
-import Head from "@docusaurus/Head";
-
-const Page = styled.div`
-  max-width: var(--ifm-container-width);
-  margin: 0 auto;
-  padding: 2rem var(--ifm-spacing-horizontal);
-  width: 100%;
-`;
-
-const PageTitle = styled.h1`
-  margin-top: 2rem;
-  font-size: 3rem;
-  font-weight: 800;
-`;
-
-const PageTitleSpecial = styled.span`
-  color: rgb(232, 67, 62);
-`;
-
-const PageDesc = styled.div`
-  margin: 1.25rem auto;
-`;
-
-const Contribute = () => {
-  const repoList = require("../../../config/docs").map(
-    (item) => item.githubRepo
-  );
-  const repoInfoList = require("../../../config/repos-info.json");
-
-  const repos = repoList.map((repoName) => {
-    return (
-      <ContributeCard
-        key={repoName}
-        repoName={repoName}
-        {...repoInfoList[repoName]}
-      />
-    );
-  });
-
-  return (
-    <Layout>
-      <Head>
-        <title>
-          Good first issue - Apache APISIX® - Cloud-Native API Gateway
-        </title>
-
-        <meta
-          name={"description"}
-          content={
-            "Help new partners to Apache APISIX Community and make first contribution."
-          }
-        />
-
-        <meta property={"og:type"} content={"website"} />
-        <meta
-          property={"og:title"}
-          content={
-            "Good first issue - Apache APISIX® - Cloud-Native API Gateway"
-          }
-        />
-        <meta
-          property={"og:site_name"}
-          content={"Apache APISIX® -- Cloud-Native API Gateway"}
-        />
-        <meta
-          property={"og:description"}
-          content={
-            "Help new partners to Apache APISIX Community and make first contribution."
-          }
-        />
-
-        <meta name={"twitter:card"} content={"summary"} />
-        <meta
-          name={"twitter:title"}
-          content={
-            "Good first issue - Apache APISIX® - Cloud-Native API Gateway"
-          }
-        />
-        <meta
-          name={"twitter:description"}
-          content={
-            "Help new partners to Apache APISIX Community and make first contribution."
-          }
-        />
-      </Head>
-      <Page>
-        <PageTitle>
-          Good <PageTitleSpecial>first</PageTitleSpecial> issue
-        </PageTitle>
-        <PageDesc>
-          Help new partners to Apache APISIX Community and make first
-          contribution.
-        </PageDesc>
-        {repos}
-      </Page>
-    </Layout>
-  );
-};
-
-export default Contribute;
diff --git a/website/src/pages/contribute/index.tsx b/website/src/pages/contribute/index.tsx
new file mode 100644
index 00000000000..acf57aef707
--- /dev/null
+++ b/website/src/pages/contribute/index.tsx
@@ -0,0 +1,96 @@
+import type { FC } from 'react';
+import React from 'react';
+import styled from 'styled-components';
+import Layout from '@theme/Layout';
+import Head from '@docusaurus/Head';
+import ContributeCard from './ContributeCard';
+import doc from '../../../config/docs';
+import repoInfoList from '../../../config/repos-info.json';
+
+const Page = styled.div`
+  max-width: var(--ifm-container-width);
+  margin: 0 auto;
+  padding: 2rem var(--ifm-spacing-horizontal);
+  width: 100%;
+`;
+
+const PageTitle = styled.h1`
+  margin-top: 2rem;
+  font-size: 3rem;
+  font-weight: 800;
+`;
+
+const PageTitleSpecial = styled.span`
+  color: rgb(232, 67, 62);
+`;
+
+const PageDesc = styled.div`
+  margin: 1.25rem auto;
+`;
+
+const Contribute: FC = () => {
+  const repoList = doc.map((item) => item.githubRepo);
+
+  const repos = repoList.map((repoName) => (
+    <ContributeCard
+      key={repoName}
+      repoName={repoName}
+      {...repoInfoList[repoName]}
+    />
+  ));
+
+  return (
+    <Layout>
+      <Head>
+        <title>
+          Good first issue - Apache APISIX® - Cloud-Native API Gateway
+        </title>
+
+        <meta
+          name="description"
+          content="Help new partners to Apache APISIX Community and make first contribution."
+        />
+
+        <meta property="og:type" content="website" />
+        <meta
+          property="og:title"
+          content="Good first issue - Apache APISIX® - Cloud-Native API Gateway"
+        />
+        <meta
+          property="og:site_name"
+          content="Apache APISIX® -- Cloud-Native API Gateway"
+        />
+        <meta
+          property="og:description"
+          content="Help new partners to Apache APISIX Community and make first contribution."
+        />
+
+        <meta name="twitter:card" content="summary" />
+        <meta
+          name="twitter:title"
+          content="Good first issue - Apache APISIX® - Cloud-Native API Gateway"
+        />
+        <meta
+          name="twitter:description"
+          content="Help new partners to Apache APISIX Community and make first contribution."
+        />
+      </Head>
+      <Page>
+        <PageTitle>
+          Good
+          {' '}
+          <PageTitleSpecial>first</PageTitleSpecial>
+          {' '}
+          issue
+        </PageTitle>
+        <PageDesc>
+          Help new partners to Apache APISIX Community and make first
+          contribution.
+        </PageDesc>
+        {repos}
+      </Page>
+    </Layout>
+  );
+};
+
+export default Contribute;
diff --git a/website/src/pages/docs.js b/website/src/pages/docs.tsx
similarity index 58%
rename from website/src/pages/docs.js
rename to website/src/pages/docs.tsx
index 12a57fdf790..cf82b550a05 100644
--- a/website/src/pages/docs.js
+++ b/website/src/pages/docs.tsx
@@ -1,17 +1,18 @@
-import React from "react";
-import styled from "styled-components";
-import "../css/customTheme.css";
-import Layout from "@theme/Layout";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
-
-import IconTriangle from "../assets/icons/triangle.svg";
-import IconSquare from "../assets/icons/square.svg";
-import IconHexagon from "../assets/icons/hexagon.svg";
-import IconPentagon from "../assets/icons/pentagon.svg";
-import IconDiamond from "../assets/icons/diamond.svg";
-import IconStar from "../assets/icons/star-solid.svg";
-import IconOctagon from "../assets/icons/octagon.svg";
-import IconShield from "../assets/icons/shield.svg";
+import type { FC } from 'react';
+import React from 'react';
+import styled from 'styled-components';
+import '../css/customTheme.css';
+import Layout from '@theme/Layout';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+
+import IconTriangle from '../assets/icons/triangle.svg';
+import IconSquare from '../assets/icons/square.svg';
+import IconHexagon from '../assets/icons/hexagon.svg';
+import IconPentagon from '../assets/icons/pentagon.svg';
+import IconDiamond from '../assets/icons/diamond.svg';
+import IconStar from '../assets/icons/star-solid.svg';
+import IconOctagon from '../assets/icons/octagon.svg';
+import IconShield from '../assets/icons/shield.svg';
 
 const Page = styled.div`
   max-width: var(--ifm-container-width);
@@ -19,12 +20,14 @@ const Page = styled.div`
   padding: 2rem var(--ifm-spacing-horizontal);
   width: 100%;
 `;
+
 const PageTitle = styled.h1`
   margin-top: 2rem;
   font-size: 3rem;
   font-weight: 800;
   text-transform: uppercase;
 `;
+
 const PageSubtitle = styled.div`
   margin-bottom: 4rem;
 `;
@@ -37,6 +40,7 @@ const CardsContainer = styled.div`
     grid-template-columns: 1fr;
   }
 `;
+
 const Card = styled.a`
   border-radius: 0.75rem;
   border: 1px solid #eee;
@@ -60,6 +64,7 @@ const Card = styled.a`
     }
   }
 `;
+
 const Title = styled.div`
   font-size: 2.4rem;
   line-height: 2.4rem;
@@ -75,6 +80,7 @@ const Title = styled.div`
     transition: all 0.6s;
   }
 `;
+
 const Description = styled.div`
   font-size: 1rem;
   margin-top: 0px;
@@ -82,11 +88,12 @@ const Description = styled.div`
     margin-top: 6px;
   }
 `;
+
 const ShapeBeforeTitle = styled.span`
   margin-right: 12px;
   & svg {
     height: 1.75rem;
-    color: ${(props) => props.color || "var(--ifm-color-primary)"};
+    color: ${(props) => props.color || 'var(--ifm-color-primary)'};
   }
   @media (max-width: 600px) {
     margin-right: 8px;
@@ -95,6 +102,7 @@ const ShapeBeforeTitle = styled.span`
     }
   }
 `;
+
 const VersionInfo = styled.div`
   display: inline-flex;
   font-size: 1rem;
@@ -104,7 +112,31 @@ const VersionInfo = styled.div`
   }
 `;
 
-const ProjectCard = (props) => {
+const shapeComponentMap = {
+  triangle: <IconTriangle />,
+  pentagon: <IconPentagon />,
+  diamond: <IconDiamond />,
+  square: <IconSquare />,
+  hexagon: <IconHexagon />,
+  star: <IconStar />,
+  shield: <IconShield />,
+  octagon: <IconOctagon />,
+};
+
+interface DocInfo {
+    name: string;
+    nameInParamCase: string;
+    description: string;
+    shape: string;
+    color: string;
+    version: string;
+    releaseDate: string;
+    firstDocPath: string;
+}
+
+interface ProjectCardProps extends DocInfo {}
+
+const ProjectCard: FC<ProjectCardProps> = (props) => {
   const {
     name,
     nameInParamCase,
@@ -113,50 +145,34 @@ const ProjectCard = (props) => {
     color,
     version,
     releaseDate,
-    firstDocPath = "",
+    firstDocPath = '',
   } = props;
-  const shapeComponent =
-    shape === "triangle" ? (
-      <IconTriangle />
-    ) : shape === "pentagon" ? (
-      <IconPentagon />
-    ) : shape === "diamond" ? (
-      <IconDiamond />
-    ) : shape === "square" ? (
-      <IconSquare />
-    ) : shape === "hexagon" ? (
-      <IconHexagon />
-    ) : shape === "star" ? (
-      <IconStar />
-    ) : shape === "shield" ? (
-      <IconShield />
-    ) : (
-      <IconOctagon />
-    );
 
   return (
     <Card href={`/docs/${nameInParamCase}${firstDocPath}`}>
       <Title>
-        <ShapeBeforeTitle color={color}>{shapeComponent}</ShapeBeforeTitle>
+        <ShapeBeforeTitle color={color}>{shapeComponentMap[shape]}</ShapeBeforeTitle>
         {name}
       </Title>
       <Description className="docs-subtitle">{description}</Description>
       <VersionInfo className="docs-versioninfo">
-        Latest version&nbsp;<span>{version}</span>&nbsp;released at&nbsp;
+        Latest version&nbsp;
+        <span>{version}</span>
+&nbsp;released at&nbsp;
         <span>{releaseDate}</span>
       </VersionInfo>
     </Card>
   );
 };
 
-export default (props) => {
+const Docs: FC = () => {
   const { siteConfig } = useDocusaurusContext();
-  if (!(siteConfig.customFields.docs || []).length) {
+  const docs = siteConfig.customFields.docs as DocInfo[] | null;
+
+  if (!docs?.length) {
     return null;
   }
-  const projects = siteConfig.customFields.docs.map((project) => {
-    return <ProjectCard key={project.name} {...project} />;
-  });
+  const projects = docs.map((project) => <ProjectCard key={project.name} {...project} />);
 
   return (
     <Layout>
@@ -168,3 +184,5 @@ export default (props) => {
     </Layout>
   );
 };
+
+export default Docs;
diff --git a/website/src/pages/downloads/ProjectCard.js b/website/src/pages/downloads/ProjectCard.tsx
similarity index 67%
rename from website/src/pages/downloads/ProjectCard.js
rename to website/src/pages/downloads/ProjectCard.tsx
index 8efd9965e0c..ad34ee4d471 100644
--- a/website/src/pages/downloads/ProjectCard.js
+++ b/website/src/pages/downloads/ProjectCard.tsx
@@ -1,21 +1,210 @@
-import React, { useState, useRef, useEffect } from "react";
-import styled from "styled-components";
-import useOutsideClick from "../../hooks/useOutsideClick";
-import "../../css/customTheme.css";
-import IconInfo from "../../assets/icons/info.svg";
-import IconStar from "../../assets/icons/star.svg";
-import IconDocumentText from "../../assets/icons/document-text.svg";
-import IconDownload from "../../assets/icons/download.svg";
-import IconTriangle from "../../assets/icons/triangle.svg";
-import IconSquare from "../../assets/icons/square.svg";
-import IconHexagon from "../../assets/icons/hexagon.svg";
-import IconStarSolid from "../../assets/icons/star-solid.svg";
-import IconOctagon from "../../assets/icons/octagon.svg";
-import IconShield from "../../assets/icons/shield.svg";
+import type { Dispatch, FC, SetStateAction } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
+import styled from 'styled-components';
+import useOutsideClick from '../../hooks/useOutsideClick';
+import '../../css/customTheme.css';
+import IconInfo from '../../assets/icons/info.svg';
+import IconStar from '../../assets/icons/star.svg';
+import IconDocumentText from '../../assets/icons/document-text.svg';
+import IconDownload from '../../assets/icons/download.svg';
+import IconTriangle from '../../assets/icons/triangle.svg';
+import IconSquare from '../../assets/icons/square.svg';
+import IconHexagon from '../../assets/icons/hexagon.svg';
+import IconStarSolid from '../../assets/icons/star-solid.svg';
+import IconOctagon from '../../assets/icons/octagon.svg';
+import IconShield from '../../assets/icons/shield.svg';
 
-const Dropdown = (props) => {
+const Card = styled.div`
+  border-radius: 0.75rem;
+  border: 1px solid #eee;
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
+  padding: 2rem;
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 3rem;
+  @media (max-width: 600px) {
+    flex-direction: column;
+    padding: 1rem;
+  }
+`;
+
+const LeftSide = styled.div`
+  flex-shrink: 2;
+  padding-left: 0.6rem;
+`;
+
+const Title = styled.a`
+  font-size: 2.4rem;
+  line-height: 2.4rem;
+  margin-bottom: 1rem;
+  font-weight: bold;
+  display: block;
+  cursor: pointer;
+  @media (max-width: 600px) {
+    margin-top: 0px;
+    font-size: 1.6rem;
+  }
+  svg {
+    transition: all 0.6s;
+  }
+  &:hover {
+    color: inherit;
+    text-decoration: none;
+    svg {
+      transform: rotate(360deg);
+    }
+  }
+`;
+
+const Description = styled.div`
+  font-size: 1.2rem;
+  margin-top: 0px;
+  @media (max-width: 600px) {
+    margin-top: 6px;
+  }
+`;
+
+const ShapeBeforeTitle = styled.span<{color: string}>`
+  margin-right: 12px;
+  & svg {
+    height: 1.75rem;
+    color: ${(props) => props.color || 'var(--ifm-color-primary)'};
+  }
+  @media (max-width: 600px) {
+    margin-right: 8px;
+    & svg {
+      height: 1.3rem;
+    }
+  }
+`;
+
+const LeftSideLinks = styled.div`
+  display: inline-flex;
+  font-size: 1rem;
+  margin-top: 24px;
+  & svg {
+    height: 1rem;
+    margin-right: 4px;
+  }
+`;
+
+const LeftSideLink = styled.a`
+  display: flex;
+  align-items: center;
+  margin-right: 18px;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.3s;
+  color: inherit;
+  &:hover {
+    text-decoration: none;
+  }
+`;
+
+const RightSide = styled.div`
+  padding-left: 2rem;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  position: relative;
+  flex-shrink: 0;
+  @media (max-width: 600px) {
+    margin-top: 1rem;
+    padding-top: 1rem;
+    border-top: 1px solid #eee;
+    padding-left: 0;
+  }
+`;
+
+const LTSCard = styled.div`
+  margin-right: 1em;
+  position: relative;
+  display: flex;
+`;
+
+const ButtonCard = styled.div`
+  margin-right: 0.3em;
+  position: relative;
+  display: flex;
+`;
+
+const ButtonRow = styled.div`
+  inline-size: auto;
+  display: flex;
+`;
+
+const Button = styled.button<{background: string}>`
+  padding: 12px 18px;
+  font-size: 18px;
+  font-weight: 600;
+  border-radius: 0.5rem;
+  transition: all 0.3s;
+  background: ${(props) => props.background || 'var(--ifm-color-primary)'};
+  color: white;
+  border: none;
+  box-sizing: border-box;
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  &:hover {
+    filter: brightness(105%);
+  }
+  svg {
+    height: 22px;
+    margin-right: 4px;
+    padding-bottom: 2px;
+  }
+`;
+
+const StyledDropdown = styled.div<{open: boolean}>`
+  top: 45px;
+  right: 0;
+  position: absolute;
+  margin-top: 0.25rem;
+  border-radius: 0.5rem;
+  border: 1px solid #eee;
+  z-index: 100;
+  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
+    0 4px 6px -2px rgba(0, 0, 0, 0.05);
+  visibility: ${(props) => (props.open ? 'visitable' : 'hidden')};
+`;
+
+const DropdownItem = styled.a`
+  margin: 0.4rem;
+  padding: 0.2rem 1rem 0.2rem 0.5rem;
+  border-radius: 5px;
+  cursor: pointer;
+  font-weight: 500;
+  display: block;
+  color: inherit;
+  &:hover {
+    color: inherit;
+    text-decoration: none;
+  }
+`;
+const VersionInfo = styled.div`
+  text-align: right;
+  font-size: 0.9rem;
+  span {
+    font-weight: 500;
+  }
+  @media (max-width: 600px) {
+    margin-bottom: 1rem;
+    text-align: left;
+  }
+`;
+
+interface DropdownProps {
+  isDropdownOpen: boolean;
+  setIsDropdownOpen: Dispatch<SetStateAction<boolean>>;
+}
+
+const Dropdown: FC<DropdownProps> = (props) => {
   const ref = useRef();
-  const { isDropdownOpen, setIsDropdownOpen } = props;
+  const { isDropdownOpen, setIsDropdownOpen, children } = props;
   useOutsideClick(ref, () => {
     if (isDropdownOpen) {
       setIsDropdownOpen(false);
@@ -27,14 +216,19 @@ const Dropdown = (props) => {
       ref={ref}
       open={isDropdownOpen}
     >
-      {props.children}
+      {children}
     </StyledDropdown>
   );
 };
 
-const LTSDropdown = (props) => {
+interface LTSDropdownProps {
+  isLTSDropdownOpen: boolean;
+  setIsLTSDropdownOpen: Dispatch<SetStateAction<boolean>>;
+}
+
+const LTSDropdown: FC<LTSDropdownProps> = (props) => {
   const ref = useRef();
-  const { isLTSDropdownOpen, setIsLTSDropdownOpen } = props;
+  const { isLTSDropdownOpen, setIsLTSDropdownOpen, children } = props;
   useOutsideClick(ref, () => {
     if (isLTSDropdownOpen) {
       setIsLTSDropdownOpen(false);
@@ -46,12 +240,70 @@ const LTSDropdown = (props) => {
       ref={ref}
       open={isLTSDropdownOpen}
     >
-      {props.children}
+      {children}
     </StyledDropdown>
   );
 };
 
-const ProjectCard = (props) => {
+const shapeComponentMap = {
+  triangle: <IconTriangle />,
+  square: <IconSquare />,
+  hexagon: <IconHexagon />,
+  star: <IconStarSolid />,
+  shield: <IconShield />,
+  octagon: <IconOctagon />,
+};
+
+const getGitHubRepoStats = (repo:string) => fetch(`https://api.github.com/repos/${repo}`, {
+  headers: {
+    'content-type': 'application/json',
+    Accept: 'application / vnd.github.v3 + json',
+  },
+}).then((response) => response.json());
+
+interface LTSButtonProps extends LTSDropdownProps {
+  name: string;
+  color: string;
+  LTSVersion: string;
+}
+
+const LTSButton: FC<LTSButtonProps> = (props) => {
+  const {
+    name, setIsLTSDropdownOpen, isLTSDropdownOpen, color, LTSVersion,
+  } = props;
+  return (
+    <Button
+      style={{ display: name === 'APISIX®' ? ' ' : 'NONE' }}
+      onClick={() => setIsLTSDropdownOpen(!isLTSDropdownOpen)}
+      background={color}
+    >
+      <IconDownload />
+      {' '}
+      {`${LTSVersion} LTS`}
+    </Button>
+  );
+};
+
+export interface DownloadInfo {
+  name: string;
+  description: string;
+  shape: string;
+  color: string;
+  githubRepo: string;
+  githubBranch: string;
+  downloadPath: string;
+  dockerhubPath: string;
+  version: string;
+  releaseDate: string;
+  firstDocPath: string;
+  LTSDownloadPath?: string;
+  LTSVersion?: string;
+}
+
+interface ProjectCardProps extends Omit<DownloadInfo, 'firstDocPath'> {
+}
+
+const ProjectCard: FC<ProjectCardProps> = (props) => {
   const [isLTSDropdownOpen, setIsLTSDropdownOpen] = useState(false);
   const [isDropdownOpen, setIsDropdownOpen] = useState(false);
   const [repoStats, setRepoStats] = useState({ stars: 0, issues: 0 });
@@ -66,26 +318,11 @@ const ProjectCard = (props) => {
     githubBranch,
     downloadPath,
     dockerhubPath,
-    LTSDownloadPath = " ",
+    LTSDownloadPath = ' ',
+    LTSVersion,
   } = props;
 
-  const Download =
-    props.name === "APISIX®" ? `${props.version} Current` : "Download";
-
-  const shapeComponent =
-    shape === "triangle" ? (
-      <IconTriangle />
-    ) : shape === "square" ? (
-      <IconSquare />
-    ) : shape === "hexagon" ? (
-      <IconHexagon />
-    ) : shape === "star" ? (
-      <IconStarSolid />
-    ) : shape === "shield" ? (
-      <IconShield />
-    ) : (
-      <IconOctagon />
-    );
+  const Download = name === 'APISIX®' ? `${version} Current` : 'Download';
 
   useEffect(() => {
     getGitHubRepoStats(githubRepo).then((stats) => {
@@ -96,23 +333,11 @@ const ProjectCard = (props) => {
     });
   }, []);
 
-  const LTSButton = () => {
-    return (
-      <Button
-        style={{ display: name === "APISIX®" ? " " : "NONE" }}
-        onClick={() => setIsLTSDropdownOpen(!isLTSDropdownOpen)}
-        background={color}
-      >
-        <IconDownload /> {`${props.LTSVersion} LTS`}
-      </Button>
-    );
-  };
-
   return (
     <Card>
       <LeftSide>
         <Title href={`https://github.com/${githubRepo}`} target="_blank">
-          <ShapeBeforeTitle color={color}>{shapeComponent}</ShapeBeforeTitle>
+          <ShapeBeforeTitle color={color}>{shapeComponentMap[shape]}</ShapeBeforeTitle>
           {name}
         </Title>
         <Description className="downloads-subtitle">{description}</Description>
@@ -123,7 +348,9 @@ const ProjectCard = (props) => {
             target="_blank"
             title="Stars"
           >
-            <IconStar /> {repoStats.stars}
+            <IconStar />
+            {' '}
+            {repoStats.stars}
           </LeftSideLink>
           <LeftSideLink
             className="downloads-leftsidelink"
@@ -131,29 +358,41 @@ const ProjectCard = (props) => {
             target="_blank"
             title="Issues"
           >
-            <IconInfo /> {repoStats.issues}
+            <IconInfo />
+            {' '}
+            {repoStats.issues}
           </LeftSideLink>
           <LeftSideLink
             className="downloads-leftsidelink"
             href={`https://github.com/${githubRepo}/blob/${githubBranch}/CHANGELOG.md`}
             target="_blank"
           >
-            <IconDocumentText /> CHANGELOG
+            <IconDocumentText />
+            {' '}
+            CHANGELOG
           </LeftSideLink>
         </LeftSideLinks>
       </LeftSide>
       <RightSide>
         <VersionInfo className="downloads-versioninfo">
-          Latest Version ·{" "}
+          Latest Version ·
+          {' '}
           <span className="downloads-versioninfo-span">{version}</span>
           <br />
-          Release Date ·{" "}
+          Release Date ·
+          {' '}
           <span className="downloads-versioninfo-span">{releaseDate}</span>
         </VersionInfo>
 
         <ButtonRow>
           <LTSCard>
-            <LTSButton />
+            <LTSButton
+              name={name}
+              color={color}
+              LTSVersion={LTSVersion}
+              isLTSDropdownOpen={isLTSDropdownOpen}
+              setIsLTSDropdownOpen={setIsLTSDropdownOpen}
+            />
             <LTSDropdown
               isLTSDropdownOpen={isLTSDropdownOpen}
               setIsLTSDropdownOpen={setIsLTSDropdownOpen}
@@ -186,7 +425,9 @@ const ProjectCard = (props) => {
               onClick={() => setIsDropdownOpen(!isDropdownOpen)}
               background={color}
             >
-              <IconDownload /> {Download}
+              <IconDownload />
+              {' '}
+              {Download}
             </Button>
             <Dropdown
               isDropdownOpen={isDropdownOpen}
@@ -230,185 +471,4 @@ const ProjectCard = (props) => {
   );
 };
 
-const getGitHubRepoStats = (repo) => {
-  return fetch(`https://api.github.com/repos/${repo}`, {
-    headers: {
-      "content-type": "application/json",
-      Accept: "application / vnd.github.v3 + json",
-    },
-  }).then((response) => response.json());
-};
-
-// styles
-const Card = styled.div`
-  border-radius: 0.75rem;
-  border: 1px solid #eee;
-  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
-  padding: 2rem;
-  display: flex;
-  justify-content: space-between;
-  margin-bottom: 3rem;
-  @media (max-width: 600px) {
-    flex-direction: column;
-    padding: 1rem;
-  }
-`;
-const LeftSide = styled.div`
-  flex-shrink: 2;
-  padding-left: 0.6rem;
-`;
-const Title = styled.a`
-  font-size: 2.4rem;
-  line-height: 2.4rem;
-  margin-bottom: 1rem;
-  font-weight: bold;
-  display: block;
-  cursor: pointer;
-  @media (max-width: 600px) {
-    margin-top: 0px;
-    font-size: 1.6rem;
-  }
-  svg {
-    transition: all 0.6s;
-  }
-  &:hover {
-    color: inherit;
-    text-decoration: none;
-    svg {
-      transform: rotate(360deg);
-    }
-  }
-`;
-const Description = styled.div`
-  font-size: 1.2rem;
-  margin-top: 0px;
-  @media (max-width: 600px) {
-    margin-top: 6px;
-  }
-`;
-const ShapeBeforeTitle = styled.span`
-  margin-right: 12px;
-  & svg {
-    height: 1.75rem;
-    color: ${(props) => props.color || "var(--ifm-color-primary)"};
-  }
-  @media (max-width: 600px) {
-    margin-right: 8px;
-    & svg {
-      height: 1.3rem;
-    }
-  }
-`;
-const LeftSideLinks = styled.div`
-  display: inline-flex;
-  font-size: 1rem;
-  margin-top: 24px;
-  & svg {
-    height: 1rem;
-    margin-right: 4px;
-  }
-`;
-const LeftSideLink = styled.a`
-  display: flex;
-  align-items: center;
-  margin-right: 18px;
-  border-radius: 6px;
-  cursor: pointer;
-  transition: all 0.3s;
-  color: inherit;
-  &:hover {
-    text-decoration: none;
-  }
-`;
-
-const RightSide = styled.div`
-  padding-left: 2rem;
-  display: flex;
-  flex-direction: column;
-  justify-content: space-between;
-  position: relative;
-  flex-shrink: 0;
-  @media (max-width: 600px) {
-    margin-top: 1rem;
-    padding-top: 1rem;
-    border-top: 1px solid #eee;
-    padding-left: 0;
-  }
-`;
-const LTSCard = styled.div`
-  margin-right: 1em;
-  position: relative;
-  display: flex;
-`;
-const ButtonCard = styled.div`
-  margin-right: 0.3em;
-  position: relative;
-  display: flex;
-`;
-const ButtonRow = styled.div`
-  inline-size: auto;
-  display: flex;
-`;
-const Button = styled.button`
-  padding: 12px 18px;
-  font-size: 18px;
-  font-weight: 600;
-  border-radius: 0.5rem;
-  transition: all 0.3s;
-  background: ${(props) => props.background || "var(--ifm-color-primary)"};
-  color: white;
-  border: none;
-  box-sizing: border-box;
-  width: 100%;
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  justify-content: center;
-  cursor: pointer;
-  &:hover {
-    filter: brightness(105%);
-  }
-  svg {
-    height: 22px;
-    margin-right: 4px;
-    padding-bottom: 2px;
-  }
-`;
-const StyledDropdown = styled.div`
-  top: 45px;
-  right: 0;
-  position: absolute;
-  margin-top: 0.25rem;
-  border-radius: 0.5rem;
-  border: 1px solid #eee;
-  z-index: 100;
-  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
-    0 4px 6px -2px rgba(0, 0, 0, 0.05);
-  visibility: ${(props) => (props.open ? "visitable" : "hidden")};
-`;
-const DropdownItem = styled.a`
-  margin: 0.4rem;
-  padding: 0.2rem 1rem 0.2rem 0.5rem;
-  border-radius: 5px;
-  cursor: pointer;
-  font-weight: 500;
-  display: block;
-  color: inherit;
-  &:hover {
-    color: inherit;
-    text-decoration: none;
-  }
-`;
-const VersionInfo = styled.div`
-  text-align: right;
-  font-size: 0.9rem;
-  span {
-    font-weight: 500;
-  }
-  @media (max-width: 600px) {
-    margin-bottom: 1rem;
-    text-align: left;
-  }
-`;
-
 export default ProjectCard;
diff --git a/website/src/pages/downloads/index.js b/website/src/pages/downloads/index.tsx
similarity index 70%
rename from website/src/pages/downloads/index.js
rename to website/src/pages/downloads/index.tsx
index 44596eec88a..67a412ee26e 100644
--- a/website/src/pages/downloads/index.js
+++ b/website/src/pages/downloads/index.tsx
@@ -1,9 +1,11 @@
-import React from "react";
-import styled from "styled-components";
-import Layout from "@theme/Layout";
-import CodeBlock from "@theme/CodeBlock";
-import ProjectCard from "./ProjectCard";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import type { FC } from 'react';
+import React from 'react';
+import styled from 'styled-components';
+import Layout from '@theme/Layout';
+import CodeBlock from '@theme/CodeBlock';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import type { DownloadInfo } from './ProjectCard';
+import ProjectCard from './ProjectCard';
 
 const DownloadsPage = styled.div`
   max-width: var(--ifm-container-width);
@@ -11,15 +13,18 @@ const DownloadsPage = styled.div`
   padding: 2rem var(--ifm-spacing-horizontal);
   width: 100%;
 `;
+
 const PageTitle = styled.h1`
   margin-top: 2rem;
   font-size: 3rem;
   font-weight: 800;
   text-transform: uppercase;
 `;
+
 const PageSubtitle = styled.div`
   margin-bottom: 4rem;
 `;
+
 const Description = styled.div`
   margin-top: 6rem;
   h2 {
@@ -32,14 +37,15 @@ const StyledCodeBlock = styled(CodeBlock)`
   margin-top: 1rem;
 `;
 
-export default (props) => {
+const Downloads: FC = () => {
   const { siteConfig } = useDocusaurusContext();
-  if (!(siteConfig.customFields.downloads || []).length) {
+  const downloads = siteConfig.customFields.downloads as DownloadInfo[] | null;
+
+  if (!downloads?.length) {
     return null;
   }
-  const projects = siteConfig.customFields.downloads.map((project) => {
-    return <ProjectCard key={project.name} {...project} />;
-  });
+
+  const projects = downloads.map((project) => <ProjectCard key={project.name} {...project} />);
 
   return (
     <Layout>
@@ -51,7 +57,7 @@ export default (props) => {
           <h2>History Versions</h2>
           <div className="markdown">
             Find all APISIX releases in the&nbsp;
-            <a href="https://archive.apache.org/dist/apisix/" target="_blank">
+            <a href="https://archive.apache.org/dist/apisix/" target="_blank" rel="noreferrer">
               Archive repository
             </a>
             .
@@ -59,6 +65,7 @@ export default (props) => {
             <a
               href="https://archive.apache.org/dist/incubator/apisix/"
               target="_blank"
+              rel="noreferrer"
             >
               Incubating Archive repository
             </a>
@@ -66,7 +73,7 @@ export default (props) => {
           </div>
           <h2>Verify the releases</h2>
           <div className="markdown">
-            <a href="https://downloads.apache.org/apisix/KEYS" target="_blank">
+            <a href="https://downloads.apache.org/apisix/KEYS" target="_blank" rel="noreferrer">
               Get PGP signatures KEYS
             </a>
             <br />
@@ -77,27 +84,33 @@ export default (props) => {
             get these files from the main distribution directory and not from
             the mirrors.
             <br />
-            <StyledCodeBlock>{`gpg -i KEYS
+            <StyledCodeBlock>
+              {`gpg -i KEYS
 
 # or
 pgpk -a KEYS
 
 # or
-pgp -ka KEYS`}</StyledCodeBlock>
+pgp -ka KEYS`}
+            </StyledCodeBlock>
             <br />
             To verify the binaries/sources you can download the relevant asc
             files for it from main distribution directory and follow the below
             guide.
-            <StyledCodeBlock>{`gpg --verify apache-apisix-********.asc apache-apisix-********
+            <StyledCodeBlock>
+              {`gpg --verify apache-apisix-********.asc apache-apisix-********
 
 # or
 pgpv apache-apisix-********.asc
 
 # or
-pgp apache-apisix-********.asc`}</StyledCodeBlock>
+pgp apache-apisix-********.asc`}
+            </StyledCodeBlock>
           </div>
         </Description>
       </DownloadsPage>
     </Layout>
   );
 };
+
+export default Downloads;
diff --git a/website/src/pages/help.js b/website/src/pages/help.tsx
similarity index 77%
rename from website/src/pages/help.js
rename to website/src/pages/help.tsx
index 9d9869b014c..c87ba81b928 100644
--- a/website/src/pages/help.js
+++ b/website/src/pages/help.tsx
@@ -1,8 +1,10 @@
-import React from "react";
-import styled from "styled-components";
-import "../css/customTheme.css"
-import Layout from "@theme/Layout";
-import ChevronRight from "../assets/icons/chevron-right.svg";
+import type { FC } from 'react';
+import React from 'react';
+import styled from 'styled-components';
+import Layout from '@theme/Layout';
+import ChevronRight from '../assets/icons/chevron-right.svg';
+
+import '../css/customTheme.css';
 
 const PageTitle = styled.h1`
   margin-top: 2rem;
@@ -21,13 +23,8 @@ const Page = styled.div`
   width: 100%;
 `;
 
-function Help(props) {
-  const { config: siteConfig, language = "" } = props;
-  const { baseUrl, docsUrl } = siteConfig;
-  const docsPart = `${docsUrl ? `${docsUrl}/` : ""}`;
-  const langPart = `${language ? `${language}/` : ""}`;
-  const docUrl = (doc) => `${baseUrl}${docsPart}${langPart}${doc}`;
-  return (
+const Help: FC = () => (
+  <Layout>
     <Page className="help-page">
       <PageTitle>NEED HELP?</PageTitle>
       <PageSubtitle>
@@ -50,6 +47,7 @@ function Help(props) {
             <a
               href="https://apisix.apache.org/docs/"
               target="_blank"
+              rel="noreferrer"
             >
               Read Documents
               <ChevronRight />
@@ -65,18 +63,19 @@ function Help(props) {
           </div>
           <p>Ask questions about the documentation and project</p>
           <div className="buttons">
-            <a href="https://github.com/apache/apisix/issues" target="_blank">
+            <a href="https://github.com/apache/apisix/issues" target="_blank" rel="noreferrer">
               GitHub
               <ChevronRight />
             </a>
             <a
               href="https://apisix.apache.org/docs/general/join"
               target="_blank"
+              rel="noreferrer"
             >
               Slack
               <ChevronRight />
             </a>
-            <a href="https://twitter.com/ApacheAPISIX" target="_blank">
+            <a href="https://twitter.com/ApacheAPISIX" target="_blank" rel="noreferrer">
               Twitter
               <ChevronRight />
             </a>
@@ -84,11 +83,7 @@ function Help(props) {
         </div>
       </div>
     </Page>
-  );
-}
-
-export default (props) => (
-  <Layout>
-    <Help {...props} />
   </Layout>
 );
+
+export default Help;
diff --git a/website/src/pages/index.js b/website/src/pages/index.js
deleted file mode 100644
index 7647e40840a..00000000000
--- a/website/src/pages/index.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import React, { useState, useEffect, useLayoutEffect } from "react";
-import useThemeContext from '@theme/hooks/useThemeContext';
-import Layout from "@theme/Layout";
-import useWindowType from "@theme/hooks/useWindowSize";
-
-import HeroSection from "./sections/heroSection";
-import Architecture from "./sections/architecture";
-import Features from "./sections/features";
-import Benefits from "./sections/benefits";
-import Comparison from "./sections/comparison";
-import OpensourcePromo from "./sections/opensourcePromo";
-import HomeEventsSection from "./sections/home-events-section";
-import EndCTA from "./sections/endcta";
-import EventPosterCard from "./sections/components/eventPosterCard";
-
-const useWindowSize = () => {
-  const [size, setSize] = useState([0, 0]);
-  useLayoutEffect(() => {
-    function updateSize() {
-      setSize([window.innerWidth, window.innerHeight]);
-    }
-    window.addEventListener('resize', updateSize);
-    updateSize();
-    return () => window.removeEventListener('resize', updateSize);
-  }, []);
-  return size;
-}
-
-const ThemeResetComponent = () => {
-  const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
-  const windowType = useWindowType();
-
-  useEffect(()=>{
-    if (windowType === 'mobile') {
-      //  remove mode switch at navbar-sidebar
-      const sidebarModeSwitch = document.querySelector("div.navbar-sidebar__brand > div");
-      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");
-      if (navbarModeSwitch) {
-        navbarModeSwitch.style.display = 'none';
-      }
-    }
-  }, [windowType])
-
-  useEffect(() => {
-    if(isDarkTheme) {
-      setLightTheme(true);
-    }
-  }, [isDarkTheme])
-
-  return (null);
-};
-
-const Index = () => {
-
-  const [screenWidth, screenHeight] = useWindowSize();
-
-  return (
-    <Layout>
-      <HeroSection />
-      <Architecture screenWidth={screenWidth} screenHeight={screenHeight} />
-      <Features screenWidth={screenWidth} screenHeight={screenHeight} />
-      <Benefits screenWidth={screenWidth} screenHeight={screenHeight} />
-      <Comparison />
-      <OpensourcePromo />
-      <HomeEventsSection />
-      <EndCTA />
-      <EventPosterCard />
-      <ThemeResetComponent/>
-    </Layout>
-  );
-};
-
-export default Index;
diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx
new file mode 100644
index 00000000000..4347c7a286d
--- /dev/null
+++ b/website/src/pages/index.tsx
@@ -0,0 +1,78 @@
+import type { FC } from 'react';
+import React, { useState, useEffect, useLayoutEffect } from 'react';
+import useThemeContext from '@theme/hooks/useThemeContext';
+import Layout from '@theme/Layout';
+import useWindowType from '@theme/hooks/useWindowSize';
+
+import HeroSection from './sections/HeroSection';
+import Architecture from './sections/Architecture';
+import Features from './sections/Features';
+import Benefits from './sections/Benefits';
+import Comparison from './sections/Comparison';
+import OpensourcePromo from './sections/OpensourcePromo';
+import HomeEventsSection from './sections/HomeEventsSection';
+import EndCTA from './sections/Endcta';
+import EventPosterCard from './sections/components/EventPosterCard';
+
+const useWindowSize = () => {
+  const [size, setSize] = useState([0, 0]);
+  useLayoutEffect(() => {
+    function updateSize() {
+      setSize([window.innerWidth, window.innerHeight]);
+    }
+    window.addEventListener('resize', updateSize);
+    updateSize();
+    return () => window.removeEventListener('resize', updateSize);
+  }, []);
+  return size;
+};
+
+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 = () => {
+  const [screenWidth] = useWindowSize();
+
+  return (
+    <Layout>
+      <HeroSection />
+      <Architecture screenWidth={screenWidth} />
+      <Features />
+      <Benefits screenWidth={screenWidth} />
+      <Comparison />
+      <OpensourcePromo />
+      <HomeEventsSection />
+      <EndCTA />
+      <EventPosterCard />
+      <ThemeResetComponent />
+    </Layout>
+  );
+};
+
+export default Index;
diff --git a/website/src/pages/plugins.js b/website/src/pages/plugins.tsx
similarity index 82%
rename from website/src/pages/plugins.js
rename to website/src/pages/plugins.tsx
index d6a9c8b3a7f..73b0fbca565 100644
--- a/website/src/pages/plugins.js
+++ b/website/src/pages/plugins.tsx
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, { useEffect } from "react";
-import styled from "styled-components";
-import Layout from "@theme/Layout";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
-
+import type { FC } from 'react';
+import React, { useEffect } from 'react';
+import styled from 'styled-components';
+import Layout from '@theme/Layout';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
 
 const PageTitle = styled.h1`
   text-align: center;
@@ -111,7 +111,7 @@ const PluginIcon = styled.div`
   min-height: 200px;
   align-items: center;
   justify-content: center;
-`
+`;
 
 const PluginName = styled.div`
   display: flex;
@@ -186,9 +186,9 @@ const SBeta = styled.div`
       border-color: #e8433e;
     }
   }
-`
+`;
 
-function Plugins(props) {
+const Plugins: FC = () => {
   useEffect(() => {
     const script = document.createElement('script');
     script.type = 'text/javascript';
@@ -197,11 +197,9 @@ function Plugins(props) {
     document.head.appendChild(script);
   }, []);
   const { siteConfig } = useDocusaurusContext();
-  const sidebar = siteConfig.customFields.plugins.map((section) => {
-    return (
-      <SidebarItem key={section.groupName}><a className="sidebar-link" href={`#${section.groupName}`}>{section.groupName}</a></SidebarItem>
-    );
-  });
+  const sidebar = siteConfig.customFields.plugins.map((section) => (
+    <SidebarItem key={section.groupName}><a className="sidebar-link" href={`#${section.groupName}`}>{section.groupName}</a></SidebarItem>
+  ));
 
   const plugins = siteConfig.customFields.plugins.map((section) => {
     const pluginCards = section.plugins.map((plugin) => {
@@ -215,15 +213,17 @@ function Plugins(props) {
         <div key={plugin.name}>
           <PluginCard href={plugin.beta ? `https://apisix.apache.org/docs/apisix/next/plugins/${pluginUrl}` : `https://apisix.apache.org/docs/apisix/plugins/${pluginUrl}`} target="_blank">
             <PluginIcon>
-              {plugin.useDefaultIcon ?
-                <img className="plugin-logo shadow default" src={'/img/plugin/default-icon.png'} alt={plugin.name} /> :
-                <svg className="plugin-logo shadow" aria-hidden="true">
-                  <use xlinkHref={`#icon${plugin.name}`} />
-                </svg>}
+              {plugin.useDefaultIcon
+                ? <img className="plugin-logo shadow default" src="/img/plugin/default-icon.png" alt={plugin.name} />
+                : (
+                  <svg className="plugin-logo shadow" aria-hidden="true">
+                    <use xlinkHref={`#icon${plugin.name}`} />
+                  </svg>
+                )}
             </PluginIcon>
             <PluginName>
               {plugin.name}
-              {plugin.beta && <SBeta title='This plugin will be supported in the next version of Apache APISIX'>Beta</SBeta>}
+              {plugin.beta && <SBeta title="This plugin will be supported in the next version of Apache APISIX">Beta</SBeta>}
             </PluginName>
             <PluginDescription>{plugin.description}</PluginDescription>
             <span className="read-more-link">{'Read more >'}</span>
@@ -242,17 +242,15 @@ function Plugins(props) {
   });
 
   return (
-    <Page>
-      <PageTitle>Apache APISIX®️ Plugin Hub</PageTitle>
-      <PageSubtitle>Powerful Plugins and Easy Integrations</PageSubtitle>
-      <SidebarContainer>{sidebar}</SidebarContainer>
-      {plugins}
-    </Page>
+    <Layout>
+      <Page>
+        <PageTitle>Apache APISIX®️ Plugin Hub</PageTitle>
+        <PageSubtitle>Powerful Plugins and Easy Integrations</PageSubtitle>
+        <SidebarContainer>{sidebar}</SidebarContainer>
+        {plugins}
+      </Page>
+    </Layout>
   );
-}
+};
 
-export default (props) => (
-  <Layout>
-    <Plugins {...props} />
-  </Layout>
-);
+export default Plugins;
diff --git a/website/src/pages/sections/Architecture.tsx b/website/src/pages/sections/Architecture.tsx
new file mode 100644
index 00000000000..d3ee38da1b7
--- /dev/null
+++ b/website/src/pages/sections/Architecture.tsx
@@ -0,0 +1,104 @@
+import type { FC } from 'react';
+import React, { useEffect } from 'react';
+import gsap from 'gsap';
+
+import '../../css/customTheme.css';
+import HLDesign from '../../assets/images/infographs/Architecture.svg';
+import Pattern from '../../assets/images/PatternGrouped.svg';
+
+interface ArchitectureProps {
+  screenWidth: number;
+}
+
+const Architecture: FC<ArchitectureProps> = (props) => {
+  const { screenWidth } = props;
+
+  useEffect(() => {
+    const strokePaths = [];
+    for (let i = 1; i < 28; i += 1) {
+      strokePaths.push(`.PatternGrouped_svg__p${i}`);
+    }
+
+    const tlStroke = gsap.timeline({
+      paused: true,
+      defaults: {
+        ease: 'power2.inOut',
+        yoyo: true,
+        repeat: -1,
+      },
+    });
+
+    tlStroke.fromTo(strokePaths, {
+      strokeDashoffset: 10000,
+    }, {
+      strokeDashoffset: 0,
+      duration: 5,
+      stagger: 0.3,
+      ease: 'power2.inOut',
+      stroke: 'red',
+    });
+
+    const observer = new IntersectionObserver(onIntersection, {
+      root: null,
+      threshold: 0.4,
+    });
+
+    function onIntersection(entries) {
+      entries.forEach((entry) => {
+        if (entry.isIntersecting) {
+          tlStroke.paused(false);
+        } else {
+          tlStroke.paused(true);
+        }
+      });
+    }
+
+    observer.observe(document.querySelector('.arch'));
+
+    return () => {
+      tlStroke.pause(0).kill();
+      observer.disconnect();
+    };
+  }, []);
+
+  return (
+    <div className="arch">
+      <div style={{
+        position: 'absolute', display: 'flex', justifyContent: 'center', alignItems: 'center', height: '120vh',
+      }}
+      >
+        <Pattern
+          className="arch-scale-svg"
+          style={{
+            width: '100vw', strokeWidth: '3', zIndex: '-10', opacity: '0.25', strokeDasharray: '10000',
+          }}
+        />
+      </div>
+      <div>
+        <h3 className="arch-head">Building for large-scale, high value systems</h3>
+      </div>
+      <div className="arch-subtitle">
+        <p>
+          Apache APISIX lets you build Cloud-Native Microservices API gateways,
+          delivering the ultimate performance, security,
+          open source and scalable platform for all your APIs and microservices.
+        </p>
+      </div>
+      <div className="arch-card" style={{ position: 'relative' }}>
+        <div className="hldesign">
+          <HLDesign className="hldesign-graphic" />
+        </div>
+        <div className="arch-card-caption">
+          <p style={{ width: screenWidth >= 768 ? '50%' : '90%' }}>
+            Apache APISIX is based on Nginx and etcd.
+            Compared with traditional API gateways,
+            APISIX has dynamic routing and hot-loading plugins
+          </p>
+        </div>
+        <div className="arch-card-border" />
+      </div>
+    </div>
+  );
+};
+
+export default Architecture;
diff --git a/website/src/pages/sections/Benefits.tsx b/website/src/pages/sections/Benefits.tsx
new file mode 100644
index 00000000000..3744c7aacb1
--- /dev/null
+++ b/website/src/pages/sections/Benefits.tsx
@@ -0,0 +1,413 @@
+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 '../../css/customTheme.css';
+
+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';
+
+interface BenefitsProps {
+  screenWidth: number
+}
+const Benefits: FC<BenefitsProps> = (props) => {
+  const triggerDiv = useRef(null);
+  const performance = useRef(null);
+  const security = useRef(null);
+  const scale = useRef(null);
+  const dynamic = useRef(null);
+  const multiplatform = useRef(null);
+
+  gsap.registerPlugin(ScrollTrigger);
+
+  const { screenWidth } = props;
+
+  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">Performance</h3>
+          <h1 className="feat-head add-left-margin">Ultimate performance </h1>
+          <p className="feat-desc add-left-margin">
+            Apache APISIX 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.
+          </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">Security</h3>
+          <h1 className="feat-head add-left-margin">Shield against the malicious</h1>
+          <p className="feat-desc add-left-margin">
+            Apache APISIX provides multiple security plugins
+            for identity authentication and interface verification,
+            putting stability and security first. For more information, check
+            {' '}
+            <Link style={{ color: '#e8433e' }} to={useBaseUrl('docs/apisix/plugins/cors/')}>here</Link>
+            .
+          </p>
+        </div>
+      </div>
+
+      <div ref={scale} className="row-benefit row-hidden">
+        <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
+          <h3 className="feat-head-desc">Scalability and availability</h3>
+          <h1 className="feat-head add-left-margin">Scales with your users</h1>
+          <p className="feat-desc add-left-margin">
+            Apache APISIX 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.
+          </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">Fully dynamic</h3>
+          <h1 className="feat-head add-left-margin">Save dev-time, design what matters </h1>
+          <p className="feat-desc add-left-margin">
+            Apache APISIX provides Hot updates and Hot plugins,
+            which continuosly update configurations without restarts,
+            saving development time and stress. Health checks,
+            circuit breakers and many more features keep the system balanced at all times.
+          </p>
+        </div>
+      </div>
+
+      <div ref={multiplatform} className="row-benefit row-hidden">
+        <div style={{ width: screenWidth > 768 ? '50%' : '100%' }}>
+          <h3 className="feat-head-desc">Multi-platform and protocol</h3>
+          <h1 className="feat-head add-left-margin">Create once, run anywhere</h1>
+          <p className="feat-desc add-left-margin">
+            Platform agnostic, no vendor lock-in,
+            Apache APISIX can run from bare-metal to kubernetes.
+            It supports HTTP to gRPC transcoding, websockets, gRPC, Dubbo,
+            MQTT proxy and multiple platforms including ARM64,
+            don&apos;t worry about the lock-in of the infra technology.
+          </p>
+        </div>
+        <div className="benefit-infograph">
+          <Multiplatform style={{ width: screenWidth >= 768 ? '50%' : '80%' }} />
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default Benefits;
diff --git a/website/src/pages/sections/Comparison.tsx b/website/src/pages/sections/Comparison.tsx
new file mode 100644
index 00000000000..9af33ad7767
--- /dev/null
+++ b/website/src/pages/sections/Comparison.tsx
@@ -0,0 +1,79 @@
+import type { FC } from 'react';
+import React from 'react';
+
+import '../../css/customTheme.css';
+import Cross from '../../assets/icons/cross.svg';
+import Tick from '../../assets/icons/tick.svg';
+
+const Comparison:FC = () => (
+  <div className="compare">
+    <div>
+      <h3 className="compare-head">Among the best, and always improving</h3>
+    </div>
+    <div className="compare-subtitle">
+      <p>
+        Apache APISIX is opensource and ever evolving.
+        Here&apos;s a general comparison of APISIX with other options in this API Gateway ecosystem.
+      </p>
+    </div>
+    <div>
+      <table className="table">
+        <thead>
+          <tr className="table-head">
+            <th scope="col" style={{ fontWeight: '900' }}>Feature</th>
+            <th scope="col" style={{ background: '#FF90A3' }}>
+              APISIX
+            </th>
+            <th scope="col" style={{ background: '#EBEBEB' }}>
+              Other API Gateways
+            </th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <th scope="row">Single-core CPU, QPS (enable limit-count and prometheus plugins)</th>
+            <td>18000</td>
+            <td>~1700</td>
+          </tr>
+          <tr>
+            <th scope="row">Latency</th>
+            <td>0.2 ms</td>
+            <td>2 ms</td>
+          </tr>
+          <tr>
+            <th scope="row">Dubbo, MQTT, Tengine and REST API to gRPC transcoding</th>
+            <td><Tick /></td>
+            <td><Cross /></td>
+          </tr>
+          <tr>
+            <th scope="row">Configuration rollback</th>
+            <td><Tick /></td>
+            <td><Cross /></td>
+          </tr>
+          <tr>
+            <th scope="row">Custom Load Balancing and routing</th>
+            <td><Tick /></td>
+            <td><Cross /></td>
+          </tr>
+          <tr>
+            <th scope="row">Plug-in hot loading</th>
+            <td><Tick /></td>
+            <td><Cross /></td>
+          </tr>
+          <tr>
+            <th scope="row">Dashboard</th>
+            <td><Tick /></td>
+            <td><Cross /></td>
+          </tr>
+          <tr>
+            <th scope="row">Support any Nginx variable as routing condition</th>
+            <td><Tick /></td>
+            <td><Cross /></td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+  </div>
+);
+
+export default Comparison;
diff --git a/website/src/pages/sections/Endcta.tsx b/website/src/pages/sections/Endcta.tsx
new file mode 100644
index 00000000000..d94c30cc2db
--- /dev/null
+++ b/website/src/pages/sections/Endcta.tsx
@@ -0,0 +1,37 @@
+import type { FC } from 'react';
+import React from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+import '../../css/customTheme.css';
+import ArrowAnim from './components/ArrowAnim';
+
+const EndCTA:FC = () => (
+  <div className="endcta" style={{ padding: '50px 0', background: '#FF90A3', margin: '0 0 -32px 0' }}>
+    <div className="endcta-text">
+      <p style={{
+        display: 'flex', justifyContent: 'center', alignItems: 'center', whiteSpace: 'pre',
+      }}
+      >
+        Try
+        <span style={{ color: '#E8433E' }}>APISIX</span>
+        {' '}
+        today
+        <img className="rocket" src="https://raw.githubusercontent.com/apache/apisix-website/master/website/src/assets/images/rocket.gif" alt="Rocket" />
+      </p>
+    </div>
+    <div className="endcta-btns">
+      <div className="hero-ctas">
+        <Link
+          to={useBaseUrl('downloads')}
+          className="btn btn-download"
+        >
+          Downloads
+        </Link>
+        <ArrowAnim />
+      </div>
+    </div>
+  </div>
+);
+
+export default EndCTA;
diff --git a/website/src/pages/sections/features.jsx b/website/src/pages/sections/Features.tsx
similarity index 69%
rename from website/src/pages/sections/features.jsx
rename to website/src/pages/sections/Features.tsx
index 855e875280a..81fb3173693 100644
--- a/website/src/pages/sections/features.jsx
+++ b/website/src/pages/sections/Features.tsx
@@ -1,38 +1,41 @@
-import React, { useEffect, useRef, useState } from "react";
-import Link from "@docusaurus/Link";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-import gsap from "gsap";
-import { ScrollTrigger } from "gsap/ScrollTrigger";
+import type { FC } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import gsap from 'gsap';
+import { ScrollTrigger } from 'gsap/ScrollTrigger';
+import ArrowAnim from './components/ArrowAnim';
 
-import "../../css/customTheme.css";
-import Dashboard from "../../assets/images/apisix-dashboard.png";
-import Snippet from "../../assets/images/code-sample.png";
-import Plugin from "../../assets/images/pluginised.png";
-import ArrowAnim from "./components/arrowAnim";
+import '../../css/customTheme.css';
+import Dashboard from '../../assets/images/apisix-dashboard.png';
+import Snippet from '../../assets/images/code-sample.png';
+import Plugin from '../../assets/images/pluginised.png';
 
-const DashboardPlayground = () => {
-  return (
-    <Link
-      className={"dashboard-playground-link add-left-margin-feat"}
-      to={"http://106.55.144.26/user/login"}
-    >
-      <div className="dashboard-playground">
-        <h2 className={"dashboard-title"}>Dashboard Playground</h2>
+const DashboardPlayground = () => (
+  <Link
+    className="dashboard-playground-link add-left-margin-feat"
+    to="http://106.55.144.26/user/login"
+  >
+    <div className="dashboard-playground">
+      <h2 className="dashboard-title">Dashboard Playground</h2>
 
-        <div className={"dashboard-account"}>
-          <div>
-            username <span>admin</span>
-          </div>
-          <div>
-            passwd <span>admin</span>
-          </div>
+      <div className="dashboard-account">
+        <div>
+          username
+          {' '}
+          <span>admin</span>
+        </div>
+        <div>
+          passwd
+          {' '}
+          <span>admin</span>
         </div>
       </div>
-    </Link>
-  );
-};
+    </div>
+  </Link>
+);
 
-const Features = () => {
+const Features:FC = () => {
   const dashboardDiv = useRef(null);
   const userfDiv = useRef(null);
   const pluginDiv = useRef(null);
@@ -50,24 +53,24 @@ const Features = () => {
   gsap.registerPlugin(ScrollTrigger);
 
   const [screenWidth, setScreenWidth] = useState(
-    typeof window !== "undefined" && window.innerWidth
+    typeof window !== 'undefined' && window.innerWidth,
   );
-  const [screenHeight, setScreenHeight] = 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);
+    window.addEventListener('resize', resizeEvent, false);
 
-    function resizeEvent(event) {
+    function resizeEvent() {
       setScreenHeight(window.innerHeight);
       setScreenWidth(window.innerWidth);
     }
 
     return () => {
-      window.removeEventListener("resize", resizeEvent);
+      window.removeEventListener('resize', resizeEvent);
     };
   }, []);
 
@@ -75,20 +78,20 @@ const Features = () => {
     const value = window.innerHeight * 2;
 
     let tl;
-    let observers = [];
+    const observers = [];
 
     if (screenWidth > 1100) {
       tl = gsap.timeline({
         defaults: {
-          ease: "linear",
+          ease: 'linear',
         },
         scrollTrigger: {
-          id: "feat",
+          id: 'feat',
           trigger: triggerDiv.current,
-          start: "top top",
+          start: 'top top',
           pin: pinDiv.current,
           scrub: 1.5,
-          end: value + "px",
+          end: `${value}px`,
         },
       });
 
@@ -108,10 +111,10 @@ const Features = () => {
       // Mobile
 
       const elems = [img1col.current, img2col.current, img3col.current];
-      for (let i = 1; i < 4; i++) {
+      for (let i = 1; i < 4; i += 1) {
         observers.push(
           new IntersectionObserver(
-            (entries, opts) => {
+            (entries) => {
               entries.forEach((entry) => {
                 if (entry.isIntersecting) {
                   observers[i - 1].disconnect();
@@ -125,10 +128,10 @@ const Features = () => {
                       opacity: 1,
                       y: 0,
                       duration: 0.5,
-                      ease: "power3.out",
+                      ease: 'power3.out',
                       yoyo: true,
-                      yoyoEase: "power3.inOut",
-                    }
+                      yoyoEase: 'power3.inOut',
+                    },
                   );
                 }
               });
@@ -136,8 +139,8 @@ const Features = () => {
             {
               root: null,
               threshold: 0.2,
-            }
-          )
+            },
+          ),
         );
       }
 
@@ -149,7 +152,7 @@ const Features = () => {
 
   return (
     <>
-      <div ref={featPin} className="feat-top" style={{ padding: "50px 0" }}>
+      <div ref={featPin} className="feat-top" style={{ padding: '50px 0' }}>
         <h3 className="feat-head-desc">Why APISIX ?</h3>
         <h1 className="feat-head add-left-margin">
           Reduce time fighting bugs, focus on designing world-class systems
@@ -162,9 +165,9 @@ const Features = () => {
       </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" }}>
+        <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">
                 Easy-to-use dashboard
               </h2>
@@ -175,7 +178,7 @@ const Features = () => {
                 contribute.
               </p>
               <div className="hero-ctas add-left-margin-feat bottom-pos">
-                <Link to={useBaseUrl("downloads")} className="btn btn-download">
+                <Link to={useBaseUrl('downloads')} className="btn btn-download">
                   Downloads
                 </Link>
                 <ArrowAnim />
@@ -184,8 +187,8 @@ const Features = () => {
             </div>
           </div>
 
-          <div ref={userfDiv} style={{ position: "relative" }}>
-            <div className="text-div" style={{ height: "100vh" }}>
+          <div ref={userfDiv} style={{ position: 'relative' }}>
+            <div className="text-div" style={{ height: '100vh' }}>
               <h2 className="i-text add-left-margin-feat">User flexible</h2>
               <p className="i-text-desc add-left-margin-feat">
                 The Apache APISIX dashboard is flexible to User demand,
@@ -195,8 +198,8 @@ const Features = () => {
             </div>
           </div>
 
-          <div ref={pluginDiv} style={{ position: "relative" }}>
-            <div className="text-div" style={{ height: "100vh" }}>
+          <div ref={pluginDiv} style={{ position: 'relative' }}>
+            <div className="text-div" style={{ height: '100vh' }}>
               <h2 className="i-text add-left-margin-feat">
                 Pluginised workflow
               </h2>
@@ -214,13 +217,13 @@ const Features = () => {
           ref={pinDiv}
           className="right-pane"
           style={{
-            width: "50%",
-            height: "100vh",
-            position: "relative",
-            overflow: "hidden",
-            display: "flex",
-            alignItems: "center",
-            justifyContent: "center",
+            width: '50%',
+            height: '100vh',
+            position: 'relative',
+            overflow: 'hidden',
+            display: 'flex',
+            alignItems: 'center',
+            justifyContent: 'center',
           }}
         >
           <img
@@ -249,16 +252,16 @@ const Features = () => {
       <div
         className="feat-container-m"
         ref={triggerDivCol}
-        style={{ width: "100%" }}
+        style={{ width: '100%' }}
       >
         {/* Mobile */}
         <div
           ref={img1col}
           className="hiddenDiv-col"
-          style={{ height: "fit-content", padding: "0 0 40px 0" }}
+          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 style={{ position: 'relative', height: '100%' }}>
+            <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
               Easy-to-use dashboard
             </h2>
             <img className="i-image-col" src={Dashboard} alt="" />
@@ -270,9 +273,9 @@ const Features = () => {
             </p>
             <div
               className="hero-ctas add-left-margin"
-              style={{ width: "fit-content" }}
+              style={{ width: 'fit-content' }}
             >
-              <Link to={useBaseUrl("downloads")} className="btn btn-download">
+              <Link to={useBaseUrl('downloads')} className="btn btn-download">
                 Downloads
               </Link>
               <ArrowAnim />
@@ -283,9 +286,9 @@ const Features = () => {
         <div
           ref={img2col}
           className="hiddenDiv-col"
-          style={{ height: "fit-content", padding: "20px 0" }}
+          style={{ height: 'fit-content', padding: '20px 0' }}
         >
-          <h2 className="add-left-margin" style={{ width: "fit-content" }}>
+          <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
             User flexible
           </h2>
           <img className="i-image-col" src={Snippet} alt="" />
@@ -299,9 +302,9 @@ const Features = () => {
         <div
           ref={img3col}
           className="hiddenDiv-col"
-          style={{ height: "fit-content", padding: "20px 0" }}
+          style={{ height: 'fit-content', padding: '20px 0' }}
         >
-          <h2 className="add-left-margin" style={{ width: "fit-content" }}>
+          <h2 className="add-left-margin" style={{ width: 'fit-content' }}>
             Pluginised workflow
           </h2>
           <img className="i-image-col" src={Plugin} alt="" />
diff --git a/website/src/pages/sections/HeroSection.tsx b/website/src/pages/sections/HeroSection.tsx
new file mode 100644
index 00000000000..fa0c4272db9
--- /dev/null
+++ b/website/src/pages/sections/HeroSection.tsx
@@ -0,0 +1,68 @@
+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 '../../css/customTheme.css';
+import HeroCanvas from './components/HeroCanvas';
+import ArrowAnim from './components/ArrowAnim';
+
+const HeroSection:FC = () => {
+  const titleRef = useRef<HTMLHeadingElement>();
+  const subtitleRef = useRef<HTMLHeadingElement>();
+  const ctaRef = useRef<HTMLHeadingElement>();
+  const canRef = useRef<HTMLHeadingElement>();
+
+  useEffect(() => {
+    const tl = gsap.timeline({
+      defaults: {
+        delay: window.innerWidth >= 768 ? 1.5 : 0.01,
+        duration: 0.5,
+        ease: 'Expo.easeInOut',
+      },
+    });
+
+    tl.fromTo([titleRef.current, subtitleRef.current, ctaRef.current], {
+      opacity: 0,
+      y: 10,
+    }, {
+      opacity: 1,
+      y: 0,
+      stagger: 0.3,
+    });
+
+    return () => {
+      tl.pause(0).kill();
+    };
+  }, []);
+
+  return (
+    <div className="hero-sec-wrap" style={{ width: '100%' }}>
+      <div className="hero-text">
+        <h2 ref={titleRef} className="hero-title hide-title">
+          <span>Effortless and smooth</span>
+          {' '}
+          <span style={{ color: '#E8433E' }}>API Traffic</span>
+          {' '}
+          management.
+        </h2>
+        <h3 ref={subtitleRef} className="hero-subtitle hide-subtitle">Apache APISIX provides rich traffic management features like Load Balancing, Dynamic Upstream, Canary Release, Circuit Breaking, Authentication, Observability, and more...</h3>
+        <div ref={ctaRef} className="hero-ctas hide-ctas">
+          <Link
+            to={useBaseUrl('downloads')}
+            className="btn btn-download"
+          >
+            Downloads
+          </Link>
+          <ArrowAnim />
+        </div>
+      </div>
+      <div ref={canRef} className="add-margin">
+        <HeroCanvas />
+      </div>
+    </div>
+  );
+};
+
+export default HeroSection;
diff --git a/website/src/pages/sections/home-events-section.jsx b/website/src/pages/sections/HomeEventsSection.tsx
similarity index 54%
rename from website/src/pages/sections/home-events-section.jsx
rename to website/src/pages/sections/HomeEventsSection.tsx
index 8a50210e9f2..0c3d94699c6 100644
--- a/website/src/pages/sections/home-events-section.jsx
+++ b/website/src/pages/sections/HomeEventsSection.tsx
@@ -1,26 +1,34 @@
-import React from "react";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import type { FC } from 'react';
+import React from 'react';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
 
-import "../../css/customTheme.css";
-import ChevronRight from "../../assets/icons/chevron-right.svg";
+import '../../css/customTheme.css';
+import ChevronRight from '../../assets/icons/chevron-right.svg';
 
-const HomeEventsSection = () => {
+interface EventInfo {
+  title: string;
+  fileName: string;
+}
+
+const HomeEventsSection:FC = () => {
   const { siteConfig } = useDocusaurusContext();
-  const events = (siteConfig.customFields.events || [])
+  const events = (siteConfig.customFields.events as EventInfo[])
     .slice(0, 4)
     .map((event) => {
       const publishTime = event.fileName.slice(0, 10);
-      const splittedFileName = event.fileName.split("-");
+      const splittedFileName = event.fileName.split('-');
       const url = `/blog/${splittedFileName
         .slice(0, 3)
-        .join("/")}/${splittedFileName.slice(3).join("-")}`;
+        .join('/')}/${splittedFileName.slice(3).join('-')}`;
       return (
         <div className="event-card" key={event.title}>
-          <a className="event-item" href={url} target="_blank">
+          <a className="event-item" href={url} target="_blank" rel="noreferrer">
             <div className="event-card-title">{event.title}</div>
             <div className="event-card-time">{publishTime}</div>
             <div className="event-card-read">
-              Read <ChevronRight style={{ width: "6px" }} />
+              Read
+              {' '}
+              <ChevronRight style={{ width: '6px' }} />
             </div>
           </a>
         </div>
@@ -28,17 +36,17 @@ const HomeEventsSection = () => {
     });
 
   return (
-    <div className="news" style={{ padding: "50px 0" }}>
+    <div className="news" style={{ padding: '50px 0' }}>
       <div>
         <h3
           className="docs-promo-head"
-          style={{ width: "100%", textAlign: "center", left: "0" }}
+          style={{ width: '100%', textAlign: 'center', left: '0' }}
         >
           Stay updated about APISIX
         </h3>
         <p
           className="docs-promo-subtitle"
-          style={{ width: "100%", textAlign: "center", left: "0" }}
+          style={{ width: '100%', textAlign: 'center', left: '0' }}
         >
           Some Recent events
         </p>
@@ -46,8 +54,9 @@ const HomeEventsSection = () => {
       </div>
       <div className="newsletter">
         <p>
-          Stay up to date about all Apache APISIX™ News, subscribe to our{" "}
-          <a hred="%">newsletter.</a>
+          Stay up to date about all Apache APISIX™ News, subscribe to our
+          {' '}
+          <a href="%">newsletter.</a>
         </p>
         <a className="news-button" href="/docs/general/join">
           Subscribe
diff --git a/website/src/pages/sections/OpensourcePromo.tsx b/website/src/pages/sections/OpensourcePromo.tsx
new file mode 100644
index 00000000000..2735044328e
--- /dev/null
+++ b/website/src/pages/sections/OpensourcePromo.tsx
@@ -0,0 +1,57 @@
+import type { FC } from 'react';
+import React from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+import OssCanvas from './components/OssCanvas';
+
+import '../../css/customTheme.css';
+import GitHub from '../../assets/icons/github-logo.svg';
+
+const OpensourcePromo: FC = () => (
+  <div className="ossPromotion">
+    <div className="docs-promo">
+      <div className="docs-promo-text">
+        <h3 className="docs-promo-head">Learn from developers</h3>
+        <div className="docs-promo-subtitle">
+          <p>
+            Want to learn Apache APISIX usage, but don&apos;t know where to start. Check out our
+            {' '}
+            <Link style={{ color: '#e8433e' }} to={useBaseUrl('docs')}>docs.</Link>
+          </p>
+          <p>
+            Like visual information, check out our
+            {' '}
+            <a style={{ color: '#e8433e' }} href="https://www.youtube.com/channel/UCgPD18cMhOg5rmPVnQhAC8g">Youtube channel</a>
+            {' '}
+            for detailed tutorials. Subscribe for more.
+          </p>
+        </div>
+      </div>
+      <div className="docs-promo-video">
+        <video preload="none" src="https://static.apiseven.com/apisix-website/videos/apisix.mp4" loading="lazy" autoPlay poster="" muted loop width="70%" height="auto" controls />
+      </div>
+    </div>
+
+    <div className="oss-promo">
+      <div className="oss-promo-text">
+        <h3 className="oss-promo-head">Be a part of building APISIX</h3>
+        <div className="oss-promo-subtitle" style={{ color: 'rgb(199, 199, 199)' }}>
+          <p>
+            Apache APISIX is opensource and ever-growing.
+            Contributors are always welcome. Reach out to us on GitHub
+          </p>
+          <div className="oss-promo-cta">
+            <GitHub style={{ width: '20px', margin: '0 10px 0 0' }} />
+            <a href="https://github.com/apache/apisix" style={{ textDecoration: 'none' }}>Check us out</a>
+          </div>
+        </div>
+      </div>
+      <div className="oss-promo-infograph">
+        <OssCanvas />
+      </div>
+    </div>
+  </div>
+);
+
+export default OpensourcePromo;
diff --git a/website/src/pages/sections/architecture.jsx b/website/src/pages/sections/architecture.jsx
deleted file mode 100644
index abcc2f9e24d..00000000000
--- a/website/src/pages/sections/architecture.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import React, { useEffect } from "react";
-import gsap from "gsap";
-
-import "../../css/customTheme.css";
-import HLDesign from "../../assets/images/infographs/Architecture.svg";
-import Pattern from "../../assets/images/PatternGrouped.svg";
-
-const Architecture = (props) => {
-  const screenWidth = props.screenWidth;
-
-  useEffect(() => {
-    let strokePaths = []
-    for (let i=1; i<28; i++) {
-      strokePaths.push(".PatternGrouped_svg__p"+i);
-    } 
-
-    let tlStroke = gsap.timeline({
-      paused: true,
-      defaults: {
-        ease: "power2.inOut",
-        yoyo: true,
-        repeat: -1,
-      },
-    });
-
-    tlStroke.fromTo(strokePaths, {
-      strokeDashoffset: 10000
-    }, {
-      strokeDashoffset: 0,
-      duration: 5,
-      stagger: 0.3,
-      ease: "power2.inOut",
-      stroke: "red",
-    });
-
-    let observer = new IntersectionObserver(onIntersection, {
-      root: null,
-      threshold: 0.4,
-    })
-      
-    function onIntersection(entries, opts){
-      entries.forEach(entry =>  {
-        if (entry.isIntersecting) {
-          tlStroke.paused(false);
-        } else {
-          tlStroke.paused(true);
-        }
-      }
-      );
-    }
-      
-    observer.observe( document.querySelector('.arch'));
-    
-    return () => {
-      tlStroke.pause(0).kill(true);
-      observer.disconnect();
-    }
-  }, []);
-
-  return (
-    <>
-      <div className="arch">
-        <div style={{position: "absolute", display: "flex", justifyContent: "center", alignItems: "center", height: "120vh"}}>
-          <Pattern className="arch-scale-svg" style={{width: "100vw", strokeWidth: "3", zIndex: "-10", opacity: "0.25", strokeDasharray: "10000"}}/>
-        </div>
-        <div>
-          <h3 className="arch-head">Building for large-scale, high value systems</h3>
-        </div>
-        <div className="arch-subtitle">
-          <p>Apache APISIX lets you build Cloud-Native Microservices API gateways, delivering the ultimate performance, security, open source and scalable platform for all your APIs and microservices.</p> 
-        </div>
-        <div className="arch-card" style={{position: "relative"}}>
-          <div className="hldesign">
-            <HLDesign className="hldesign-graphic"/>
-          </div>
-          <div className="arch-card-caption">
-            <p style={{width: screenWidth >=768 ? "50%" : "90%"}}>Apache APISIX is based on Nginx and etcd. Compared with traditional API gateways, APISIX has dynamic routing and hot-loading plugins</p>
-          </div>
-          <div className="arch-card-border">
-          </div>
-        </div>
-      </div>
-    </>
-  );
-}
-  
-export default Architecture;
diff --git a/website/src/pages/sections/benefits.jsx b/website/src/pages/sections/benefits.jsx
deleted file mode 100644
index ad429e4bfd8..00000000000
--- a/website/src/pages/sections/benefits.jsx
+++ /dev/null
@@ -1,386 +0,0 @@
-import React, { useRef, useEffect, useState } from "react";
-import Link from "@docusaurus/Link";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-import gsap from "gsap"
-import { ScrollTrigger } from "gsap/ScrollTrigger";
-
-import "../../css/customTheme.css";
-
-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";
-
-const Benefits = (props) => {
-  const triggerDiv = useRef(null);
-  const performance = useRef(null);
-  const security = useRef(null);
-  const scale = useRef(null);
-  const dynamic = useRef(null);
-  const multiplatform = useRef(null);
-
-  gsap.registerPlugin(ScrollTrigger);
-
-  const screenWidth = props.screenWidth;
-
-  useEffect(() => {
-    let tweenTls = [];
-    let observers = [];
-
-    for (let i=0; i<5; i++) {
-      tweenTls.push(gsap.timeline({
-        paused: true,
-        yoyo: true, 
-        yoyoEase: "power3.out",
-        repeat: -1,
-        defaults: {
-          yoyo: true,
-          ease: "power3.inOut",
-          yoyoEase: "power3.out"
-        },
-      }));
-    }
-
-    let circles = [];
-    let links = [];
-    const colors = ["#FE7F80", "white", "red"];
-    const pathColors = ["#FE7F80", "black"];
-
-    for (let i=1; i<28; i++) {
-      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++) {
-      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++) { 
-      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++) {
-      tweenTls[4].fromTo(".multiplatform_svg__server-port"+i,{    
-        fill: "#60E0F2",
-      },{
-        fill: "#ffdc21",
-        duration: 0.5,
-      });
-    }
-    
-    let 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, opts){
-      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++) {
-      observers.push(new IntersectionObserver((entries, opts)=>{
-        entries.forEach(entry =>  {
-          if (entry.isIntersecting) {
-            tweenTls[i].paused(false);
-          } else {
-            tweenTls[i].paused(true);
-          }
-        }
-        );
-      }, {
-        root: null,
-        threshold: .2
-      }));
-    }
-
-    observers.forEach((it, index)=>{
-      it.observe(elems[index]);
-    });
-
-    return () => {
-      observers.forEach((it, index)=>{
-        it.disconnect();
-      });
-      tweenTls.forEach((it, index)=>{
-        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">Performance</h3>
-            <h1 className="feat-head add-left-margin">Ultimate performance </h1>
-            <p className="feat-desc add-left-margin"> 
-            Apache APISIX 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.                        
-            </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">Security</h3>
-            <h1 className="feat-head add-left-margin">Shield against the malicious</h1>
-            <p className="feat-desc add-left-margin"> 
-            Apache APISIX provides multiple security plugins for identity authentication and interface verification, putting stability and security first. For more information, check <Link style={{color: "#e8433e"}} to={useBaseUrl("docs/apisix/plugins/cors/")}>here</Link>.
-            </p>
-          </div>
-        </div>
-
-        <div ref={scale} className="row-benefit row-hidden" >
-          <div style={{width: screenWidth > 768 ? "50%" : "100%"}}>
-            <h3 className="feat-head-desc">Scalability and availability</h3>
-            <h1 className="feat-head add-left-margin">Scales with your users</h1>
-            <p className="feat-desc add-left-margin"> 
-              Apache APISIX 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.
-            </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">Fully dynamic</h3>
-            <h1 className="feat-head add-left-margin">Save dev-time, design what matters </h1>
-            <p className="feat-desc add-left-margin"> 
-              Apache APISIX provides Hot updates and Hot plugins, which continuosly update configurations without restarts, saving development time and stress. Health checks, circuit breakers and many more features keep the system balanced at all times.
-            </p>
-          </div>
-        </div>
-
-        <div ref={multiplatform} className="row-benefit row-hidden" >
-          <div style={{width: screenWidth > 768 ? "50%" : "100%"}}>
-            <h3 className="feat-head-desc">Multi-platform and protocol</h3>
-            <h1 className="feat-head add-left-margin">Create once, run anywhere</h1>
-            <p className="feat-desc add-left-margin"> 
-              Platform agnostic, no vendor lock-in, Apache APISIX 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.
-            </p>
-          </div>
-          <div className="benefit-infograph">
-            <Multiplatform style={{width: screenWidth >=768 ? "50%" : "80%"}}/>
-          </div>
-        </div>
-      </div>
-    </>
-  );
-}
-  
-export default Benefits;
diff --git a/website/src/pages/sections/comparison.jsx b/website/src/pages/sections/comparison.jsx
deleted file mode 100644
index 11ef8e1945a..00000000000
--- a/website/src/pages/sections/comparison.jsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from "react";
-
-import "../../css/customTheme.css";
-import Cross from "../../assets/icons/cross.svg";
-import Tick from "../../assets/icons/tick.svg";
-
-const Comparison = () => {
-  return (
-    <>
-      <div className="compare">
-        <div>
-          <h3 className="compare-head">Among the best, and always improving</h3>
-        </div>
-        <div className="compare-subtitle">
-          <p>Apache APISIX is opensource and ever evolving. Here’s a general comparison of APISIX with other options in this API Gateway ecosystem.</p> 
-        </div>
-        <div>
-          <table className="table">
-            <thead>
-              <tr className="table-head">
-                <th scope="col" style={{fontWeight: "900"}}>Feature</th>
-                <th scope="col" style={{background: "#FF90A3"}}>
-                  APISIX
-                </th>
-                <th scope="col" style={{background: "#EBEBEB"}}>
-                  Other API Gateways
-                </th>
-              </tr>
-            </thead>
-            <tbody>
-              <tr>
-                <th scope="row">Single-core CPU, QPS (enable limit-count and prometheus plugins)</th>
-                <td>18000</td>
-                <td>~1700</td>
-              </tr>
-              <tr>
-                <th scope="row">Latency</th>
-                <td>0.2 ms</td>
-                <td>2 ms</td>
-              </tr>
-              <tr>
-                <th scope="row">Dubbo, MQTT, Tengine and REST API to gRPC transcoding</th>
-                <td><Tick /></td>
-                <td><Cross /></td>
-              </tr>
-              <tr>
-                <th scope="row">Configuration rollback</th>
-                <td><Tick /></td>
-                <td><Cross /></td>
-              </tr>
-              <tr>
-                <th scope="row">Custom Load Balancing and routing</th>
-                <td><Tick /></td>
-                <td><Cross /></td>
-              </tr>
-              <tr>
-                <th scope="row">Plug-in hot loading</th>
-                <td><Tick /></td>
-                <td><Cross /></td>
-              </tr>
-              <tr>
-                <th scope="row">Dashboard</th>
-                <td><Tick /></td>
-                <td><Cross /></td>
-              </tr>
-              <tr>
-                <th scope="row">Support any Nginx variable as routing condition</th>
-                <td><Tick /></td>
-                <td><Cross /></td>
-              </tr>
-            </tbody>
-          </table>
-        </div>
-      </div>
-    </>
-  );
-}
-  
-export default Comparison;
diff --git a/website/src/pages/sections/components/ArrowAnim.tsx b/website/src/pages/sections/components/ArrowAnim.tsx
new file mode 100644
index 00000000000..3af142a169d
--- /dev/null
+++ b/website/src/pages/sections/components/ArrowAnim.tsx
@@ -0,0 +1,65 @@
+import type { FC } from 'react';
+import React, { useCallback, useRef } from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import gsap from 'gsap';
+
+import '../../../css/customTheme.css';
+
+const ArrowAnim: FC = () => {
+  const endpathRef1 = useRef(null);
+  const endpathRef2 = useRef(null);
+
+  const mouseOver = useCallback(
+    () => {
+      gsap.to([endpathRef2.current], {
+        strokeDashoffset: 970,
+        duration: 0.4,
+      });
+      gsap.to([endpathRef1.current], {
+        stroke: '#9b9b9b',
+        duration: 0.4,
+      });
+      gsap.to([endpathRef2.current], {
+        stroke: '#9b9b9b',
+        duration: 0.4,
+      });
+    },
+    [],
+  );
+
+  const mouseOut = useCallback(
+    () => {
+      gsap.to([endpathRef2.current], {
+        strokeDashoffset: 1002,
+        duration: 0.4,
+      });
+      gsap.to([endpathRef1.current], {
+        stroke: 'black',
+        duration: 0.4,
+      });
+      gsap.to([endpathRef2.current], {
+        stroke: 'black',
+        duration: 0.4,
+      });
+    },
+    [],
+  );
+
+  return (
+    <Link
+      to={useBaseUrl('docs')}
+      onMouseOver={mouseOver}
+      onMouseLeave={mouseOut}
+      className="btn-docs"
+    >
+      Go to docs...
+      <svg width="15" strokeWidth="3" height="25" viewBox="0 0 43 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+        <path ref={endpathRef1} d="M27.5 1L42.5 16L27.5 31" stroke="black" strokeLinecap="round" strokeLinejoin="round" />
+        <path ref={endpathRef2} className="arrow-btn" d="M42.5 16H0.5" stroke="black" strokeLinecap="round" strokeLinejoin="round" />
+      </svg>
+    </Link>
+  );
+};
+
+export default ArrowAnim;
diff --git a/website/src/pages/sections/components/EventPosterCard.tsx b/website/src/pages/sections/components/EventPosterCard.tsx
new file mode 100644
index 00000000000..f063a37ce2c
--- /dev/null
+++ b/website/src/pages/sections/components/EventPosterCard.tsx
@@ -0,0 +1,89 @@
+import type { FC } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import gsap from 'gsap';
+
+import '../../../css/customTheme.css';
+
+interface EventPosterCardInfo {
+  show: boolean;
+  expire: string;
+  image: string;
+  link: string;
+}
+
+const EventPosterCard:FC = () => {
+  const { siteConfig } = useDocusaurusContext();
+  const {
+    show, expire, link, image,
+  } = siteConfig.customFields.eventPosterCard as EventPosterCardInfo;
+  const [display, setDisplay] = useState(false);
+  const picRef = useRef(null);
+
+  useEffect(() => {
+    gsap.fromTo(picRef.current, {
+      x: 500,
+      opacity: 0,
+    }, {
+      x: 0,
+      opacity: 1,
+      delay: 3.0,
+    });
+  }, []);
+
+  useEffect(() => {
+    if (!localStorage.getItem('SHOW_EVENT_ENTRY')) {
+      setDisplay(true);
+    }
+
+    if (!show) {
+      setDisplay(false);
+    } else {
+      const expireTimestamp = new Date(expire).getTime();
+      if (expireTimestamp <= new Date().getTime()) {
+        setDisplay(false);
+      }
+    }
+  }, []);
+
+  const onClose = () => {
+    gsap.to(picRef.current, {
+      x: 500,
+      opacity: 0,
+      onComplete: () => {
+        setDisplay(false);
+      },
+    });
+    if (typeof window !== 'undefined') {
+      localStorage.setItem('SHOW_EVENT_ENTRY', 'true');
+    }
+  };
+
+  if (!display) {
+    return null;
+  }
+
+  return (
+    <div ref={picRef} className="pic-wrapper">
+      <button className="pic-wrapper-close" onClick={onClose} type="button">
+        <svg
+          aria-hidden="true"
+          focusable="false"
+          data-prefix="fas"
+          data-icon="times"
+          className="svg-inline--fa fa-times fa-w-11"
+          role="img"
+          xmlns="http://www.w3.org/2000/svg"
+          viewBox="0 0 352 512"
+        >
+          <path fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" />
+        </svg>
+      </button>
+      <a href={link} onClick={onClose}>
+        <img src={image} alt="" />
+      </a>
+    </div>
+  );
+};
+
+export default EventPosterCard;
diff --git a/website/src/pages/sections/components/HeroCanvas.tsx b/website/src/pages/sections/components/HeroCanvas.tsx
new file mode 100644
index 00000000000..c2ce719c221
--- /dev/null
+++ b/website/src/pages/sections/components/HeroCanvas.tsx
@@ -0,0 +1,248 @@
+import type { FC } from 'react';
+import React, { useRef, useEffect } from 'react';
+import * as THREE from 'three';
+import gsap from 'gsap';
+
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
+
+import '../../../css/customTheme.css';
+import vertex from '!!raw-loader!../../../shaders/vertex.vert';
+import fragment from '!!raw-loader!../../../shaders/fragment.frag';
+
+const HeroCanvas: FC = () => {
+  const canvasRef = useRef<HTMLCanvasElement>();
+  const overlayRef = useRef<HTMLDivElement>();
+
+  let canvasHeight: number;
+  let canvasWidth: number;
+  let screenWidth: number;
+  let screenHeight: number;
+  let controls: OrbitControls;
+  let isLoaded = false;
+  let isRendering = false;
+  let animationFrame: number;
+
+  useEffect(() => {
+    screenWidth = window.innerWidth;
+    screenHeight = window.innerHeight;
+
+    const mouse = { x: 0.5, y: 0.5 };
+    const fragMouse = { x: 0.5, y: 0.5 };
+
+    let camera; let mesh; let scene; let renderer; let material; let
+      geometry;
+
+    window.addEventListener('resize', onWindowResize, false);
+
+    if (screenWidth > 1100) {
+      canvasHeight = screenHeight;
+      canvasWidth = screenWidth / 2;
+    } else {
+      canvasHeight = screenHeight / 2;
+      canvasWidth = screenWidth;
+    }
+
+    canvasRef.current.width = canvasWidth;
+    canvasRef.current.height = canvasHeight;
+
+    canvasRef.current.addEventListener('mousemove', (event) => {
+      const ctx = {
+        x: (event.clientX),
+        y: (event.clientY),
+      };
+
+      const canvasOffset = {
+        left: canvasRef.current.getBoundingClientRect().x,
+        top: canvasRef.current.getBoundingClientRect().y,
+      };
+
+      ctx.x = ((ctx.x - canvasOffset.left) / canvasWidth);
+      ctx.y = ((ctx.y - canvasOffset.top) / canvasHeight);
+
+      gsap.to(mouse, 2, {
+        x: ctx.x * (canvasWidth / canvasHeight) - (canvasWidth / canvasHeight) / 2,
+        y: (1.0 - ctx.y) - 0.5,
+        onUpdate: () => {
+          material.uniforms.u_mouse.value.x = mouse.x;
+          material.uniforms.u_mouse.value.y = mouse.y;
+        },
+      });
+
+      gsap.to(fragMouse, 2, {
+        x: ctx.x,
+        y: (1.0 - ctx.y),
+        onUpdate: () => {
+          material.uniforms.u_fragMouse.value.x = fragMouse.x;
+          material.uniforms.u_fragMouse.value.y = fragMouse.y;
+        },
+      });
+    });
+
+    function getRandom(a, b) {
+      return a + (b - a) * Math.random();
+    }
+
+    const canvasObserver = new IntersectionObserver(onCanvasIntersection, {
+      root: null,
+      threshold: 0.01,
+    });
+
+    init(canvasWidth, canvasHeight);
+
+    function onCanvasIntersection(entries) {
+      entries.forEach((entry) => {
+        if (entry.isIntersecting && isLoaded) {
+          if (isLoaded && !isRendering) {
+            animate();
+          } else {
+            console.log('Loading');
+          }
+        } else {
+          if (animationFrame) {
+            cancelAnimationFrame(animationFrame);
+            isRendering = false;
+          }
+        }
+      });
+    }
+
+    canvasObserver.observe(canvasRef.current);
+
+    function init(width: number, height: number) {
+      const ctx = canvasRef.current;
+
+      renderer = new THREE.WebGLRenderer({ canvas: ctx });
+      renderer.autoClearColor = false;
+
+      camera = new THREE.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);
+
+      const { count } = geometry.attributes.position;
+      const arrSize = new THREE.BufferAttribute(new Float32Array(count), 1);
+
+      for (let i = 0; i < arrSize.count; i += 1) {
+        arrSize.array[i] = getRandom(0, 1);
+      }
+      geometry.setAttribute('aSize', arrSize, 1);
+
+      geometry.scale(2.0, 1.0, 1.0);
+
+      scene = new THREE.Scene();
+      renderer.setSize(canvasWidth, canvasHeight);
+
+      const uniforms = {
+        u_time: {
+          type: 'f',
+          value: 1.0,
+        },
+        u_resolution: {
+          type: 'v2',
+          value: new THREE.Vector2(),
+        },
+        u_mouse: {
+          type: 'v2',
+          value: new THREE.Vector2(0.5, 0.5),
+        },
+        u_fragMouse: {
+          type: 'v2',
+          value: new THREE.Vector2(0.5, 0.5),
+        },
+      };
+
+      scene.background = new THREE.Color('red');
+
+      camera.position.z = 5;
+      controls.update();
+
+      material = new THREE.ShaderMaterial({
+        uniforms,
+        vertexShader: vertex,
+        fragmentShader: fragment,
+        wireframe: true,
+        side: THREE.DoubleSide,
+      });
+
+      mesh = new THREE.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);
+
+      backGeometry.scale(50, 50, 1);
+      background.position.set(10, 10, -10);
+      background.rotation.set(Math.PI / 2, 0, 0);
+
+      scene.add(mesh);
+      scene.add(background);
+
+      // Tested and checked
+      camera.position.set(
+        0.16430412417444037,
+        -1.5202138879420155,
+        0.20892968987792318,
+      );
+
+      controls.update();
+
+      renderer.setPixelRatio(window.devicePixelRatio);
+      onWindowResize();
+
+      isLoaded = true;
+    }
+
+    function onWindowResize() {
+      screenHeight = window.innerHeight;
+      screenWidth = window.innerWidth;
+
+      if (screenWidth > 1100) {
+        canvasHeight = screenHeight;
+        canvasWidth = screenWidth / 2;
+      } else {
+        canvasHeight = screenHeight / 2;
+        canvasWidth = screenWidth;
+      }
+
+      renderer.setSize(canvasWidth, canvasHeight);
+      material.uniforms.u_resolution.value.x = renderer.domElement.width;
+      material.uniforms.u_resolution.value.y = renderer.domElement.height;
+    }
+
+    function animate() {
+      animationFrame = requestAnimationFrame(animate);
+      material.uniforms.u_time.value += 0.05;
+      controls.update();
+      renderer.render(scene, camera);
+      isRendering = true;
+    }
+
+    return () => {
+      // eslint-disable-next-line prefer-spread
+      scene.remove.apply(scene, scene.children);
+      canvasObserver.disconnect();
+    };
+  }, []);
+
+  useEffect(() => {
+    gsap.to(overlayRef.current, {
+      height: 0,
+      delay: window.innerWidth >= 768 ? 0 : 0.3,
+      duration: 2.1,
+      ease: 'Expo.easeInOut',
+    });
+  }, []);
+
+  return (
+    <div className="hero-infograph" style={{ position: 'relative' }}>
+      <canvas ref={canvasRef} className="homeCanvas" />
+      <div ref={overlayRef} className="homeCanvas-overlay" />
+    </div>
+  );
+};
+
+export default HeroCanvas;
diff --git a/website/src/pages/sections/components/ossCanvas.jsx b/website/src/pages/sections/components/OssCanvas.tsx
similarity index 59%
rename from website/src/pages/sections/components/ossCanvas.jsx
rename to website/src/pages/sections/components/OssCanvas.tsx
index 237594460c7..506d3096486 100644
--- a/website/src/pages/sections/components/ossCanvas.jsx
+++ b/website/src/pages/sections/components/OssCanvas.tsx
@@ -1,87 +1,94 @@
-import React, { useRef, useEffect, useState } from "react";
-import * as THREE from "three";
-import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
+import type { FC } from 'react';
+import React, { useRef, useEffect, useState } from 'react';
+import * as THREE from 'three';
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
 
-import "../../../css/customTheme.css";
- 
-const OssCanvas = () => {
-  let screenWidth, screenHeight;
+import '../../../css/customTheme.css';
+
+const OssCanvas: FC = () => {
+  let screenWidth: number;
+  let screenHeight: number;
+  let canvasHeight: number;
+  let canvasWidth: number;
 
   const canvasRef = useRef(null);
 
-  let canvasHeight, canvasWidth;
-  
   useEffect(() => {
-    let camera, scene, renderer, material, mesh;
-    
+    let camera;
+    let scene;
+    let renderer;
+    let material;
+    let mesh;
+
     screenWidth = window.innerWidth;
     screenHeight = window.innerHeight;
     window.addEventListener('resize', onWindowResize, false);
-    
+
     let controls;
-    let isLoaded = false, isRendering = false, animationFrame;
-    
+    let isLoaded = false; let isRendering = false; let
+      animationFrame;
+
     if (screenWidth > 1100) {
       canvasHeight = 500;
-      canvasWidth = screenWidth/2;
+      canvasWidth = screenWidth / 2;
     } else {
-      canvasHeight = 500
+      canvasHeight = 500;
       canvasWidth = screenWidth;
     }
 
-    function onWindowResize(event) {
+    function onWindowResize() {
       screenHeight = window.innerHeight;
       screenWidth = window.innerWidth;
 
       if (screenWidth > 1100) {
         canvasHeight = 500;
-        canvasWidth = screenWidth/2;
+        canvasWidth = screenWidth / 2;
       } else {
-        canvasHeight = 500
+        canvasHeight = 500;
         canvasWidth = screenWidth;
       }
-  
+
       renderer.setSize(canvasWidth, canvasHeight);
     }
-    
-    let ossCanvasObserver = new IntersectionObserver(onOssCanvasIntersection, {
+
+    const ossCanvasObserver = new IntersectionObserver(onOssCanvasIntersection, {
       root: null,
       threshold: 0.01,
     });
 
     function init(width, height) {
       const ctx = canvasRef.current;
-      renderer = new THREE.WebGLRenderer({canvas: ctx});
+      renderer = new THREE.WebGLRenderer({ canvas: ctx });
 
       camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
-      
-      controls = new OrbitControls( camera, renderer.domElement );
+
+      controls = new OrbitControls(camera, renderer.domElement);
       controls.enableZoom = false;
 
-      const radius = window.innerWidth > 768 ? 5 : 4.5;  
-      const detail = 8; 
-      
+      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});
+      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.target.copy(mesh.position);
+
       controls.update();
       renderer.setPixelRatio(window.devicePixelRatio);
 
@@ -89,7 +96,7 @@ const OssCanvas = () => {
 
       isLoaded = true;
     }
-    
+
     function animate() {
       animationFrame = requestAnimationFrame(animate);
 
@@ -97,42 +104,42 @@ const OssCanvas = () => {
       mesh.rotation.y += 0.005;
 
       controls.update();
-      
+
       renderer.render(scene, camera);
       isRendering = true;
     }
-    
+
     init(canvasWidth, canvasHeight);
 
-    function onOssCanvasIntersection(entries, opts){
-      entries.forEach(entry =>  {
+    function onOssCanvasIntersection(entries) {
+      entries.forEach((entry) => {
         if (entry.isIntersecting && isLoaded) {
           if (isLoaded && !isRendering) {
             animate();
           } else {
-            console.log("Loading")
+            console.log('Loading');
           }
         } else {
           if (animationFrame) {
-          cancelAnimationFrame(animationFrame);
-          isRendering = false;
+            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"></canvas>
+    <canvas ref={canvasRef} width={canvasWidth} height={canvasHeight} className="ossCanvas" />
   );
-}
+};
 
 export default OssCanvas;
diff --git a/website/src/pages/sections/components/arrowAnim.jsx b/website/src/pages/sections/components/arrowAnim.jsx
deleted file mode 100644
index df7a7bc1bbb..00000000000
--- a/website/src/pages/sections/components/arrowAnim.jsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import React, { useRef } from "react";
-import Link from "@docusaurus/Link";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-import gsap from "gsap"
-
-import "../../../css/customTheme.css";
-
-const ArrowAnim = () => {
-  const endpathRef1 = useRef(null);
-  const endpathRef2 = useRef(null);
-  
-  function mouseOver() {
-    gsap.to([endpathRef2.current],{
-      strokeDashoffset: 970,
-      duration: 0.4
-    });
-    gsap.to([endpathRef1.current],{
-      stroke: "#9b9b9b",
-      duration: 0.4
-    });
-    gsap.to([endpathRef2.current],{
-      stroke: "#9b9b9b",
-      duration: 0.4
-    });
-  }
-
-  function mouseOut() {
-    gsap.to([endpathRef2.current],{
-      strokeDashoffset: 1002,
-      duration: 0.4
-    });
-    gsap.to([endpathRef1.current],{
-      stroke: "black",
-      duration: 0.4
-    });
-    gsap.to([endpathRef2.current],{
-      stroke: "black",
-      duration: 0.4
-    });
-  }
-
-  return (
-    <>
-      <Link
-        to={useBaseUrl("docs")} onMouseOver={mouseOver} onMouseLeave={mouseOut} className="btn-docs">
-        Go to docs...
-        <svg width="15" strokeWidth="3" height="25" viewBox="0 0 43 32" fill="none" xmlns="http://www.w3.org/2000/svg">
-          <path ref={endpathRef1} d="M27.5 1L42.5 16L27.5 31" stroke="black" strokeLinecap="round" strokeLinejoin="round"/>
-          <path ref={endpathRef2} className="arrow-btn" d="M42.5 16H0.5" stroke="black" strokeLinecap="round" strokeLinejoin="round"/>
-        </svg>
-      </Link> 
-    </>
-  );
-}
-  
-export default ArrowAnim;
diff --git a/website/src/pages/sections/components/eventPosterCard.jsx b/website/src/pages/sections/components/eventPosterCard.jsx
deleted file mode 100644
index 35ea50f21b1..00000000000
--- a/website/src/pages/sections/components/eventPosterCard.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import React, { useState, useRef, useEffect } from "react";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
-import gsap from "gsap"
-
-import "../../../css/customTheme.css";
-
-
-const EventPosterCard = () => {
-  const { siteConfig } = useDocusaurusContext();
-  const [display, setDisplay] = useState(false);
-  const picRef = useRef(null);
-
-  useEffect(() => {
-    gsap.fromTo(picRef.current, {
-      x: 500,
-      opacity: 0
-    }, {
-      x: 0,
-      opacity: 1,
-      delay: 3.0,
-    });
-  }, []);
-
-  useEffect(() => {
-    if (!localStorage.getItem('SHOW_EVENT_ENTRY')) {
-      setDisplay(true);
-    }
-
-    if (!siteConfig.customFields.eventPosterCard.show) {
-      setDisplay(false);
-    } else {
-      const expire = siteConfig.customFields.eventPosterCard.expire;
-      const expireTimestamp = new Date(expire).getTime();
-      if (expireTimestamp <= new Date().getTime()) {
-        setDisplay(false);
-      }
-    }
-  }, []);
-
-  const onClose = () => {
-    gsap.to(picRef.current, {
-      x: 500,
-      opacity: 0,
-      onComplete: ()=>{
-        setDisplay(false);
-      }
-    });
-    if (typeof window !== 'undefined') {
-      localStorage.setItem('SHOW_EVENT_ENTRY', 'true');
-    }
-  };
-
-  if (!display) {
-    return null;
-  }
-
-  return (
-      <div ref={picRef} className="pic-wrapper">
-        <button className="pic-wrapper-close" onClick={onClose}>
-          <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="times"
-               className="svg-inline--fa fa-times fa-w-11" role="img" xmlns="http://www.w3.org/2000/svg"
-               viewBox="0 0 352 512">
-            <path fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"></path>
-          </svg>
-        </button>
-        <a href={siteConfig.customFields.eventPosterCard.link} onClick={onClose}>
-          <img src={siteConfig.customFields.eventPosterCard.image} alt=""/>
-        </a>
-      </div>
-  );
-}
-
-export default EventPosterCard;
diff --git a/website/src/pages/sections/components/heroCanvas.jsx b/website/src/pages/sections/components/heroCanvas.jsx
deleted file mode 100644
index 6c47ae2bac1..00000000000
--- a/website/src/pages/sections/components/heroCanvas.jsx
+++ /dev/null
@@ -1,236 +0,0 @@
-import React, { useRef, useEffect } from "react";
-import * as THREE from "three";
-import gsap from "gsap"
-
-import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
-
-import "../../../css/customTheme.css";
-import vertex from '!!raw-loader!../../../shaders/vertex.vert';
-import fragment from '!!raw-loader!../../../shaders/fragment.frag';
- 
-const HeroCanvas = () => {
-  const canvasRef = useRef(0);
-  const overlayRef = useRef(0);
-
-  let canvasHeight, canvasWidth, screenWidth, screenHeight, controls;
-  let isLoaded = false, isRendering = false, animationFrame;
-
-  useEffect(() => {
-    screenWidth = window.innerWidth;
-    screenHeight = window.innerHeight;
-
-    let mouse = {x: 0.5, y: 0.5};
-    let fragMouse = {x: 0.5, y: 0.5};
-
-    let camera, mesh, scene, renderer, material, geometry;
-
-    window.addEventListener('resize', onWindowResize, false);
-  
-    if (screenWidth > 1100) {
-      canvasHeight = screenHeight;
-      canvasWidth = screenWidth / 2;
-    } else {
-      canvasHeight = screenHeight / 2;
-      canvasWidth = screenWidth;
-    }
-
-    canvasRef.current.width = canvasWidth;
-    canvasRef.current.height = canvasHeight;
-
-    canvasRef.current.addEventListener("mousemove", function (event) {
-    
-    let ctx = {
-      x: (event.clientX),
-      y: (event.clientY)
-    };
-
-    const canvasOffset = {
-      left: canvasRef.current.getBoundingClientRect().x,
-      top: canvasRef.current.getBoundingClientRect().y
-    };
-
-    ctx.x = ((ctx.x - canvasOffset.left) / canvasWidth);
-    ctx.y = ((ctx.y - canvasOffset.top) / canvasHeight);
-    
-    gsap.to(mouse, 2, {
-      x: ctx.x * (canvasWidth / canvasHeight) - (canvasWidth / canvasHeight) / 2,
-      y: (1.0 - ctx.y) - 0.5,
-      onUpdate: ()=>{
-        material.uniforms.u_mouse.value.x = mouse.x;
-        material.uniforms.u_mouse.value.y = mouse.y;
-      }
-    });
-    
-    gsap.to(fragMouse, 2, {
-      x: ctx.x,
-      y: (1.0 - ctx.y),
-      onUpdate: ()=>{
-      material.uniforms.u_fragMouse.value.x = fragMouse.x;
-      material.uniforms.u_fragMouse.value.y = fragMouse.y;
-      }
-    });
-    });
-  
-    function getRandom(a, b) {
-      return a + (b - a) * Math.random();
-    }
-  
-    let canvasObserver = new IntersectionObserver(onCanvasIntersection, {
-      root: null,
-      threshold: 0.01,
-    });
-
-    init(canvasWidth, canvasHeight);
-  
-    function onCanvasIntersection(entries, opts){
-      entries.forEach( entry =>  {
-        if (entry.isIntersecting && isLoaded) {
-          if (isLoaded && !isRendering) {
-          animate();
-          } else {
-          console.log("Loading")
-          }
-        } else {
-        if (animationFrame) {
-          cancelAnimationFrame(animationFrame);
-          isRendering = false;
-        }
-        }
-      }
-    );
-    }      
-  
-    canvasObserver.observe(canvasRef.current);
-  
-    function init(width, height) {
-      const ctx = canvasRef.current;
-    
-      renderer = new THREE.WebGLRenderer({canvas: ctx});
-      renderer.autoClearColor = false;
-  
-      camera = new THREE.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);
-
-      let count = geometry.attributes.position.count;
-      let arrSize = new THREE.BufferAttribute(new Float32Array(count), 1);
-
-      for (let i = 0; i < arrSize.count; i++) {
-        arrSize.array[i] = getRandom(0, 1)
-      }
-      geometry.setAttribute("aSize", arrSize, 1);
-
-      geometry.scale(2.0, 1.0, 1.0);
-
-      scene = new THREE.Scene();
-      renderer.setSize(canvasWidth, canvasHeight);
-  
-      let uniforms = {
-        u_time: {
-          type: "f",
-          value: 1.0
-        },
-        u_resolution: {
-          type: "v2",
-          value: new THREE.Vector2()
-        },
-        u_mouse: {
-          type: "v2",
-          value: new THREE.Vector2(0.5, 0.5)
-        },
-        u_fragMouse: {
-          type: "v2",
-          value: new THREE.Vector2(0.5, 0.5)
-        },
-      };
-  
-      scene.background = new THREE.Color('red');
-  
-      camera.position.z = 5;
-      controls.update();
-
-      material = new THREE.ShaderMaterial({
-        uniforms: uniforms,
-        vertexShader: vertex,
-        fragmentShader: fragment,
-        wireframe: true,
-        side: THREE.DoubleSide
-      });
-    
-      mesh = new THREE.Points(geometry, material);
-    
-      let backGeometry = new THREE.PlaneBufferGeometry(width / height, 1, 200, 200);
-      let bgMaterial = new THREE.MeshBasicMaterial({color: 0x121212, wireframe: false});
-      let background = new THREE.Mesh(backGeometry, bgMaterial);
-    
-      backGeometry.scale(50,50,1);
-      background.position.set(10,10,-10);
-      background.rotation.set(Math.PI/2,0,0);
-
-      scene.add(mesh);
-      scene.add(background);
-    
-      camera.position.set( 0.16430412417444037, -1.5202138879420155, 0.20892968987792318);  // Tested and checked 
-      controls.update();
-    
-      renderer.setPixelRatio(window.devicePixelRatio);
-      onWindowResize();
-
-      isLoaded = true;
-    }
-  
-    function onWindowResize(event) {
-      screenHeight = window.innerHeight;
-      screenWidth = window.innerWidth;
-
-      if (screenWidth > 1100) {
-        canvasHeight = screenHeight;
-        canvasWidth = screenWidth / 2;
-      } else {
-        canvasHeight = screenHeight / 2;
-        canvasWidth = screenWidth;
-      }
-      
-      renderer.setSize(canvasWidth, canvasHeight);
-      material.uniforms.u_resolution.value.x = renderer.domElement.width;
-      material.uniforms.u_resolution.value.y = renderer.domElement.height;
-    }
-  
-    function animate() {
-      animationFrame = requestAnimationFrame(animate);
-      material.uniforms.u_time.value += 0.05;
-      controls.update();
-      renderer.render(scene, camera);
-      isRendering = true;
-    }
-
-    return ()=>{
-      scene.remove.apply(scene, scene.children);
-      canvasObserver.disconnect();
-    }
-  }, []);
-
-  
-  useEffect(() => {
-    gsap.to(overlayRef.current,{
-    height: 0,
-    delay: window.innerWidth >= 768 ? 0 : 0.3,
-    duration: 2.1,
-    ease: "Expo.easeInOut"
-    });
-  }, [])
-
-  return (
-    <div className="hero-infograph" style={{position: "relative"}}>
-      <canvas ref={canvasRef} className="homeCanvas"></canvas>
-      <div ref={overlayRef} className="homeCanvas-overlay"></div>
-    </div>  
-  );
-}
-
-export default HeroCanvas;
diff --git a/website/src/pages/sections/endcta.jsx b/website/src/pages/sections/endcta.jsx
deleted file mode 100644
index 34a8174f5e1..00000000000
--- a/website/src/pages/sections/endcta.jsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from "react";
-import Link from "@docusaurus/Link";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-
-import "../../css/customTheme.css";
-import ArrowAnim from "./components/arrowAnim";
-
-const EndCTA = () => {
-  return (
-    <>
-      <div className="endcta" style={{padding: "50px 0", background: "#FF90A3", margin: "0 0 -32px 0"}}>
-        <div className="endcta-text">
-          <p style={{display: "flex", justifyContent: "center", alignItems: "center", whiteSpace: "pre"}}>Try <span style={{color: "#E8433E"}}>APISIX</span> today <img className="rocket" src="https://raw.githubusercontent.com/apache/apisix-website/master/website/src/assets/images/rocket.gif" alt="Rocket"/></p>
-        </div>
-        <div className="endcta-btns">
-          <div className="hero-ctas">
-            <Link
-              to={useBaseUrl("downloads")}
-              className="btn btn-download">
-              Downloads
-            </Link>
-            <ArrowAnim />
-          </div>
-        </div>
-      </div>
-    </>
-  );
-}
-  
-export default EndCTA;
diff --git a/website/src/pages/sections/heroSection.jsx b/website/src/pages/sections/heroSection.jsx
deleted file mode 100644
index ae4b96d83f1..00000000000
--- a/website/src/pages/sections/heroSection.jsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import React, { useRef, useEffect } from "react";
-import Link from "@docusaurus/Link";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-import gsap from "gsap"
-
-import "../../css/customTheme.css";
-import HeroCanvas from "./components/heroCanvas"
-import ArrowAnim from "./components/arrowAnim";
-
-const HeroSection = (props) => {
-  const titleRef = useRef(0)
-  const subtitleRef = useRef(0)
-  const ctaRef = useRef(0)
-  const canRef = useRef(0)
-  
-  useEffect(() => {
-    let tl = gsap.timeline({
-      defaults: {
-        delay: window.innerWidth >= 768 ? 1.5 : 0.01,
-        duration: 0.5,
-        ease: "Expo.easeInOut" 
-      },
-    });
-    
-    tl.fromTo([titleRef.current, subtitleRef.current, ctaRef.current],{
-      opacity: 0,
-      y: 10
-    },{
-      opacity: 1,
-      y: 0,
-      stagger: 0.3
-    });
-
-    return () => {
-      tl.pause(0).kill(true);
-    }
-  }, [])
-
-  return (
-    <>
-      <div className="hero-sec-wrap" style={{width: "100%"}}>
-        <div className="hero-text">
-          <h2 ref={titleRef} className="hero-title hide-title"><span>Effortless and smooth</span> <span style={{color: "#E8433E"}}>API Traffic</span> management.</h2>
-          <h3 ref={subtitleRef} className="hero-subtitle hide-subtitle">Apache APISIX provides rich traffic management features like Load Balancing, Dynamic Upstream, Canary Release, Circuit Breaking, Authentication, Observability, and more...</h3>
-          <div ref={ctaRef} className="hero-ctas hide-ctas">
-            <Link
-              to={useBaseUrl("downloads")}
-              className="btn btn-download">
-              Downloads
-            </Link>
-            <ArrowAnim />
-          </div>
-        </div>
-        <div ref={canRef} className="add-margin">
-          <HeroCanvas></HeroCanvas>
-        </div>
-      </div>
-    </>
-  );
-}
-  
-export default HeroSection;
-  
\ No newline at end of file
diff --git a/website/src/pages/sections/opensourcePromo.jsx b/website/src/pages/sections/opensourcePromo.jsx
deleted file mode 100644
index 9913520ca33..00000000000
--- a/website/src/pages/sections/opensourcePromo.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from "react";
-import Link from "@docusaurus/Link";
-import useBaseUrl from "@docusaurus/useBaseUrl";
-
-import OssCanvas from "./components/ossCanvas"
-
-import "../../css/customTheme.css";
-import GitHub from "../../assets/icons/github-logo.svg";
-
-const OpensourcePromo = (props) => {
-  return (
-    <>
-      <div className="ossPromotion">
-        <div className="docs-promo">
-          <div className="docs-promo-text">
-            <h3 className="docs-promo-head">Learn from developers</h3>
-            <div className="docs-promo-subtitle">
-              <p>Want to learn Apache APISIX usage, but don’t know where to start. Check out our <Link style={{ color: "#e8433e" }} to={useBaseUrl("docs")}>docs.</Link></p>
-              <p>Like visual information, check out our <a style={{ color: "#e8433e" }} href="https://www.youtube.com/channel/UCgPD18cMhOg5rmPVnQhAC8g">Youtube channel</a> for detailed tutorials. Subscribe for more.</p>
-            </div>
-          </div>
-          <div className="docs-promo-video">
-            <video preload="none" src="https://static.apiseven.com/apisix-website/videos/apisix.mp4" loading="lazy" autoPlay={true} poster="" muted={true} loop={true} width="70%" height="auto" controls></video>
-          </div>
-        </div>
-
-        <div className="oss-promo">
-          <div className="oss-promo-text">
-            <h3 className="oss-promo-head">Be a part of building APISIX</h3>
-            <div className="oss-promo-subtitle" style={{ color: "rgb(199, 199, 199)" }}>
-              <p>Apache APISIX is opensource and ever-growing. Contributors are always welcome. Reach out to us on GitHub</p>
-              <div className="oss-promo-cta">
-                <GitHub style={{ width: "20px", margin: "0 10px 0 0" }} />
-                <a href="https://github.com/apache/apisix" style={{ textDecoration: "none" }}>Check us out</a>
-              </div>
-            </div>
-          </div>
-          <div className="oss-promo-infograph">
-            <OssCanvas />
-          </div>
-        </div>
-      </div>
-    </>
-  );
-}
-
-export default OpensourcePromo;
diff --git a/website/src/pages/showcase/index.js b/website/src/pages/showcase/index.js
deleted file mode 100644
index 9b55db4ef45..00000000000
--- a/website/src/pages/showcase/index.js
+++ /dev/null
@@ -1,81 +0,0 @@
-const React = require("react");
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
-import Layout from "@theme/Layout";
-import './styles.scss';
-
-const Container = (props) => {
-  return (
-    <div className="hero text--center showcase">
-      <div className="container">
-        {props.children}
-      </div>
-    </div>
-  );
-}
-
-const Header = (props) => {
-  return (
-    <div className="header">
-      <div className="title">
-        Showcase
-      </div>
-      <div className="tips">
-        This project is used by all these folks
-        <br />
-        Are you using this project?&nbsp;
-        <a
-          href="https://github.com/apache/apisix/blob/master/powered-by.md"
-          target="_blank"
-          rel="noopener"
-        >
-          <u>Add your company</u>
-        </a>
-      </div>
-    </div>
-  );
-}
-
-const Content = (props) => {
-  const { siteConfig } = useDocusaurusContext();
-  if (!(siteConfig.customFields.showcases || []).length) {
-    return null;
-  }
-  const showcases = siteConfig.customFields.showcases.map((user) => (
-    <div className="col col--2 item" key={user.infoLink}>
-      <UserCard
-        image={'https://raw.githubusercontent.com/apache/apisix-website/master/website/static/img/' + user.image}
-        caption={user.caption}
-        infoLink={user.infoLink}
-      />
-    </div>
-  ));
-
-  return (
-    <div className="row content">
-      {showcases}
-    </div>
-  );
-}
-
-const UserCard = (props) => {
-  return (
-    <div className="user-card">
-      <a href={props.infoLink}>
-        <img className="logo" src={props.image} alt={props.caption} />
-      </a>
-    </div>
-  );
-}
-
-const Showcase = (props) => {
-  return (
-    <Layout>
-      <Container>
-        <Header />
-        <Content />
-      </Container>
-    </Layout>
-  );
-};
-
-export default Showcase;
diff --git a/website/src/pages/showcase/index.tsx b/website/src/pages/showcase/index.tsx
new file mode 100644
index 00000000000..a5e80cd03b7
--- /dev/null
+++ b/website/src/pages/showcase/index.tsx
@@ -0,0 +1,87 @@
+import type { FC } from 'react';
+import React from 'react';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import Layout from '@theme/Layout';
+import './styles.scss';
+
+const Container: FC = (props) => {
+  const { children } = props;
+
+  return (
+    <div className="hero text--center showcase">
+      <div className="container">
+        {children}
+      </div>
+    </div>
+  );
+};
+
+const Header: FC = () => (
+  <div className="header">
+    <div className="title">
+      Showcase
+    </div>
+    <div className="tips">
+      This project is used by all these folks
+      <br />
+      Are you using this project?&nbsp;
+      <a
+        href="https://github.com/apache/apisix/blob/master/powered-by.md"
+        target="_blank"
+        rel="noopener noreferrer"
+      >
+        <u>Add your company</u>
+      </a>
+    </div>
+  </div>
+);
+
+interface UserCardProps {
+  infoLink: string;
+  image: string;
+  caption: string;
+}
+
+const UserCard: FC<UserCardProps> = (props) => {
+  const { infoLink, image, caption } = props;
+  return (
+    <div className="user-card">
+      <a href={infoLink}>
+        <img className="logo" src={image} alt={caption} />
+      </a>
+    </div>
+  );
+};
+
+const Content: FC = () => {
+  const { siteConfig } = useDocusaurusContext();
+  if (!(siteConfig.customFields.showcases || []).length) {
+    return null;
+  }
+  const showcases = siteConfig.customFields.showcases.map((user) => (
+    <div className="col col--2 item" key={user.infoLink}>
+      <UserCard
+        image={`https://raw.githubusercontent.com/apache/apisix-website/master/website/static/img/${user.image}`}
+        caption={user.caption}
+        infoLink={user.infoLink}
+      />
+    </div>
+  ));
+
+  return (
+    <div className="row content">
+      {showcases}
+    </div>
+  );
+};
+
+const Showcase: FC = () => (
+  <Layout>
+    <Container>
+      <Header />
+      <Content />
+    </Container>
+  </Layout>
+);
+
+export default Showcase;
diff --git a/website/src/pages/team.js b/website/src/pages/team.tsx
similarity index 58%
rename from website/src/pages/team.js
rename to website/src/pages/team.tsx
index 4d3f7307a72..590ad7dc9bf 100644
--- a/website/src/pages/team.js
+++ b/website/src/pages/team.tsx
@@ -1,16 +1,18 @@
-import React from "react";
-import styled from "styled-components";
-import Layout from "@theme/Layout";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
-import GitHubLogo from "../assets/icons/github-logo.svg";
-import "../css/customTheme.css";
-import IconCode from "../assets/icons/code.svg";
-import IconStar from "../assets/icons/star.svg";
-import IconDatabase from "../assets/icons/database.svg";
-import IconTerminal from "../assets/icons/terminal.svg";
-import IconPuzzle from "../assets/icons/puzzle.svg";
-import IconEye from "../assets/icons/eye.svg";
-import IconDocumentText from "../assets/icons/document-text.svg";
+import type { FC } from 'react';
+import React from 'react';
+import styled from 'styled-components';
+import Layout from '@theme/Layout';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import GitHubLogo from '../assets/icons/github-logo.svg';
+import IconCode from '../assets/icons/code.svg';
+import IconStar from '../assets/icons/star.svg';
+import IconDatabase from '../assets/icons/database.svg';
+import IconTerminal from '../assets/icons/terminal.svg';
+import IconPuzzle from '../assets/icons/puzzle.svg';
+import IconEye from '../assets/icons/eye.svg';
+import IconDocumentText from '../assets/icons/document-text.svg';
+
+import '../css/customTheme.css';
 
 const PageTitle = styled.h1`
   margin-top: 2rem;
@@ -241,23 +243,24 @@ const ContributeCardRightSide = styled.div`
   }
 `;
 
-function Team(props) {
+const Team: FC = () => {
   const { siteConfig } = useDocusaurusContext();
   const memberSections = siteConfig.customFields.team.map((section) => {
-    const memberCards = section.members.map((member) => {
-      return (
-        <div key={member.username}>
-          <MemberCard
-            href={`https://github.com/${member.githubUsername}`}
-            target="_blank"
-          >
-            <Avatar src={member.avatarUrl} />
-            <MemberName>{member.name}</MemberName>
-            <Username>@{member.username}</Username>
-          </MemberCard>
-        </div>
-      );
-    });
+    const memberCards = section.members.map((member) => (
+      <div key={member.username}>
+        <MemberCard
+          href={`https://github.com/${member.githubUsername}`}
+          target="_blank"
+        >
+          <Avatar src={member.avatarUrl} />
+          <MemberName>{member.name}</MemberName>
+          <Username>
+            @
+            {member.username}
+          </Username>
+        </MemberCard>
+      </div>
+    ));
     return (
       <div key={section.groupName}>
         <SectionTitle>{section.groupName}</SectionTitle>
@@ -267,63 +270,61 @@ function Team(props) {
       </div>
     );
   });
-  const repoComponents = siteConfig.customFields.allRepos.map((repo) => {
-    return (
-      <RepoCard
-        className="team-repocard"
-        href={`https://github.com/${repo}/graphs/contributors`}
-        target="_blank"
-        key={repo}
-      >
-        <GitHubLogo className="team-githubLogo" /> {repo}
-      </RepoCard>
-    );
-  });
+  const repoComponents = siteConfig.customFields.allRepos.map((repo) => (
+    <RepoCard
+      className="team-repocard"
+      href={`https://github.com/${repo}/graphs/contributors`}
+      target="_blank"
+      key={repo}
+    >
+      <GitHubLogo className="team-githubLogo" />
+      {' '}
+      {repo}
+    </RepoCard>
+  ));
   return (
-    <Page>
-      <PageTitle>Team</PageTitle>
-      <PageSubtitle>We love open source.</PageSubtitle>
-      {memberSections}
-      <SectionTitle>Contributors</SectionTitle>
-      <SectionSubtitle>
-        You can find all contributors of Apache APISIX from GitHub contribution
-        list.
-      </SectionSubtitle>
-      <RepoCardsContainer>{repoComponents}</RepoCardsContainer>
-      <SectionTitle>Contributor Over Time</SectionTitle>
-      <SectionSubtitle>
-        Note: This graph contains contributors from all repos under Apache APISIX
-      </SectionSubtitle>
-      <img src="https://contributor-graph-api.apiseven.com/contributors-svg?repo=apache/apisix&merge=true" alt="Contributor Over Time"/>
-      <ContributeCard>
-        <ContributeCardLeftSide>
-          <ContributeCardTitle>🛠 Become A Committer </ContributeCardTitle>
-          <ContributeCardSubtitle>
-            The Apache APISIX community follows the Apache Community’s process
-            on accepting a new committer. After a contributor participates
-            APISIX's community actively, PMC and Committers will make decisions
-            to invite the contributor join Committers and PMC.
-          </ContributeCardSubtitle>
-          <ContributeCardButton href="/docs/general/contributor-guide">
-            Start Contribute
-          </ContributeCardButton>
-        </ContributeCardLeftSide>
-        <ContributeCardRightSide>
-          <IconCode id="icon-code" />
-          <IconStar id="icon-star" />
-          <IconDatabase id="icon-database" />
-          <IconTerminal id="icon-terminal" />
-          <IconPuzzle id="icon-puzzle" />
-          <IconEye id="icon-eye" />
-          <IconDocumentText id="icon-document-text" />
-        </ContributeCardRightSide>
-      </ContributeCard>
-    </Page>
+    <Layout>
+      <Page>
+        <PageTitle>Team</PageTitle>
+        <PageSubtitle>We love open source.</PageSubtitle>
+        {memberSections}
+        <SectionTitle>Contributors</SectionTitle>
+        <SectionSubtitle>
+          You can find all contributors of Apache APISIX from GitHub contribution
+          list.
+        </SectionSubtitle>
+        <RepoCardsContainer>{repoComponents}</RepoCardsContainer>
+        <SectionTitle>Contributor Over Time</SectionTitle>
+        <SectionSubtitle>
+          Note: This graph contains contributors from all repos under Apache APISIX
+        </SectionSubtitle>
+        <img src="https://contributor-graph-api.apiseven.com/contributors-svg?repo=apache/apisix&merge=true" alt="Contributor Over Time" />
+        <ContributeCard>
+          <ContributeCardLeftSide>
+            <ContributeCardTitle>🛠 Become A Committer </ContributeCardTitle>
+            <ContributeCardSubtitle>
+              The Apache APISIX community follows the Apache Community&apos;s process
+              on accepting a new committer. After a contributor participates
+              APISIX&apos;s community actively, PMC and Committers will make decisions
+              to invite the contributor join Committers and PMC.
+            </ContributeCardSubtitle>
+            <ContributeCardButton href="/docs/general/contributor-guide">
+              Start Contribute
+            </ContributeCardButton>
+          </ContributeCardLeftSide>
+          <ContributeCardRightSide>
+            <IconCode id="icon-code" />
+            <IconStar id="icon-star" />
+            <IconDatabase id="icon-database" />
+            <IconTerminal id="icon-terminal" />
+            <IconPuzzle id="icon-puzzle" />
+            <IconEye id="icon-eye" />
+            <IconDocumentText id="icon-document-text" />
+          </ContributeCardRightSide>
+        </ContributeCard>
+      </Page>
+    </Layout>
   );
-}
+};
 
-export default (props) => (
-  <Layout>
-    <Team {...props} />
-  </Layout>
-);
+export default Team;
diff --git a/website/tsconfig.json b/website/tsconfig.json
index b307ca4d016..2ef4dc1a3fe 100644
--- a/website/tsconfig.json
+++ b/website/tsconfig.json
@@ -2,5 +2,8 @@
   "extends": "@tsconfig/docusaurus/tsconfig.json",
   "include": [
     "src/"
-  ]
+  ],
+  "compilerOptions": {
+    "resolveJsonModule": true
+  }
 }
diff --git a/yarn.lock b/yarn.lock
index 7dc70e96443..33e2992506f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1944,6 +1944,14 @@
   resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
   integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==
 
+"@types/hoist-non-react-statics@*":
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
+  integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
+  dependencies:
+    "@types/react" "*"
+    hoist-non-react-statics "^3.3.0"
+
 "@types/html-minifier-terser@^6.0.0":
   version "6.1.0"
   resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35"
@@ -2065,6 +2073,15 @@
   resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
   integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
 
+"@types/styled-components@^5.1.24":
+  version "5.1.24"
+  resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.24.tgz#b52ae677f03ea8a6018aa34c6c96b7018b7a3571"
+  integrity sha512-mz0fzq2nez+Lq5IuYammYwWgyLUE6OMAJTQL9D8hFLP4Pkh7gVYJii/VQWxq8/TK34g/OrkehXaFNdcEKcItug==
+  dependencies:
+    "@types/hoist-non-react-statics" "*"
+    "@types/react" "*"
+    csstype "^3.0.2"
+
 "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
@@ -5435,7 +5452,7 @@ history@^4.9.0:
     tiny-warning "^1.0.0"
     value-equal "^1.0.1"
 
-hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0:
+hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
   integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -9610,7 +9627,7 @@ style-to-object@0.3.0, style-to-object@^0.3.0:
   dependencies:
     inline-style-parser "0.1.1"
 
-styled-components@^5.3.3:
+styled-components@^5, styled-components@^5.3.3:
   version "5.3.5"
   resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.5.tgz#a750a398d01f1ca73af16a241dec3da6deae5ec4"
   integrity sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==