Skip to content

Commit

Permalink
fix(docs): side menu sticky on desktop + mobile (#988)
Browse files Browse the repository at this point in the history
* fix(docs): update menu to be fixed position

* fix(docs): update menu to be fixed position for landing page layout with initial scroll

* fix(docs): side menu position reset when user navigates

* fix(docs): mobile menu view scroll fix

* chore: fix lint warnings + remove scrollto helper

* chore: empty changeset for docs menu ui fixes

* fix(docs): update chain web description

* fix(docs): update chain web description

* chore: revert single quote from chainweb doc page

* chore: move styles to sprinkles
  • Loading branch information
realdreamer authored Oct 5, 2023
1 parent 3fba752 commit 3b72555
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 42 deletions.
2 changes: 2 additions & 0 deletions .changeset/giant-lizards-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
1 change: 1 addition & 0 deletions packages/apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"react-dom": "^18.2.0",
"react-markdown": "~8.0.7",
"react-tweet": "~3.1.1",
"react-use": "^17.4.0",
"redoc": "~2.0.0",
"rehype-pretty-code": "~0.9.5",
"rehype-raw": "^7.0.0",
Expand Down
52 changes: 31 additions & 21 deletions packages/apps/docs/src/components/Layout/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,44 @@ import {
} from './menu.css';

import classNames from 'classnames';
import type { FC, ReactNode } from 'react';
import React from 'react';
import type { FC, ForwardedRef, ReactNode } from 'react';
import React, { forwardRef } from 'react';

interface IProps {
children?: ReactNode;
dataCy?: string;
isOpen?: boolean;
inLayout?: boolean;
layout: 'landing' | 'normal';
style?: React.CSSProperties;
ref?: ForwardedRef<HTMLDivElement>;
}

export const Menu: FC<IProps> = ({
children,
dataCy,
isOpen = false,
inLayout = false,
layout = 'normal',
}) => {
const classes = classNames(
menuClass,
menuOpenVariants[isOpen ? 'isOpen' : 'isClosed'],
menuInLayoutVariants[inLayout ? 'true' : 'false'],
menuLayoutVariants[layout],
);
export const Menu: FC<IProps> = forwardRef<HTMLDivElement, IProps>(
(
{
children,
dataCy,
isOpen = false,
inLayout = false,
layout = 'normal',
style,
},
ref,
) => {
const classes = classNames(
menuClass,
menuOpenVariants[isOpen ? 'isOpen' : 'isClosed'],
menuInLayoutVariants[inLayout ? 'true' : 'false'],
menuLayoutVariants[layout],
);

return (
<div data-cy={dataCy} className={classes}>
{children}
</div>
);
};
return (
<div data-cy={dataCy} className={classes} style={style} ref={ref}>
{children}
</div>
);
},
);

Menu.displayName = 'Menu';
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { breakpoints, sprinkles } from '@kadena/react-ui/theme';
import { breakpoints, sprinkles, vars } from '@kadena/react-ui/theme';

import { $$leftSideWidth, $$sideMenu } from '../../global.css';

import { style, styleVariants } from '@vanilla-extract/css';

export const menuClass = style([
sprinkles({
position: 'absolute',
paddingBottom: '$40',
position: 'fixed',
height: '100%',
width: '100%',
background: '$background',
overflow: 'hidden',
top: '$17',
bottom: 0,
}),
{
height: `calc(100vh - ${vars.sizes.$13})`,
gridArea: 'menu',
gridRow: '2 / span 3',
zIndex: $$sideMenu,
Expand All @@ -25,9 +27,13 @@ export const menuClass = style([
width: $$leftSideWidth,
},
[`screen and ${breakpoints.md}`]: {
position: 'relative',
position: 'sticky',
top: vars.sizes.$18,
bottom: 'auto',
height: `calc(100vh - ${vars.sizes.$18})`,
transform: 'translateX(0)',
background: 'transparent',
paddingBottom: vars.sizes.$40,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { sprinkles } from '@kadena/react-ui/theme';
import { breakpoints, sprinkles } from '@kadena/react-ui/theme';

import { style, styleVariants } from '@vanilla-extract/css';

Expand All @@ -10,8 +10,12 @@ export const menuCardClass = style([
paddingX: '$6',
}),
{
overflowY: 'scroll',
transition: 'transform .2s ease',
'@media': {
[`screen and ${breakpoints.md}`]: {
overflowY: 'scroll',
},
},
},
]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import { style } from '@vanilla-extract/css';
export const sideMenuClass = style([
sprinkles({
position: 'relative',

height: '100%',
paddingBottom: '$25',
}),
{
overflowY: 'auto',
overflowX: 'hidden',
},
]);

export const listClass = style([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { breakpoints } from '@kadena/react-ui/theme';

import { Footer } from '../Footer';
import { Menu, MenuBack } from '../Menu';
import { SideMenu } from '../SideMenu';

import { useMenu } from '@/hooks';
import { useMenu, useWindowScroll } from '@/hooks';
import type { IMenuItem } from '@/types/Layout';
import type { FC, ReactNode } from 'react';
import React from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useMedia } from 'react-use';

interface IProps {
children?: ReactNode;
Expand All @@ -21,6 +24,47 @@ export const Template: FC<IProps> = ({
hideSideMenu = false,
}) => {
const { isMenuOpen, closeMenu } = useMenu();
const isMediumDevice = useMedia(breakpoints.md);
const [{ y }] = useWindowScroll();
const mainContentRef = useRef<HTMLDivElement>(null);
const [initialTopSpacing, setInitialTopSpacing] = useState('');
const [style, setStyle] = useState<React.CSSProperties>({});
// Enable position if it's minimum medium device size
// and layout type is landing
const enablePositioning = layout === 'landing' && isMediumDevice;

useEffect(() => {
if (!enablePositioning) return;
// Get the initial paddingTop value at initial rendering
const paddingTop = getComputedStyle(
mainContentRef.current as HTMLDivElement,
)?.paddingTop;
// When we get css from computed style it comes with `px` suffix
const onlyValue = paddingTop.split('px')[0];
setInitialTopSpacing(onlyValue);

// Reset style value when we navigate to different pages
return () => {
setStyle({});
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
if (!mainContentRef.current || !enablePositioning) {
setStyle({});
return;
}

// From the initial top spacing subtract the window scroll value
// to maintain the scrolling effect
const paddingValue = parseInt(initialTopSpacing) - (y || 0);

if (paddingValue <= 0) return;
setStyle({
paddingTop: paddingValue,
});
}, [y, initialTopSpacing, enablePositioning]);

return (
<>
Expand All @@ -30,6 +74,8 @@ export const Template: FC<IProps> = ({
isOpen={isMenuOpen}
inLayout={!hideSideMenu}
layout={layout}
ref={mainContentRef}
style={style}
>
<SideMenu closeMenu={closeMenu} menuItems={menuItems} />
</Menu>
Expand Down
1 change: 1 addition & 0 deletions packages/apps/docs/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { useOpenSearch } from './useOpenSearch';
export { useSearch } from './useSearch';
export * from './useGetBlogs';
export { useMenu, MenuProvider } from './useMenu';
export { useWindowScroll } from './useWindowScroll';
28 changes: 28 additions & 0 deletions packages/apps/docs/src/hooks/useWindowScroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

export function useWindowScroll(): [
{
x: number;
y: number;
},
] {
const [state, setState] = React.useState({
x: 0,
y: 0,
});

React.useLayoutEffect((): (() => void) => {
const handleScroll = (): void => {
setState({ x: window.scrollX, y: window.scrollY });
};

handleScroll();
window.addEventListener('scroll', handleScroll);

return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);

return [state];
}
Loading

2 comments on commit 3b72555

@vercel
Copy link

@vercel vercel bot commented on 3b72555 Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

alpha-docs – ./packages/apps/docs

alpha-docs.kadena.io
alpha-docs-kadena-js.vercel.app
alpha-docs-git-main-kadena-js.vercel.app
docs-silk-two.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 3b72555 Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs-storybook – ./packages/apps/docs

docs-storybook-kadena-js.vercel.app
kadena-js-docs.vercel.app
docs-storybook-git-main-kadena-js.vercel.app

Please sign in to comment.