Skip to content

Commit

Permalink
Sticky side nav (#59)
Browse files Browse the repository at this point in the history
* Sticky side nav

* useLayoutEffect for better performance

* Fix sticky nav position on page load

* Test PR preview

* Add git hash as website version

* Remove test console log
  • Loading branch information
quietbits authored Jul 14, 2021
1 parent 4fb966a commit d30b657
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 17 deletions.
7 changes: 5 additions & 2 deletions @stellar/design-system-website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"description": "Stellar Development Foundation’s design system website",
"license": "Apache-2.0",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"git-info": "rm -rf src/generated/ && mkdir src/generated/ && echo export default \"{\\\"commitHash\\\": \\\"$(git rev-parse --short HEAD)\\\"}\" > src/generated/gitInfo.ts",
"start": "yarn git-info && react-scripts start",
"build": "yarn git-info && react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint-tsc": "tsc --noEmit"
},
"dependencies": {
"@stellar/design-system": "^0.2.1",
"lodash": "^4.17.21",
"prism-react-renderer": "^1.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand All @@ -30,6 +32,7 @@
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^13.1.5",
"@types/jest": "^26.0.22",
"@types/lodash": "^4.14.171",
"@types/node": "^14.14.41",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
Expand Down
13 changes: 7 additions & 6 deletions @stellar/design-system-website/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import { Layout } from "@stellar/design-system";
import { Landing } from "pages/Landing";
import { ComponentDetails } from "pages/ComponentDetails";
import { SideNavContext } from "context/SideNav";
import {
BREAKPOINT_SMALL,
CSS_CLASS_SMALL_SCREEN,
CSS_CLASS_SIDE_NAV_OPEN_TRIGGER,
CSS_CLASS_SIDE_NAV_OPEN,
CSS_CLASS_DISABLE_BODY_SCROLL,
} from "constants/variables";

import "styles.scss";

const BREAKPOINT_SMALL = 600;
const CSS_CLASS_SMALL_SCREEN = "small-screen";
const CSS_CLASS_SIDE_NAV_OPEN_TRIGGER = "side-nav-open-trigger";
const CSS_CLASS_SIDE_NAV_OPEN = "side-nav-open";
const CSS_CLASS_DISABLE_BODY_SCROLL = "no-body-scroll";

export const App = () => {
const [sideNavState, setSideNavState] = useState({
isEnabled: false,
Expand Down
54 changes: 53 additions & 1 deletion @stellar/design-system-website/src/components/SideNav/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { useLayoutEffect, createRef, useState } from "react";
import { NavButton, Icon } from "@stellar/design-system";
import { debounce } from "lodash";
import { componentsInDisplayOrder } from "constants/componentsInDisplayOrder";
import {
CSS_CLASS_LAYOUT_CONTAINER,
BREAKPOINT_SMALL,
} from "constants/variables";
import "./styles.scss";

interface SideNavProps {
Expand All @@ -9,13 +15,59 @@ interface SideNavProps {
}

export const SideNav = ({ activeItemId, onClick, onClose }: SideNavProps) => {
const sideNavRef = createRef<HTMLDivElement>();

const [containerOffsetTop, setContainerOffsetTop] =
useState<number | undefined>();
const [isSideNavFixed, setIsSideNavFixed] = useState(false);

const scrollHandler = debounce(() => {
if (!containerOffsetTop) {
return;
}

window.requestAnimationFrame(() => {
const isLargeScreen = window.matchMedia(
`(min-width: ${BREAKPOINT_SMALL}px)`,
);
const isFixed =
isLargeScreen.matches && window.pageYOffset >= containerOffsetTop;

setIsSideNavFixed(isFixed);
});
}, 50);

// Get and set offset top of the layout container
useLayoutEffect(() => {
if (sideNavRef?.current) {
const offsetTop = (
sideNavRef?.current?.closest(
`.${CSS_CLASS_LAYOUT_CONTAINER}`,
) as HTMLDivElement
)?.offsetTop;
setContainerOffsetTop(offsetTop || 0);
}
}, [sideNavRef]);

// Handle scroll
useLayoutEffect(() => {
window.addEventListener("scroll", scrollHandler, true);

return () => {
window.removeEventListener("scroll", scrollHandler, true);
};
}, [scrollHandler]);

const handleClick = (itemId: string) => {
onClick(itemId);
onClose();
};

return (
<div className="SideNav">
<div
className={`SideNav ${isSideNavFixed ? "SideNav--fixed" : ""}`}
ref={sideNavRef}
>
<div className="SideNav__content">
{componentsInDisplayOrder.map((item) => {
const isActive = activeItemId === item.id;
Expand Down
13 changes: 11 additions & 2 deletions @stellar/design-system-website/src/components/SideNav/styles.scss
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
.SideNav {
width: 100%;
height: 100%;
width: calc(var(--SideNav-width) - 1rem);
// 8 rem is top + footer
height: calc(100% - 8rem);
overflow-y: auto;
position: relative;
top: 0;
transition: top var(--anim-transition-default);

&--fixed {
position: fixed;
top: 1rem;
}

@media (max-width: 600px) {
background-color: var(--pal-background-primary);
width: var(--SideNav-width);
height: 100%;
}

&__content {
Expand Down
6 changes: 6 additions & 0 deletions @stellar/design-system-website/src/constants/variables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const BREAKPOINT_SMALL = 600;
export const CSS_CLASS_SMALL_SCREEN = "small-screen";
export const CSS_CLASS_SIDE_NAV_OPEN_TRIGGER = "side-nav-open-trigger";
export const CSS_CLASS_SIDE_NAV_OPEN = "side-nav-open";
export const CSS_CLASS_DISABLE_BODY_SCROLL = "no-body-scroll";
export const CSS_CLASS_LAYOUT_CONTAINER = "Layout__content";
1 change: 1 addition & 0 deletions @stellar/design-system-website/src/generated/gitInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default { commitHash: "a02b763" };
18 changes: 12 additions & 6 deletions @stellar/design-system-website/src/pages/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TextLink,
} from "@stellar/design-system";
import { ComponentsList } from "components/ComponentsList";
import GitHub from "generated/gitInfo";
import { useSideNavEnabled } from "hooks/useSideNavEnabled";

export const Landing = ({ sideNavEnabled }: { sideNavEnabled?: boolean }) => {
Expand Down Expand Up @@ -48,12 +49,17 @@ export const Landing = ({ sideNavEnabled }: { sideNavEnabled?: boolean }) => {
<div className="Section__content">
<Heading2>Current version</Heading2>

<TextLink href="https://www.npmjs.com/package/@stellar/design-system">
<img
src="https://img.shields.io/npm/v/@stellar/design-system.svg?style=flat-square"
alt="npm version"
/>
</TextLink>
<p>
<TextLink href="https://www.npmjs.com/package/@stellar/design-system">
<img
src="https://img.shields.io/npm/v/@stellar/design-system.svg?style=flat-square"
alt="npm version"
/>
</TextLink>
</p>
<p>
Website: <code>{GitHub.commitHash}</code>
</p>
</div>
</div>

Expand Down
4 changes: 4 additions & 0 deletions @stellar/design-system-website/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
margin-top: 1rem;
}

.Layout__header {
z-index: 1;
}

.Layout__containerWithSideNav {
display: flex;

Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1862,6 +1862,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=

"@types/lodash@^4.14.171":
version "4.14.171"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b"
integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg==

"@types/minimatch@*", "@types/minimatch@^3.0.3":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
Expand Down

0 comments on commit d30b657

Please sign in to comment.