Skip to content

Instantly share code, notes, and snippets.

@horaciosystem
Last active January 27, 2021 21:32
Show Gist options
  • Save horaciosystem/253bdfbbbb524a12282bb57a3ee70290 to your computer and use it in GitHub Desktop.
Save horaciosystem/253bdfbbbb524a12282bb57a3ee70290 to your computer and use it in GitHub Desktop.
Sidebar [react, reakit, tailwindcss, postcss, postcss-nested]
import {
useDialogState,
Dialog,
DialogDisclosure,
DialogBackdrop,
} from "reakit/Dialog"
import styles from "./Layout.module.css"
function Layout({ children }) {
const dialog = useDialogState({ animated: true })
const { productDomain } = useProduct()
Router.events.on("routeChangeComplete", () => dialog.hide())
return (
<>
<div>
<Header
openSidebarButton={
<DialogDisclosure
data-test-id="open-sidebar-button"
as={Button}
theme="primary"
size="sm"
{...dialog}
aria-label="open menu"
className="mr-2 md:mr-4 min-w-0 flex-shrink-0"
>
<MenuIcon className="w-6 md:w-6" />
</DialogDisclosure>
}
/>
{children}
<UserModules />
<DialogBackdrop {...dialog} className={styles.sidebarBackdrop}>
<Dialog
{...dialog}
aria-label="Navigation bar"
className={`${styles.sidebar} bg-inverse w-65`}
preventBodyScroll
hideOnClickOutside
hideOnEsc
tabIndex={0}
>
<SideNavbar />
</Dialog>
</DialogBackdrop>
</div>
</>
)
}
.sidebar {
position: fixed;
left: 0;
top: 0;
height: 100vh;
overflow: auto;
z-index: 999;
outline: 0;
will-change: transform;
transition: transform 0.3s ease;
transform: translate3d(-100%, 0, 0);
&[data-enter] {
transform: translate3d(0, 0, 0);
}
}
.sidebarBackdrop {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
&[data-enter] {
opacity: 1;
}
}
import React from "react"
import { useRouter } from "next/router"
import { useOrganization } from "app/common/Organization"
import InternalLink from "app/common/InternalLink"
import OrganizationIcon from "app/common/icons/Organization"
import { Text } from "app/ui"
import {
useDisclosureState,
Disclosure,
DisclosureContent,
} from "reakit/Disclosure"
import styles from "./SideNavbar.module.css"
import { useUniversalCtx } from "app/lib/universal-context"
function SideNavbar() {
const organization = useOrganization()
const appContext = useUniversalCtx()
const router = useRouter()
const { route } = router
const routes = filterRoutesByProduct(appContext)
return (
<div data-test-id="sidebar" className="text-xl text-secondary pb-16">
<header className="flex items-center p-4">
<div className="pr-4 flex-shrink-0">
<OrganizationIcon className="w-8 h-8" />
</div>
<Text size="sm" className="font-bold text-secondary truncate">
{organization?.name}
</Text>
</header>
<nav aria-label="primary" role="navigation">
{routes.map((item) => {
if (item.items) {
return (
<NavSubmenuItem
key={item.label}
{...item}
organizationSlug={organization?.slug}
currentRoute={route}
/>
)
}
return (
<NavLink
key={item.label}
{...item}
organizationSlug={organization?.slug}
currentRoute={route}
/>
)
})}
</nav>
</div>
)
}
function NavSubmenuItem({ label, items, organizationSlug, currentRoute }) {
const isChildActive = items.some((it) => it.href === currentRoute)
const disclosure = useDisclosureState({
visible: isChildActive,
animated: true,
})
return (
<div>
<Disclosure
{...disclosure}
className={`transition-colors duration-300 ease-in-out flex w-full items-center font-semibold justify-between px-4 h-16 is-inverse`}
>
{label}
<ChevronIcon
className={`${styles.navSubmenuIcon} ${
disclosure.visible && styles.isExpanded
}`}
/>
</Disclosure>
<DisclosureContent
{...disclosure}
className={`${isChildActive} ? "bg-white" : "bg-transparent" ${styles.navSubmenu}`}
>
{items.map(({ label, href }) => (
<NavLink
key={label}
label={label}
href={href}
organizationSlug={organizationSlug}
currentRoute={currentRoute}
isSubmenuItem
/>
))}
</DisclosureContent>
</div>
)
}
function NavLink({
label,
href,
organizationSlug,
currentRoute,
isSubmenuItem,
}) {
const isActive = href === currentRoute
const as = href.replace("[organizationSlug]", organizationSlug)
const theme = isActive
? "is-secondary"
: isSubmenuItem
? styles.navSubItem
: "is-inverse"
return (
<InternalLink
href={href}
as={as}
className={`transition-colors duration-300 ease-in-out h-16 ${theme}`}
aria-label={label}
{...(isActive && { "aria-current": "page" })}
>
<span className={isSubmenuItem ? "pl-3" : undefined}>{label}</span>
</InternalLink>
)
}
export default SideNavbar
.navSubmenu {
@apply h-auto overflow-hidden;
will-change: content;
transition: max-height 350ms ease-in-out;
max-height: 0;
&[data-enter] {
@apply max-h-screen;
}
}
.navSubmenuIcon {
will-change: transform;
transition: transform 300ms ease;
transform: rotate(0deg);
&.isExpanded {
transform: rotate(90deg);
}
}
.navSubItem {
@apply bg-white text-secondary;
&:active,
&:focus {
@apply bg-inverse-lighten text-primary-lighten;
}
&:hover {
@apply bg-inverse-darken text-white;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment