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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ Format: weekly entries grouped by feature area.

---

## 2026-04-06 — Vertical Sidebar Navigation

### Changed
- Replace horizontal nav with vertical sidebar nav using shadcn SidebarMenu primitives
- Move navigation (Inbox, Home, Journal, Tasks) from sidebar header to sidebar content area
- Simplify SidebarHeaderContent to only render traffic lights and vault switcher

---

## 2026-04-06 — Split View Polish

### Fixed
Expand Down
41 changes: 10 additions & 31 deletions apps/desktop/src/renderer/src/components/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
SidebarRail,
useSidebar
} from '@/components/ui/sidebar'
import { HorizontalNav } from '@/components/sidebar/horizontal-nav'
import { SidebarNav } from '@/components/sidebar/sidebar-nav'
import { SidebarSection } from '@/components/sidebar-section'
import { NotesTree } from '@/components/notes-tree'
import { SidebarTagList } from '@/components/sidebar/sidebar-tag-list'
Expand Down Expand Up @@ -75,19 +75,7 @@ const mainNav: {
{ title: 'Tasks', page: 'tasks', icon: SidebarTasks, shortcut: '⌘⌥4' }
]

function SidebarHeaderContent({
items,
isActive,
onNavClick,
inboxCount,
todayTasksCount
}: {
items: typeof mainNav
isActive: (item: import('@/contexts/tabs/types').SidebarItem) => boolean
onNavClick: (page: AppPage) => (e: React.MouseEvent) => void
inboxCount: number
todayTasksCount: number
}) {
function SidebarHeaderContent() {
const { state } = useSidebar()
const isCollapsed = state === 'collapsed'

Expand All @@ -104,16 +92,6 @@ function SidebarHeaderContent({
<VaultSwitcher />
</div>
</div>

{/* Horizontal icon nav — between traffic lights and search */}
<HorizontalNav
items={items}
isActive={isActive}
onNavClick={onNavClick}
inboxCount={inboxCount}
todayTasksCount={todayTasksCount}
isCollapsed={isCollapsed}
/>
</SidebarHeader>
)
}
Expand Down Expand Up @@ -474,14 +452,15 @@ function AppSidebarInner({ currentPage, viewCounts, ...props }: AppSidebarProps)

return (
<Sidebar collapsible="icon" {...props}>
<SidebarHeaderContent
items={mainNav}
isActive={isActiveItem}
onNavClick={handleNavClick}
inboxCount={inboxCount}
todayTasksCount={todayTasksCount}
/>
<SidebarHeaderContent />
<SidebarContent className="flex flex-col overflow-hidden gap-0">
<SidebarNav
items={mainNav}
isActive={isActiveItem}
onNavClick={handleNavClick}
inboxCount={inboxCount}
todayTasksCount={todayTasksCount}
/>
<SidebarDrillDownContainer>{mainContent}</SidebarDrillDownContainer>
</SidebarContent>
<SidebarFooter className="gap-0">
Expand Down
114 changes: 0 additions & 114 deletions apps/desktop/src/renderer/src/components/sidebar/horizontal-nav.tsx

This file was deleted.

66 changes: 66 additions & 0 deletions apps/desktop/src/renderer/src/components/sidebar/sidebar-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
SidebarGroup,
SidebarMenu,
SidebarMenuItem,
SidebarMenuButton,
SidebarMenuBadge
} from '@/components/ui/sidebar'
import type { AppPage } from '@/App'
import type { SidebarItem, TabType } from '@/contexts/tabs/types'

interface NavItem {
title: string
page: AppPage
icon: React.ComponentType<{ className?: string; size?: number }>
shortcut?: string
}

interface SidebarNavProps {
items: NavItem[]
isActive: (item: SidebarItem) => boolean
onNavClick: (page: AppPage) => (e: React.MouseEvent) => void
inboxCount: number
todayTasksCount: number
}

export function SidebarNav({
items,
isActive,
onNavClick,
inboxCount,
todayTasksCount
}: SidebarNavProps) {
return (
<SidebarGroup className="shrink-0 py-1.5 pb-0">
<SidebarMenu>
{items.map((item) => {
const sidebarItem: SidebarItem = {
type: item.page as TabType,
title: item.title,
path: `/${item.page}`
}
const active = isActive(sidebarItem)
const badgeCount =
item.page === 'inbox' ? inboxCount : item.page === 'tasks' ? todayTasksCount : 0
const tooltipLabel = item.shortcut ? `${item.title} ${item.shortcut}` : item.title

return (
<SidebarMenuItem key={item.page}>
<SidebarMenuButton
tooltip={tooltipLabel}
isActive={active}
onClick={onNavClick(item.page)}
>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
{badgeCount > 0 && (
<SidebarMenuBadge>{badgeCount > 9 ? '9+' : badgeCount}</SidebarMenuBadge>
)}
</SidebarMenuItem>
)
})}
</SidebarMenu>
</SidebarGroup>
)
}
Loading