170 lines
7.5 KiB
JavaScript
170 lines
7.5 KiB
JavaScript
import { useLocation } from 'react-router-dom';
|
|
import { SideNav, SideNavSection, SideNavItem } from '@astryxdesign/core/SideNav';
|
|
import { Text } from '@astryxdesign/core/Text';
|
|
|
|
import navItems from '@/menu/navItems';
|
|
|
|
// ==============================|| DOORMILE - SIDE NAV ||============================== //
|
|
// Thin wrapper around Astryx's SideNav template: sections + items driven by navItems.
|
|
// Branding lives in the TopNav logo only — a second logo here (above the nav items)
|
|
// duplicated it, so this stays icon+label only. Collapse state is controlled from
|
|
// MainLayout so the TopNav logo can track it (round mark collapsed, full wordmark
|
|
// expanded).
|
|
|
|
export default function Sidebar({ isCollapsed, onCollapsedChange }) {
|
|
const location = useLocation();
|
|
const isActive = (url) => !!url && location.pathname.startsWith(url);
|
|
|
|
return (
|
|
<>
|
|
<SideNav
|
|
className="doormile-side-nav"
|
|
collapsible={{ isCollapsed, onCollapsedChange, buttonLabel: 'Collapse navigation' }}
|
|
style={{
|
|
// White + a right border/shadow matches the TopNav's chrome so the
|
|
// top and side nav read as one unified surface instead of two
|
|
// mismatched panels (TopNav is white with a bottom border already).
|
|
backgroundColor: '#ffffff',
|
|
borderRight: '1px solid rgba(5, 54, 89, 0.08)',
|
|
boxShadow: '1px 0 3px rgba(15, 23, 42, 0.03)',
|
|
paddingBlock: '12px',
|
|
paddingInline: '8px',
|
|
boxSizing: 'border-box',
|
|
// Astryx's collapsed-rail width reads var(--spacing-12) (48px default),
|
|
// which feels cramped for our icons. Overriding the token on this
|
|
// element only widens the collapsed rail without touching the same
|
|
// token's unrelated uses elsewhere (e.g. AppShell's mobile top bar).
|
|
'--spacing-12': '72px'
|
|
}}
|
|
>
|
|
{navItems.map((grp) => (
|
|
<SideNavSection key={grp.group} title={grp.group}>
|
|
{grp.items.map((item) => (
|
|
<SideNavItem
|
|
key={item.id}
|
|
label={item.title}
|
|
icon={item.icon}
|
|
href={item.url}
|
|
isSelected={isActive(item.url)}
|
|
/>
|
|
))}
|
|
</SideNavSection>
|
|
))}
|
|
</SideNav>
|
|
<style>{`
|
|
/* Astryx packs items 2px apart by default, which reads as one
|
|
merged block on hover instead of distinct rows. The items
|
|
wrapper has no stable class of its own, but it's always the
|
|
section's second/last child div, right after the header. */
|
|
.doormile-side-nav .astryx-side-nav-section > div:last-child {
|
|
gap: 6px !important;
|
|
}
|
|
|
|
/* Collapsed nav items are the only ones Astryx renders with an
|
|
aria-label on the item element itself (expanded rows show the
|
|
label as visible text instead), so it doubles as a stable hook
|
|
for "collapsed only" styling without touching the expanded rail. */
|
|
.doormile-side-nav .astryx-side-nav-item[aria-label] {
|
|
width: 40px;
|
|
height: 40px;
|
|
margin-inline: auto;
|
|
border-radius: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: background-color 0.15s ease;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item[aria-label] .astryx-icon {
|
|
width: 18px !important;
|
|
height: 18px !important;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item[aria-label]:hover {
|
|
background-color: rgba(10, 19, 23, 0.08) !important;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item[aria-label]:focus-visible {
|
|
outline: 2px solid rgba(10, 19, 23, 0.4);
|
|
outline-offset: 2px;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item[aria-label][data-selected='selected'] {
|
|
background-color: rgba(10, 19, 23, 0.12) !important;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item[aria-label][data-selected='selected'] .astryx-icon {
|
|
color: #0A1317 !important;
|
|
}
|
|
|
|
/* Expanded rows: rounded hover/selected states with a left accent
|
|
bar on the active item, instead of the default flat highlight.
|
|
The accent bar is always present (via ::before) but only faded
|
|
in on selection, so clicking a link fades it in smoothly instead
|
|
of the bar snapping into place flush against the row edges.
|
|
Row sizing mirrors doormile_console's NavItem pattern (py: 1,
|
|
i.e. 8px top/bottom padding on the button itself) instead of a
|
|
fixed-height row: the highlight is painted directly on the item's
|
|
own (now-padded) background, so it naturally gets breathing room
|
|
above and below rather than filling a cramped fixed-height box
|
|
edge to edge. */
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label]) {
|
|
position: relative;
|
|
margin-inline: 2px;
|
|
height: auto;
|
|
padding-block: 12px !important;
|
|
transition: background-color 0.15s ease, transform 0.15s ease;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label])::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: -2px;
|
|
top: 12px;
|
|
bottom: 12px;
|
|
width: 3px;
|
|
border-radius: 3px;
|
|
background-color: #0A1317;
|
|
opacity: 0;
|
|
transition: opacity 0.15s ease;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label]):hover {
|
|
background-color: rgba(10, 19, 23, 0.05) !important;
|
|
transform: translateX(2px);
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label]):focus-visible {
|
|
outline: 2px solid rgba(10, 19, 23, 0.4);
|
|
outline-offset: 2px;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label])[data-selected='selected'] {
|
|
background-color: rgba(10, 19, 23, 0.08) !important;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label])[data-selected='selected']::before {
|
|
opacity: 1;
|
|
}
|
|
.doormile-side-nav .astryx-side-nav-item:not([aria-label])[data-selected='selected'] .astryx-icon {
|
|
color: #0A1317 !important;
|
|
}
|
|
|
|
/* Astryx's sticky-bottom footer wrapper (the toggle button's direct
|
|
parent, always the nav's last direct child) drops its top padding
|
|
to 0 in the collapsed state while keeping 8px on the bottom, so
|
|
the arrow sits flush against the top of its box instead of
|
|
centered in the rail's height. Restore matching padding on both
|
|
sides so it centers correctly. */
|
|
.doormile-side-nav > div:last-child {
|
|
padding-block: 8px !important;
|
|
}
|
|
|
|
/* Collapse/expand toggle (the "<" / ">" chevron button). Give it a
|
|
clean circular hover, centered on the same axis as the nav icons
|
|
above it (the rail's own 8px inline padding already keeps it clear
|
|
of the sidebar's edge, so no extra offset is needed here). */
|
|
.doormile-side-nav button[aria-label*="sidebar"],
|
|
.doormile-side-nav button[aria-label*="navigation"] {
|
|
border-radius: 50% !important;
|
|
transition: background-color 0.15s ease !important;
|
|
}
|
|
.doormile-side-nav button[aria-label*="sidebar"]:hover,
|
|
.doormile-side-nav button[aria-label*="navigation"]:hover {
|
|
background-color: rgba(10, 19, 23, 0.08) !important;
|
|
}
|
|
`}</style>
|
|
</>
|
|
);
|
|
}
|