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/06/21 06:08:09 UTC

[apisix-website] branch master updated: fix: plugin route sidebar style error (#1115)

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 fca7e134e71 fix: plugin route sidebar style error (#1115)
fca7e134e71 is described below

commit fca7e134e71c21b09f91cbad00648dc3f5c28faf
Author: Barchiel <el...@gmail.com>
AuthorDate: Tue Jun 21 14:08:03 2022 +0800

    fix: plugin route sidebar style error (#1115)
---
 website/src/components/UI/Affix.tsx | 101 ++++++++++++++++++++++++++++++++++++
 website/src/hooks/useMount.ts       |  11 ++++
 website/src/pages/plugins.tsx       |  21 ++++----
 website/src/utils/index.ts          |  28 ++++++++++
 4 files changed, 152 insertions(+), 9 deletions(-)

diff --git a/website/src/components/UI/Affix.tsx b/website/src/components/UI/Affix.tsx
new file mode 100644
index 00000000000..49a0fe9eed9
--- /dev/null
+++ b/website/src/components/UI/Affix.tsx
@@ -0,0 +1,101 @@
+import type { CSSProperties, FC } from 'react';
+import React, { useState } from 'react';
+import styled from 'styled-components';
+
+import useMount from '../../hooks/useMount';
+import { getDomStyle, styleUnit2Number } from '../../utils';
+
+interface AffixProps {
+  style: CSSProperties;
+}
+
+const AffixContent = styled.div``;
+
+const getPositionStyle = (
+  hasCssSticky: boolean,
+  defaultStyles: CSSProperties = {},
+):CSSProperties => {
+  const { width = 0 } = defaultStyles;
+  const positionStyle: CSSProperties = hasCssSticky ? {
+    position: 'sticky',
+    marginLeft: `-${styleUnit2Number(width)}px`,
+    display: 'inline-block',
+    float: 'left',
+  } : {
+    position: 'absolute',
+  };
+
+  return {
+    ...positionStyle,
+    ...defaultStyles,
+  };
+};
+
+const Affix: FC<AffixProps> = (props) => {
+  const { style, children } = props;
+
+  const { top: propStyleTop = 0 } = style || {};
+  const defaultHeight = styleUnit2Number(propStyleTop);
+
+  const [hasCssSticky, SetHasCssSticky] = useState(true);
+  const [positionStyle, SetPositionStyle] = useState(style);
+  const [height, setHeight] = useState(0);
+  const [parentHeight, setParentHeight] = useState(0);
+  const [scrollHeight, setScrollHeight] = useState(0);
+
+  const getHeight = (element: HTMLElement) => {
+    if (element) {
+      const parentDom = element.parentElement ?? document.body;
+      const parentPaddingBottom = styleUnit2Number(getDomStyle(parentDom, 'padding-bottom'));
+      setHeight(element.clientHeight);
+      setParentHeight(parentDom.clientHeight + parentDom.offsetTop - parentPaddingBottom);
+    }
+  };
+
+  const getScrollHeight = () => {
+    setScrollHeight(() => window.scrollY);
+  };
+
+  useMount(() => {
+    const hasSticky = CSS.supports('position', 'sticky');
+    SetHasCssSticky(hasSticky);
+    SetPositionStyle(getPositionStyle(hasSticky, style));
+
+    if (!hasSticky) {
+      window.addEventListener('scroll', getScrollHeight);
+    }
+
+    return () => {
+      window.removeEventListener('scroll', getScrollHeight);
+    };
+  });
+
+  const getScrollStyle = (): CSSProperties => {
+    if (hasCssSticky) {
+      return positionStyle;
+    }
+
+    if (parentHeight > (scrollHeight + window.innerHeight)) {
+      return {
+        ...positionStyle,
+        top: scrollHeight + defaultHeight,
+      };
+    }
+
+    return {
+      ...positionStyle,
+      top: parentHeight - height,
+    };
+  };
+
+  return (
+    <AffixContent
+      ref={getHeight}
+      style={getScrollStyle()}
+    >
+      {children}
+    </AffixContent>
+  );
+};
+
+export default Affix;
diff --git a/website/src/hooks/useMount.ts b/website/src/hooks/useMount.ts
new file mode 100644
index 00000000000..7d643f0f5c7
--- /dev/null
+++ b/website/src/hooks/useMount.ts
@@ -0,0 +1,11 @@
+import type { EffectCallback } from 'react';
+import { useEffect } from 'react';
+
+const useMount = (fn: () => void): void => {
+  const callback: EffectCallback = () => {
+    fn();
+  };
+  useEffect(callback, []);
+};
+
+export default useMount;
diff --git a/website/src/pages/plugins.tsx b/website/src/pages/plugins.tsx
index 04f735e4437..20466fe2ab9 100644
--- a/website/src/pages/plugins.tsx
+++ b/website/src/pages/plugins.tsx
@@ -23,6 +23,8 @@ import Translate from '@docusaurus/Translate';
 
 import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
 
+import Affix from '../components/UI/Affix';
+
 const PageTitle = styled.h1`
   text-align: center;
   margin-top: 1rem;
@@ -41,7 +43,7 @@ const PageSubtitle = styled.div`
 const SidebarItem = styled.div`
   padding-top: 3px;
   padding-bottom: 3px;
-  padding-right: 3px; 
+  padding-right: 3px;
   text-align: right;
   font-size: 1rem;
   font-weight: 400;
@@ -60,7 +62,7 @@ const Page = styled.div`
 
 const PluginsContainer = styled.div`
   display: grid;
-  margin-left: 200px; 
+  margin-left: 200px;
   grid-template-columns: repeat(3, 1fr);
   grid-gap: 5px;
   @media (max-width: 1200px) {
@@ -76,12 +78,8 @@ const PluginsContainer = styled.div`
 
 const SidebarContainer = styled.div`
   display: grid;
-  width: 250px;
-  position: fixed;
-  z-index: 1;
-  left: 0;
+  width: 100%;
   overflow-x: hidden;
-  top: 300px;
   padding-right: 10px;
   border-style: solid;
   border-color: #ffffff #efeff5 #ffffff #ffffff ;
@@ -137,7 +135,7 @@ const PluginDescription = styled.div`
 `;
 
 const SectionTitle = styled.h2`
-  margin-left: 200px; 
+  margin-left: 200px;
   margin-bottom: 24px;
   margin-top: 84px;
   text-transform: uppercase;
@@ -253,7 +251,12 @@ const Plugins: FC = () => {
         <PageSubtitle>
           <Translate id="plugins.website.subtitle">Powerful Plugins and Easy Integrations</Translate>
         </PageSubtitle>
-        <SidebarContainer>{sidebar}</SidebarContainer>
+        <Affix style={{
+          width: 250, top: 300, left: 0, zIndex: 1,
+        }}
+        >
+          <SidebarContainer>{sidebar}</SidebarContainer>
+        </Affix>
         {plugins}
       </Page>
     </Layout>
diff --git a/website/src/utils/index.ts b/website/src/utils/index.ts
new file mode 100644
index 00000000000..5f974914e41
--- /dev/null
+++ b/website/src/utils/index.ts
@@ -0,0 +1,28 @@
+export const getDomStyle = (dom: HTMLElement, attr: string): string => {
+  const currentStyle = getComputedStyle(dom);
+  return currentStyle[attr];
+};
+
+export const styleUnit2Number = (value: string | number = 0): number => {
+  if (typeof value === 'number') {
+    return value;
+  }
+
+  const strValue = value;
+  const isNumber = /[0-9]+/;
+  if (!isNumber.test(strValue[0])) {
+    const [first = 0] = strValue.match(isNumber) || [];
+    return Number(first);
+  }
+
+  if (value.includes('%')) {
+    return parseFloat(value) / 100;
+  }
+
+  return parseFloat(value);
+};
+
+export default {
+  getDomStyle,
+  styleUnit2Number,
+};