Skip to content

Commit

Permalink
💄 Docs NavBar consistency and docs UI rework (#2175)
Browse files Browse the repository at this point in the history
* add sticky prop to navbar

* implement navbar sticky + navbar replacement in docs

* move navbar ontop of left hand nav

* docs ui overhaul

* drop shadow and increase gap

* drop z-index to hide behind cookie banner

* remove outdated + out of style mobile nav (that is replaced in side bar)

* modernize version button

* rm unused styling

* modernize search tab

* fix mobile and tablet overlay z-index

* nav menu opener interaction

* chevron padding

* closing z-index fix

* fix mobile nav toggle
  • Loading branch information
joshbermanssw authored Sep 17, 2024
1 parent b0528e3 commit 724b70b
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 227 deletions.
40 changes: 28 additions & 12 deletions components/DocumentationNavigation/DocsLeftSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,39 @@ import styled, { css } from 'styled-components'

export const DocsLeftSidebar = styled.div<{ open: boolean }>`
line-height: 1.25;
background-color: white;
border-right: 1px solid var(--color-grey-2);
padding: 0;
background-color: rgba(255, 255, 255, 0.5);
padding: 10px;
position: fixed;
z-index: 250;
left: 0;
z-index: 49;
left: 0;
top: 0;
width: 80%;
min-width: 16rem;
max-width: 24rem;
height: 100%;
z-index: 1250;
height: 100%;
z-index: 49;
transform: translate3d(-100%, 0, 0);
transition: all 140ms ease-in;
display: flex;
flex-direction: column;
align-content: space-between;
overflow: visible;
border-radius: 0.75rem;
box-shadow: 0 15px 20px -5px rgba(0, 0, 0, 0.05),
0 -5px 30px -5px rgba(0, 0, 0, 0.05),
0 15px 20px -5px rgba(0, 0, 0, 0.05),
0 -5px 20px -5px rgba(0, 0, 0, 0.05);
> ul {
flex: 1 1 auto;
padding: 1rem 1px 1rem 0;
background: linear-gradient(to bottom, white, rgba(255, 255, 255, 0) 1rem),
background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0) 1rem),
linear-gradient(to bottom, var(--color-grey-1), white 1rem);
background-attachment: local, scroll;
background-repeat: no-repeat;
background-size: 100% 1rem, 100% 1rem;
margin-right: -1px;
}
${props =>
Expand All @@ -42,12 +47,23 @@ export const DocsLeftSidebar = styled.div<{ open: boolean }>`
@media (min-width: 840px) {
position: sticky;
height: 100vh;
top: 0;
height: calc(100vh - 80px);
top: 40px;
grid-area: sidebar;
place-self: stretch;
width: 100%;
left: 0;
left: 40px;
transform: translate3d(0, 0, 0);
margin-top: 30px;
margin-bottom: 40px;
}
@media (max-width: 840px) {
background-color: var(--color-light);
height: 100%;
padding: 0;
}
`
162 changes: 68 additions & 94 deletions components/DocumentationNavigation/DocsNavigationList.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import React, { createContext } from 'react'
import styled, { css } from 'styled-components'
import { DocsNavProps } from './DocumentationNavigation'
import { useRouter } from 'next/router'
import { matchActualTarget } from 'utils'
import { DynamicLink } from '../../components/ui'
import docsLinks from '../../content/docs-navigation.json'
import { BiChevronRight } from 'react-icons/bi'
import AnimateHeight from 'react-animate-height'
import data from '../../content/siteConfig.json'
import React, { createContext } from 'react';
import styled, { css } from 'styled-components';
import { DocsNavProps } from './DocumentationNavigation';
import { useRouter } from 'next/router';
import { matchActualTarget } from 'utils';
import { DynamicLink } from '../../components/ui';
import docsLinks from '../../content/docs-navigation.json';
import { BiChevronRight } from 'react-icons/bi';
import AnimateHeight from 'react-animate-height';
import data from '../../content/siteConfig.json';

interface NavTitleProps {
level: number
selected: boolean
childSelected?: boolean
children: React.ReactNode | React.ReactNode[]
onClick?: () => void
level: number;
selected: boolean;
childSelected?: boolean;
children: React.ReactNode | React.ReactNode[];
onClick?: () => void;
}

const NavTitle = ({
Expand All @@ -41,18 +41,18 @@ const NavTitle = ({
selected: 'text-[15px] font-sans pt-0.5 font-bold text-blue-500',
childSelected: 'text-[15px] font-sans pt-1 font-[500] text-gray-800',
},
}
};

const headerLevel = level > 3 ? 3 : level
const headerLevel = level > 3 ? 3 : level;
const selectedClass = selected
? 'selected'
: childSelected
? 'childSelected'
: 'default'
: 'default';
const classes =
level < 1
? headerLevelClasses[headerLevel]
: headerLevelClasses[headerLevel][selectedClass]
: headerLevelClasses[headerLevel][selectedClass];

return (
<div
Expand All @@ -61,76 +61,77 @@ const NavTitle = ({
>
{children}
</div>
)
}
);
};

const hasNestedSlug = (navItems = [], slug) => {
for (let item of navItems) {
if (matchActualTarget(item.slug || item.href, slug)) {
return true
return true;
}
if (item.items) {
if (hasNestedSlug(item.items, slug)) {
return true
return true;
}
}
}
return false
}
return false;
};

const NavLevel = ({
navListElem,
categoryData,
level = 0,
}: {
navListElem?: any
categoryData: any
level?: number
navListElem?: any;
categoryData: any;
level?: number;
}) => {
const navLevelElem = React.useRef(null)
const router = useRouter()
const path = router.asPath
const slug = categoryData.slug
const navLevelElem = React.useRef(null);
const router = useRouter();
const path = router.asPath;
const slug = categoryData.slug;
const [expanded, setExpanded] = React.useState(
matchActualTarget(slug || categoryData.href, path) ||
hasNestedSlug(categoryData.items, path) ||
level === 0
)
);

const selected = path == slug || (slug == '/docs' && path == "/docs/")
const childSelected = hasNestedSlug(categoryData.items, router.asPath)


React.useEffect(() => {
if (
navListElem &&
navLevelElem.current &&
navListElem.current &&
selected
) {
const scrollOffset = navListElem.current.scrollTop
const navListOffset = navListElem.current.getBoundingClientRect().top
const navListHeight = navListElem.current.offsetHeight
const navItemOffset = navLevelElem.current.getBoundingClientRect().top
const scrollOffset = navListElem.current.scrollTop;
const navListOffset = navListElem.current.getBoundingClientRect().top;
const navListHeight = navListElem.current.offsetHeight;
const navItemOffset = navLevelElem.current.getBoundingClientRect().top;
const elementOutOfView =
navItemOffset - navListOffset > navListHeight + scrollOffset
navItemOffset - navListOffset > navListHeight + scrollOffset;

if (elementOutOfView) {
navLevelElem.current.scrollIntoView({
behavior: 'auto',
block: 'center',
inline: 'nearest',
})
});
}
}
}, [navLevelElem.current, navListElem, selected])
}, [navLevelElem.current, navListElem, selected]);

return (
<>
<NavLabelContainer ref={navLevelElem} status={categoryData.status}>
{categoryData.slug ? (
<DynamicLink href={categoryData.slug} passHref>
<NavTitle level={level} selected={selected && !childSelected}>
<span className="bg-white pr-2 -mr-2">{categoryData.title}</span>
<span className="pr-2 -mr-2">{categoryData.title}</span>
</NavTitle>
</DynamicLink>
) : (
Expand All @@ -139,10 +140,10 @@ const NavLevel = ({
selected={selected && !childSelected}
childSelected={childSelected}
onClick={() => {
setExpanded(!expanded)
setExpanded(!expanded);
}}
>
<span className="bg-white pr-2 -mr-2">{categoryData.title}</span>
<span className=" pr-2 -mr-2">{categoryData.title}</span>
{categoryData.items && !selected && (
<BiChevronRight
className={`${
Expand Down Expand Up @@ -183,11 +184,11 @@ const NavLevel = ({
</AnimateHeight>
)}
</>
)
}
);
};

interface NavLevelChildContainerProps {
level: number
level: number;
}

const NavLevelChildContainer = styled.div<NavLevelChildContainerProps>`
Expand All @@ -204,7 +205,7 @@ const NavLevelChildContainer = styled.div<NavLevelChildContainerProps>`
padding-top: 0.25rem;
padding-bottom: 0.125rem;
`}
`
`;

const NavLabelContainer = styled.div<{ status: string }>`
position: relative;
Expand Down Expand Up @@ -238,24 +239,14 @@ const NavLabelContainer = styled.div<{ status: string }>`
align-self: center;
}
`}
`
`;

export const DocsNavigationList = ({ navItems }: DocsNavProps) => {
const router = useRouter()
const navListElem = React.useRef(null)
const router = useRouter();
const navListElem = React.useRef(null);

return (
<>
<MobileMainNav>
{docsLinks &&
docsLinks.map(({ id, href, label }) => {
return (
<DynamicLink key={id + href} href={href} passHref>
<div key={id}>{label}</div>
</DynamicLink>
)
})}
</MobileMainNav>
<DocsNavigationContainer ref={navListElem}>
{navItems.map((categoryData) => (
<NavLevel
Expand All @@ -269,54 +260,37 @@ export const DocsNavigationList = ({ navItems }: DocsNavProps) => {
))}
</DocsNavigationContainer>
</>
)
}

const MobileMainNav = styled.div`
padding: 0.5rem 0;
background: var(--color-grey-1);
border-bottom: 1px solid var(--color-light-dark);
a {
display: block;
text-decoration: none;
font-size: 1rem;
font-weight: bold;
padding: 0.375rem 1rem 0.375rem 1rem;
color: var(--color-orange);
margin: 0;
font-family: var(--font-tuner);
font-style: normal;
opacity: 1;
transition: transform 180ms ease-out;
line-height: 1;
&:hover,
&:focus {
text-decoration: none;
transform: translate3d(-1px, -2px, 0);
}
}
);
};

@media (min-width: 1200px) {
display: none;
}
`

const DocsNavigationContainer = styled.div`
overflow-y: auto;
overflow-x: hidden;
padding: 0.5rem 0 1.5rem 0;
margin-right: -1px;
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
@media (min-width: 1600px) {
padding: 1rem 1rem 2rem 1rem;
}
`
`;

const AnchorIcon = styled.span`
display: inline-block;
position: relative;
transform: translate3d(0, 0, 0);
transition: all 150ms ease-out;
`
`;
Loading

0 comments on commit 724b70b

Please sign in to comment.