Skip to content

Commit 0864eb8

Browse files
authored
feat: docs sidebar footer with version and product name (#356)
- **fix: run audit fixes from npm** - **feat: provide docsidebar** - **feat: provide footer with product and version**
1 parent f3f9513 commit 0864eb8

File tree

9 files changed

+314
-0
lines changed

9 files changed

+314
-0
lines changed

src/components/DocSidebarFooter.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, { useEffect, useState } from "react";
2+
import { useActiveDocContext } from "@docusaurus/plugin-content-docs/client";
3+
4+
export default function DocSidebarFooter() {
5+
const [currentPlugin, setCurrentPlugin] = useState('default');
6+
const [activeProduct, setActiveProduct] = useState('fluvio');
7+
8+
useEffect(() => {
9+
const isBrowser = typeof window !== 'undefined';
10+
11+
if (isBrowser) {
12+
const location = window.location.pathname;
13+
14+
if (location.startsWith('/sdf')) {
15+
setCurrentPlugin('sdf');
16+
setActiveProduct('sdf');
17+
} else {
18+
setCurrentPlugin('default');
19+
setActiveProduct('fluvio');
20+
}
21+
}
22+
}, [currentPlugin]);
23+
24+
const version = useActiveDocContext(currentPlugin);
25+
26+
return (
27+
<footer className="font-mono text-xs py-2 px-5">
28+
{activeProduct}<span className="font-mono">@</span><span className="font-mono">{version?.activeVersion?.label}</span>
29+
</footer>
30+
);
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import {translate} from '@docusaurus/Translate';
4+
import IconArrow from '@theme/Icon/Arrow';
5+
import type {Props} from '@theme/DocSidebar/Desktop/CollapseButton';
6+
7+
import styles from './styles.module.css';
8+
9+
export default function CollapseButton({onClick}: Props): JSX.Element {
10+
return (
11+
<button
12+
type="button"
13+
title={translate({
14+
id: 'theme.docs.sidebar.collapseButtonTitle',
15+
message: 'Collapse sidebar',
16+
description: 'The title attribute for collapse button of doc sidebar',
17+
})}
18+
aria-label={translate({
19+
id: 'theme.docs.sidebar.collapseButtonAriaLabel',
20+
message: 'Collapse sidebar',
21+
description: 'The title attribute for collapse button of doc sidebar',
22+
})}
23+
className={clsx(
24+
'button button--secondary button--outline',
25+
styles.collapseSidebarButton,
26+
)}
27+
onClick={onClick}>
28+
<IconArrow className={styles.collapseSidebarButtonIcon} />
29+
</button>
30+
);
31+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
:root {
2+
--docusaurus-collapse-button-bg: transparent;
3+
--docusaurus-collapse-button-bg-hover: rgb(0 0 0 / 10%);
4+
}
5+
6+
[data-theme='dark']:root {
7+
--docusaurus-collapse-button-bg: rgb(255 255 255 / 5%);
8+
--docusaurus-collapse-button-bg-hover: rgb(255 255 255 / 10%);
9+
}
10+
11+
@media (min-width: 997px) {
12+
.collapseSidebarButton {
13+
display: block !important;
14+
background-color: var(--docusaurus-collapse-button-bg);
15+
height: 40px;
16+
position: sticky;
17+
bottom: 0;
18+
border-radius: 0;
19+
border: 1px solid var(--ifm-toc-border-color);
20+
}
21+
22+
.collapseSidebarButtonIcon {
23+
transform: rotate(180deg);
24+
margin-top: 4px;
25+
}
26+
27+
[dir='rtl'] .collapseSidebarButtonIcon {
28+
transform: rotate(0);
29+
}
30+
31+
.collapseSidebarButton:hover,
32+
.collapseSidebarButton:focus {
33+
background-color: var(--docusaurus-collapse-button-bg-hover);
34+
}
35+
}
36+
37+
.collapseSidebarButton {
38+
display: none;
39+
margin: 0;
40+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React, {useState} from 'react';
2+
import clsx from 'clsx';
3+
import {ThemeClassNames} from '@docusaurus/theme-common';
4+
import {
5+
useAnnouncementBar,
6+
useScrollPosition,
7+
} from '@docusaurus/theme-common/internal';
8+
import {translate} from '@docusaurus/Translate';
9+
import DocSidebarItems from '@theme/DocSidebarItems';
10+
import type {Props} from '@theme/DocSidebar/Desktop/Content';
11+
12+
import styles from './styles.module.css';
13+
14+
function useShowAnnouncementBar() {
15+
const {isActive} = useAnnouncementBar();
16+
const [showAnnouncementBar, setShowAnnouncementBar] = useState(isActive);
17+
18+
useScrollPosition(
19+
({scrollY}) => {
20+
if (isActive) {
21+
setShowAnnouncementBar(scrollY === 0);
22+
}
23+
},
24+
[isActive],
25+
);
26+
return isActive && showAnnouncementBar;
27+
}
28+
29+
export default function DocSidebarDesktopContent({
30+
path,
31+
sidebar,
32+
className,
33+
}: Props): JSX.Element {
34+
const showAnnouncementBar = useShowAnnouncementBar();
35+
36+
return (
37+
<nav
38+
aria-label={translate({
39+
id: 'theme.docs.sidebar.navAriaLabel',
40+
message: 'Docs sidebar',
41+
description: 'The ARIA label for the sidebar navigation',
42+
})}
43+
className={clsx(
44+
'menu thin-scrollbar',
45+
styles.menu,
46+
showAnnouncementBar && styles.menuWithAnnouncementBar,
47+
className,
48+
)}>
49+
<ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list')}>
50+
<DocSidebarItems items={sidebar} activePath={path} level={1} />
51+
</ul>
52+
</nav>
53+
);
54+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@media (min-width: 997px) {
2+
.menu {
3+
flex-grow: 1;
4+
padding: 0.5rem;
5+
}
6+
@supports (scrollbar-gutter: stable) {
7+
.menu {
8+
padding: 0.5rem 0 0.5rem 0.5rem;
9+
scrollbar-gutter: stable;
10+
}
11+
}
12+
13+
.menuWithAnnouncementBar {
14+
margin-bottom: var(--docusaurus-announcement-bar-height);
15+
}
16+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import {useThemeConfig} from '@docusaurus/theme-common';
4+
import Logo from '@theme/Logo';
5+
import CollapseButton from '@theme/DocSidebar/Desktop/CollapseButton';
6+
import Content from '@theme/DocSidebar/Desktop/Content';
7+
import type {Props} from '@theme/DocSidebar/Desktop';
8+
9+
import styles from './styles.module.css';
10+
import DocSidebarFooter from '@site/src/components/DocSidebarFooter';
11+
12+
function DocSidebarDesktop({path, sidebar, onCollapse, isHidden}: Props) {
13+
const {
14+
navbar: {hideOnScroll},
15+
docs: {
16+
sidebar: {hideable},
17+
},
18+
} = useThemeConfig();
19+
20+
return (
21+
<div
22+
className={clsx(
23+
styles.sidebar,
24+
hideOnScroll && styles.sidebarWithHideableNavbar,
25+
isHidden && styles.sidebarHidden,
26+
)}>
27+
{hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
28+
<Content path={path} sidebar={sidebar} />
29+
{hideable && <CollapseButton onClick={onCollapse} />}
30+
<DocSidebarFooter />
31+
</div>
32+
);
33+
}
34+
35+
export default React.memo(DocSidebarDesktop);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@media (min-width: 997px) {
2+
.sidebar {
3+
display: flex;
4+
flex-direction: column;
5+
height: 100%;
6+
padding-top: var(--ifm-navbar-height);
7+
width: var(--doc-sidebar-width);
8+
}
9+
10+
.sidebarWithHideableNavbar {
11+
padding-top: 0;
12+
}
13+
14+
.sidebarHidden {
15+
opacity: 0;
16+
visibility: hidden;
17+
}
18+
19+
.sidebarLogo {
20+
display: flex !important;
21+
align-items: center;
22+
margin: 0 var(--ifm-navbar-padding-horizontal);
23+
min-height: var(--ifm-navbar-height);
24+
max-height: var(--ifm-navbar-height);
25+
color: inherit !important;
26+
text-decoration: none !important;
27+
}
28+
29+
.sidebarLogo img {
30+
margin-right: 0.5rem;
31+
height: 2rem;
32+
}
33+
}
34+
35+
.sidebarLogo {
36+
display: none;
37+
}

src/theme/DocSidebar/Mobile/index.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import {
4+
NavbarSecondaryMenuFiller,
5+
type NavbarSecondaryMenuComponent,
6+
ThemeClassNames,
7+
} from '@docusaurus/theme-common';
8+
import {useNavbarMobileSidebar} from '@docusaurus/theme-common/internal';
9+
import DocSidebarItems from '@theme/DocSidebarItems';
10+
import type {Props} from '@theme/DocSidebar/Mobile';
11+
12+
// eslint-disable-next-line react/function-component-definition
13+
const DocSidebarMobileSecondaryMenu: NavbarSecondaryMenuComponent<Props> = ({
14+
sidebar,
15+
path,
16+
}) => {
17+
const mobileSidebar = useNavbarMobileSidebar();
18+
return (
19+
<ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list')}>
20+
<DocSidebarItems
21+
items={sidebar}
22+
activePath={path}
23+
onItemClick={(item) => {
24+
// Mobile sidebar should only be closed if the category has a link
25+
if (item.type === 'category' && item.href) {
26+
mobileSidebar.toggle();
27+
}
28+
if (item.type === 'link') {
29+
mobileSidebar.toggle();
30+
}
31+
}}
32+
level={1}
33+
/>
34+
</ul>
35+
);
36+
};
37+
38+
function DocSidebarMobile(props: Props) {
39+
return (
40+
<NavbarSecondaryMenuFiller
41+
component={DocSidebarMobileSecondaryMenu}
42+
props={props}
43+
/>
44+
);
45+
}
46+
47+
export default React.memo(DocSidebarMobile);

src/theme/DocSidebar/index.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import {useWindowSize} from '@docusaurus/theme-common';
3+
import DocSidebarDesktop from '@theme/DocSidebar/Desktop';
4+
import DocSidebarMobile from '@theme/DocSidebar/Mobile';
5+
import type {Props} from '@theme/DocSidebar';
6+
7+
export default function DocSidebar(props: Props): JSX.Element {
8+
const windowSize = useWindowSize();
9+
10+
// Desktop sidebar visible on hydration: need SSR rendering
11+
const shouldRenderSidebarDesktop =
12+
windowSize === 'desktop' || windowSize === 'ssr';
13+
14+
// Mobile sidebar not visible on hydration: can avoid SSR rendering
15+
const shouldRenderSidebarMobile = windowSize === 'mobile';
16+
17+
return (
18+
<>
19+
{shouldRenderSidebarDesktop && <DocSidebarDesktop {...props} />}
20+
{shouldRenderSidebarMobile && <DocSidebarMobile {...props} />}
21+
</>
22+
);
23+
}

0 commit comments

Comments
 (0)