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,
+};