Skip to content

Commit 5cecf6b

Browse files
committed
navigation rail
1 parent c006f73 commit 5cecf6b

File tree

3 files changed

+94
-24
lines changed

3 files changed

+94
-24
lines changed
Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,25 @@
1-
import { Icon, List, ListItem, NavigationRail } from 'actify'
1+
import { NavigationRail } from 'actify'
22

33
export default () => {
4-
const list = [
4+
const items = [
55
{
66
label: 'Home',
7-
icon: <Icon>home</Icon>
7+
icon: 'home',
8+
badge: 1234
89
},
910
{
1011
label: 'Camera',
11-
icon: <Icon>photo_camera</Icon>
12+
icon: 'photo_camera'
1213
},
1314
{
1415
label: 'User',
15-
icon: <Icon>person</Icon>
16+
icon: 'person'
1617
},
1718
{
1819
label: 'Settings',
19-
icon: <Icon>settings</Icon>
20+
icon: 'settings'
2021
}
2122
]
2223

23-
return (
24-
<NavigationRail>
25-
<List className="py-3 w-full">
26-
{list.map((item, index) => (
27-
<ListItem key={index} className="pl-0 py-2 flex flex-col">
28-
{item.icon}
29-
<span className="text-xs font-semibold mt-1">{item.label}</span>
30-
</ListItem>
31-
))}
32-
</List>
33-
</NavigationRail>
34-
)
24+
return <NavigationRail items={items} />
3525
}

packages/actify/src/components/NavigationRail/NavigationRail.tsx

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,75 @@
11
'use client'
22

3+
import { Badge } from '../Badges'
4+
import { Icon } from '../Icon'
35
import React from 'react'
6+
import { Ripple } from '../Ripple'
47
import clsx from 'clsx'
58
import styles from './navigation-rail.module.css'
9+
import { useControllableState } from '../../hooks'
610

7-
interface NavigationRailProps extends React.ComponentProps<'div'> {}
11+
interface Item extends React.ComponentProps<'button'> {
12+
label: string
13+
icon: React.ReactNode
14+
badge?: number | string
15+
isActive?: boolean
16+
}
17+
18+
interface NavigationRailProps extends React.ComponentProps<'div'> {
19+
items: Item[]
20+
menu?: React.ReactNode
21+
value?: number
22+
defaultValue?: number
23+
setValue?: (index: number) => void
24+
}
25+
26+
const Item = (props: Item) => {
27+
const { icon, label, badge, isActive, ...rest } = props
28+
29+
return (
30+
<button
31+
{...rest}
32+
className={clsx(styles['item'], isActive && styles['active'])}
33+
>
34+
<Ripple />
35+
<Badge value={badge}>
36+
{typeof icon == 'string' ? <Icon>{icon}</Icon> : icon}
37+
</Badge>
38+
<label className={styles['label']}>{label}</label>
39+
</button>
40+
)
41+
}
842

943
const NavigationRail = (props: NavigationRailProps) => {
10-
const { children, className, ...rest } = props
44+
const { value, defaultValue, setValue } = props
45+
const [activeIndex, setActiveIndex] = useControllableState({
46+
value,
47+
defaultValue,
48+
onChange: setValue
49+
})
50+
51+
const { children, className, menu, items = [], ...rest } = props
1152
return (
1253
<div {...rest} className={clsx(styles['root'], className)}>
13-
{children}
54+
{/* Menu icon (optional) */}
55+
{menu}
56+
{/* Navigation Items */}
57+
<nav className={styles['items']}>
58+
{items.map((item, index) => {
59+
const { icon, label, badge } = item
60+
const isActive = index == activeIndex
61+
return (
62+
<Item
63+
key={index}
64+
icon={icon}
65+
label={label}
66+
badge={badge}
67+
isActive={isActive}
68+
onClick={() => setActiveIndex(index)}
69+
/>
70+
)
71+
})}
72+
</nav>
1473
</div>
1574
)
1675
}
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
11
.root {
2+
display: inline-flex;
3+
}
4+
.items {
5+
width: 80px;
6+
min-height: 540px;
27
display: flex;
3-
align-items: center;
8+
gap: 12px;
49
justify-content: center;
5-
width: 5rem /* 80px */;
6-
min-height: 33.75rem /* 540px */;
10+
flex-direction: column;
711
background-color: var(--md-sys-color-surface);
812
}
13+
.item {
14+
height: 56px;
15+
width: 100%;
16+
display: flex;
17+
position: relative;
18+
align-items: center;
19+
flex-direction: column;
20+
}
21+
.active {
22+
color: var(--md-sys-color-on-primary);
23+
background-color: var(--md-sys-color-primary);
24+
}
25+
.label {
26+
font-size: 12px;
27+
font-weight: 600;
28+
margin-top: 4px;
29+
}

0 commit comments

Comments
 (0)