Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 77 additions & 86 deletions src/layouts/AdminLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,123 +18,102 @@ import {
UsersIcon,
} from '@heroicons/react/24/outline'
import { Skeleton } from '@/shared/primitives/Skeleton'
import BottomNav from '@/shared/composites/BottomNav/BottomNav'

const AdminLayout = () => {
const [collapsed, setCollapsed] = useState(false)
const [activeItem, setActiveItem] = useState('Queue')
const [loading, setLoading] = useState(true)
const navItems = [
{
label: 'Queue',

useEffect(() => {
const timer = setTimeout(() => {
setLoading(false)
}, 5000)
route: '/queue',

return () => {
clearTimeout(timer)
}
}, [])
icon: <QueueListIcon className="size-4" />,

return (
<div className="bg-bg-primary text-text-primary min-h-screen">
<ToastProvider />
badge: 3,

<aside
className={`fixed top-0 left-0 z-30 h-screen transition-all duration-300 ${
collapsed ? 'w-[72px]' : 'w-64'
} `}
>
<SidebarNav
collapsed={collapsed}
onToggle={() => {
setCollapsed(!collapsed)
}}
items={[
{
label: 'Queue',
badgeVariant: 'danger' as const,
},

icon: <QueueListIcon className="size-4" />,
{
label: 'Resolved',

badge: 3,
route: '/resolved',

badgeVariant: 'danger',
icon: <CheckIcon className="size-4" />,

isActive: activeItem === 'Queue',
badge: 12,

onClick: () => {
setActiveItem('Queue')
badgeVariant: 'info' as const,
},

console.log('Queue clicked')
},
},

{
label: 'Resolved',

icon: <CheckIcon className="size-4" />,
{
label: 'Escalated',

badge: 12,
route: '/escalated',

badgeVariant: 'info',
icon: <ExclamationTriangleIcon className="size-4" />,

isActive: activeItem === 'Resolved',
badge: 1,

onClick: () => {
setActiveItem('Resolved')
badgeVariant: 'danger' as const,
},

console.log('Resolved clicked')
},
},

{
label: 'Escalated',
{
label: 'Users',

icon: <ExclamationTriangleIcon className="size-4" />,
route: '/users',

badge: 1,
icon: <UsersIcon className="size-4" />,
},

badgeVariant: 'danger',
{
label: 'Analytics',

isActive: activeItem === 'Escalated',
route: '/analytics',

onClick: () => {
setActiveItem('Escalated')
icon: <PresentationChartLineIcon className="size-4" />,
},
]

console.log('Escalated clicked')
},
},

{
label: 'Users',

icon: <UsersIcon className="size-4" />,

isActive: activeItem === 'Users',

onClick: () => {
setActiveItem('Users')
const AdminLayout = () => {
const [collapsed, setCollapsed] = useState(false)
const [activeRoute, setActiveRoute] = useState('/queue')
const [loading, setLoading] = useState(true)

console.log('Users clicked')
},
},
useEffect(() => {
const timer = setTimeout(() => {
setLoading(false)
}, 5000)

{
label: 'Analytics',
return () => {
clearTimeout(timer)
}
}, [])

icon: <PresentationChartLineIcon className="size-4" />,
return (
<div className="bg-bg-primary text-text-primary min-h-screen">
<ToastProvider />

isActive: activeItem === 'Analytics',
<aside
className={`fixed top-0 left-0 z-30 hidden h-screen transition-all duration-300 md:block ${collapsed ? 'w-[72px]' : 'w-64'} `}
>
<SidebarNav
collapsed={collapsed}
onToggle={() => {
setCollapsed(!collapsed)
}}
items={navItems.map((item) => ({
...item,

onClick: () => {
setActiveItem('Analytics')
isActive: activeRoute === item.label,

console.log('Analytics clicked')
},
onClick: () => {
setActiveRoute(item.label)
},
]}
}))}
/>
</aside>

<div className={`transition-all duration-300 ${collapsed ? 'ml-[72px]' : 'ml-64'} `}>
<div className={`transition-all duration-300 ${collapsed ? 'md:ml-[72px]' : 'md:ml-64'} `}>
<Topbar
title="Moderation Queue"
showSearch
Expand All @@ -148,10 +127,22 @@ const AdminLayout = () => {
}
/>

<main className="p-6">
<main className="p-6 pb-24 md:pb-6">
<Outlet />
</main>
</div>
<BottomNav
items={navItems}
activeRoute={activeRoute}
onNavigate={(route) => {
setActiveRoute(route)

window.scrollTo({
top: 0,
behavior: 'smooth',
})
}}
/>
</div>
)
}
Expand Down
147 changes: 147 additions & 0 deletions src/shared/composites/BottomNav/BottomNav.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { useState } from 'react'

import type { Meta, StoryObj } from '@storybook/react-vite'

import {
QueueListIcon,
CheckIcon,
ExclamationTriangleIcon,
UsersIcon,
PresentationChartLineIcon,
} from '@heroicons/react/24/outline'

import { BottomNav } from './BottomNav'

const items = [
{
label: 'Queue',

route: '/queue',

icon: <QueueListIcon className="size-5" />,

badge: 3,

badgeVariant: 'danger' as const,
},

{
label: 'Resolved',

route: '/resolved',

icon: <CheckIcon className="size-5" />,

badge: 12,

badgeVariant: 'info' as const,
},

{
label: 'Escalated',

route: '/escalated',

icon: <ExclamationTriangleIcon className="size-5" />,

badge: 1,

badgeVariant: 'danger' as const,
},

{
label: 'Users',

route: '/users',

icon: <UsersIcon className="size-5" />,
},

{
label: 'Analytics',

route: '/analytics',

icon: <PresentationChartLineIcon className="size-5" />,
},
]

const meta = {
title: 'Shared/Composites/BottomNav',

component: BottomNav,

tags: ['autodocs'],

parameters: {
layout: 'fullscreen',

viewport: {
defaultViewport: 'mobile1',
},
},

decorators: [
(Story) => (
<div className="bg-bg-primary min-h-screen">
<Story />
</div>
),
],
} satisfies Meta<typeof BottomNav>

export default meta

type Story = StoryObj

export const Default: Story = {
render: () => (
<BottomNav
items={items}
activeRoute="/queue"
onNavigate={(route) => {
console.log(route)
}}
/>
),
}

export const ThirdItemActive: Story = {
render: () => (
<BottomNav
items={items}
activeRoute="/escalated"
onNavigate={(route) => {
console.log(route)
}}
/>
),
}

export const Interactive: Story = {
render: () => {
const [activeRoute, setActiveRoute] = useState('/queue')

return (
<BottomNav
items={items}
activeRoute={activeRoute}
onNavigate={(route) => {
setActiveRoute(route)
}}
/>
)
},
}

export const AccessibilityPreview: Story = {
render: () => (
<BottomNav
items={items}
activeRoute="/queue"
onNavigate={(route) => {
console.log(route)
}}
/>
),
}
Loading
Loading