refactor(nav): reorganize sidebar with dynamic sections at top

- move runs and sessions to top of navigation (most dynamic)
- add visual separator between dynamic and configuration sections
- reorder remaining items: scenarios, snippets, credentials, environments
- implement separator component in nav rendering logic
This commit is contained in:
2026-04-14 23:15:49 +03:00
parent 6c43b53590
commit 622924ed53
2 changed files with 32 additions and 18 deletions
+6
View File
@@ -95,6 +95,12 @@
background: var(--color-secondary-hover); background: var(--color-secondary-hover);
} }
.navSeparator {
height: var(--border-width);
background: var(--color-border);
margin: var(--space-2) var(--space-2);
}
.main { .main {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
+26 -18
View File
@@ -90,13 +90,17 @@ const SnippetDetailPage = lazy(() =>
import('./pages/snippet/SnippetDetailPage').then((m) => ({ default: m.SnippetDetailPage })), import('./pages/snippet/SnippetDetailPage').then((m) => ({ default: m.SnippetDetailPage })),
); );
const NAV: { path: string; labelKey: string; Icon: LucideIcon }[] = [ const NAV: (
{ path: '/environments', labelKey: 'nav.environments', Icon: Globe }, | { path: string; labelKey: string; Icon: LucideIcon }
{ path: '/credentials', labelKey: 'nav.credentials', Icon: KeyRound }, | { separator: true }
{ path: '/snippets', labelKey: 'nav.snippets', Icon: Braces }, )[] = [
{ path: '/sessions', labelKey: 'nav.sessions', Icon: Monitor },
{ path: '/scenarios', labelKey: 'nav.scenarios', Icon: ClipboardList },
{ path: '/runs', labelKey: 'nav.runs', Icon: Activity }, { path: '/runs', labelKey: 'nav.runs', Icon: Activity },
{ path: '/sessions', labelKey: 'nav.sessions', Icon: Monitor },
{ separator: true },
{ path: '/scenarios', labelKey: 'nav.scenarios', Icon: ClipboardList },
{ path: '/snippets', labelKey: 'nav.snippets', Icon: Braces },
{ path: '/credentials', labelKey: 'nav.credentials', Icon: KeyRound },
{ path: '/environments', labelKey: 'nav.environments', Icon: Globe },
]; ];
export default function App() { export default function App() {
@@ -114,18 +118,22 @@ export default function App() {
> >
<div className={styles.sideContent}> <div className={styles.sideContent}>
<nav className={styles.nav}> <nav className={styles.nav}>
{NAV.map(({ path, labelKey, Icon }) => ( {NAV.map((item, index) =>
<NavLink 'separator' in item ? (
key={path} <div key={`separator-${index}`} className={styles.navSeparator} />
to={path} ) : (
className={({ isActive }) => <NavLink
[styles.navItem, isActive ? styles.navItemActive : ''].filter(Boolean).join(' ') key={item.path}
} to={item.path}
> className={({ isActive }) =>
<Icon size={16} className={styles.navIcon} aria-hidden="true" /> [styles.navItem, isActive ? styles.navItemActive : ''].filter(Boolean).join(' ')
{t(labelKey)} }
</NavLink> >
))} <item.Icon size={16} className={styles.navIcon} aria-hidden="true" />
{t(item.labelKey)}
</NavLink>
),
)}
</nav> </nav>
<div className={styles.sideFooter}> <div className={styles.sideFooter}>