Skip to content

Commit f0597fc

Browse files
Merge branch 'git-rid-of-the-new-task-button-at-the-bottom-of-the-repositories-view-which-shouldn-t-be-there-hmcx'
2 parents 9591d7b + 7bdf2ca commit f0597fc

6 files changed

Lines changed: 242 additions & 101 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vibora",
33
"private": true,
4-
"version": "1.12.1",
4+
"version": "1.12.2",
55
"description": "The Vibe Engineer's Cockpit",
66
"license": "PolyForm-Shield-1.0.0",
77
"type": "module",

src/components/kanban/create-task-modal.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ interface CreateTaskModalProps {
6060
open?: boolean
6161
onOpenChange?: (open: boolean) => void
6262
defaultRepository?: Repository
63+
showTrigger?: boolean
6364
}
6465

65-
export function CreateTaskModal({ open: controlledOpen, onOpenChange, defaultRepository }: CreateTaskModalProps = {}) {
66+
export function CreateTaskModal({ open: controlledOpen, onOpenChange, defaultRepository, showTrigger = true }: CreateTaskModalProps = {}) {
6667
const { t } = useTranslation('tasks')
6768
const { t: tc } = useTranslation('common')
6869
const [internalOpen, setInternalOpen] = useState(false)
@@ -238,10 +239,12 @@ export function CreateTaskModal({ open: controlledOpen, onOpenChange, defaultRep
238239
return (
239240
<>
240241
<Dialog open={open} onOpenChange={setOpen}>
241-
<DialogTrigger render={<Button size="sm" />}>
242-
<HugeiconsIcon icon={PlusSignIcon} size={16} strokeWidth={2} data-slot="icon" />
243-
{t('newTask')}
244-
</DialogTrigger>
242+
{showTrigger && (
243+
<DialogTrigger render={<Button size="sm" />}>
244+
<HugeiconsIcon icon={PlusSignIcon} size={16} strokeWidth={2} data-slot="icon" />
245+
{t('newTask')}
246+
</DialogTrigger>
247+
)}
245248
<DialogContent className="sm:max-w-md max-h-[80dvh] flex flex-col overflow-hidden">
246249
<form onSubmit={handleSubmit} className="flex flex-col min-h-0 flex-1">
247250
<DialogHeader className="shrink-0">

src/components/layout/header.tsx

Lines changed: 67 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ import { useState, useEffect } from 'react'
22
import { Link, useRouterState } from '@tanstack/react-router'
33
import { useTranslation } from 'react-i18next'
44
import { Button } from '@/components/ui/button'
5+
import {
6+
NavigationMenu,
7+
NavigationMenuContent,
8+
NavigationMenuItem,
9+
NavigationMenuLink,
10+
NavigationMenuList,
11+
NavigationMenuTrigger,
12+
} from '@/components/ui/navigation-menu'
513
import { HugeiconsIcon } from '@hugeicons/react'
614
import {
715
GridViewIcon,
@@ -12,6 +20,7 @@ import {
1220
GitPullRequestIcon,
1321
BrowserIcon,
1422
ChartLineData01Icon,
23+
More03Icon,
1524
} from '@hugeicons/core-free-icons'
1625
import { CreateTaskModal } from '@/components/kanban/create-task-modal'
1726

@@ -20,119 +29,83 @@ interface HeaderProps {
2029
onOpenCommandPalette?: () => void
2130
}
2231

32+
const NAV_ITEMS = [
33+
{ to: '/tasks', icon: GridViewIcon, labelKey: 'header.tasks', matchPrefix: true },
34+
{ to: '/terminals', icon: CommandLineIcon, labelKey: 'header.terminals', matchPrefix: false },
35+
{ to: '/worktrees', icon: FolderSyncIcon, labelKey: 'header.worktrees', matchPrefix: true },
36+
{ to: '/repositories', icon: Database01Icon, labelKey: 'header.repositories', matchPrefix: true },
37+
{ to: '/review', icon: GitPullRequestIcon, labelKey: 'header.review', matchPrefix: true },
38+
{ to: '/monitoring', icon: ChartLineData01Icon, labelKey: 'header.monitoring', matchPrefix: true },
39+
] as const
40+
2341
export function Header({ onNewTaskRef, onOpenCommandPalette }: HeaderProps) {
2442
const { t } = useTranslation('navigation')
2543
const { location } = useRouterState()
2644
const pathname = location.pathname
2745
const [createTaskOpen, setCreateTaskOpen] = useState(false)
2846

47+
const isActive = (to: string, matchPrefix: boolean) =>
48+
matchPrefix ? pathname.startsWith(to) : pathname === to
49+
2950
// Expose the open function to parent via callback ref pattern
3051
useEffect(() => {
3152
onNewTaskRef?.(() => setCreateTaskOpen(true))
3253
}, [onNewTaskRef])
3354

3455
return (
3556
<header className="sticky top-0 z-10 flex h-12 shrink-0 items-center justify-between border-b border-border bg-black px-4 max-sm:px-2">
36-
<div className="flex min-w-0 items-center gap-4 max-sm:gap-1">
37-
<Link to="/tasks" className="hidden items-center sm:flex">
57+
<div className="flex min-w-0 items-center gap-4 max-sm:gap-2">
58+
<Link to="/tasks" className="flex items-center">
3859
<img src="/vibora-logo.jpeg" alt="Vibora" className="h-7" />
3960
</Link>
4061

41-
<nav className="flex items-center gap-1 max-sm:gap-0">
42-
<Link to="/tasks">
43-
<Button
44-
variant={pathname.startsWith('/tasks') ? 'secondary' : 'ghost'}
45-
size="sm"
46-
className="max-sm:px-2"
47-
>
48-
<HugeiconsIcon
49-
icon={GridViewIcon}
50-
size={16}
51-
strokeWidth={2}
52-
data-slot="icon"
53-
/>
54-
<span className="max-sm:hidden">{t('header.tasks')}</span>
55-
</Button>
56-
</Link>
57-
<Link to="/terminals">
58-
<Button
59-
variant={pathname === '/terminals' ? 'secondary' : 'ghost'}
60-
size="sm"
61-
className="max-sm:px-2"
62-
>
63-
<HugeiconsIcon
64-
icon={CommandLineIcon}
65-
size={16}
66-
strokeWidth={2}
67-
data-slot="icon"
68-
/>
69-
<span className="max-sm:hidden">{t('header.terminals')}</span>
70-
</Button>
71-
</Link>
72-
<Link to="/worktrees">
73-
<Button
74-
variant={pathname.startsWith('/worktrees') ? 'secondary' : 'ghost'}
75-
size="sm"
76-
className="max-sm:px-2"
77-
>
78-
<HugeiconsIcon
79-
icon={FolderSyncIcon}
80-
size={16}
81-
strokeWidth={2}
82-
data-slot="icon"
83-
/>
84-
<span className="max-sm:hidden">{t('header.worktrees')}</span>
85-
</Button>
86-
</Link>
87-
<Link to="/repositories">
88-
<Button
89-
variant={pathname.startsWith('/repositories') ? 'secondary' : 'ghost'}
90-
size="sm"
91-
className="max-sm:px-2"
92-
>
93-
<HugeiconsIcon
94-
icon={Database01Icon}
95-
size={16}
96-
strokeWidth={2}
97-
data-slot="icon"
98-
/>
99-
<span className="max-sm:hidden">{t('header.repositories')}</span>
100-
</Button>
101-
</Link>
102-
<Link to="/review">
103-
<Button
104-
variant={pathname.startsWith('/review') ? 'secondary' : 'ghost'}
105-
size="sm"
106-
className="max-sm:px-2"
107-
>
108-
<HugeiconsIcon
109-
icon={GitPullRequestIcon}
110-
size={16}
111-
strokeWidth={2}
112-
data-slot="icon"
113-
/>
114-
<span className="max-sm:hidden">{t('header.review')}</span>
115-
</Button>
116-
</Link>
117-
<Link to="/monitoring">
118-
<Button
119-
variant={pathname.startsWith('/monitoring') ? 'secondary' : 'ghost'}
120-
size="sm"
121-
className="max-sm:px-2"
122-
>
123-
<HugeiconsIcon
124-
icon={ChartLineData01Icon}
125-
size={16}
126-
strokeWidth={2}
127-
data-slot="icon"
128-
/>
129-
<span className="max-sm:hidden">{t('header.monitoring')}</span>
130-
</Button>
131-
</Link>
62+
{/* Mobile navigation menu */}
63+
<NavigationMenu className="lg:hidden">
64+
<NavigationMenuList>
65+
<NavigationMenuItem>
66+
<NavigationMenuTrigger className="bg-transparent hover:bg-muted/50 data-open:bg-muted/50 gap-1 px-2">
67+
<HugeiconsIcon icon={More03Icon} size={16} strokeWidth={2} />
68+
<span className="sr-only">Menu</span>
69+
</NavigationMenuTrigger>
70+
<NavigationMenuContent className="min-w-48">
71+
{NAV_ITEMS.map((item) => (
72+
<NavigationMenuLink
73+
key={item.to}
74+
href={item.to}
75+
active={isActive(item.to, item.matchPrefix)}
76+
render={<Link to={item.to} />}
77+
>
78+
<HugeiconsIcon icon={item.icon} size={16} strokeWidth={2} />
79+
{t(item.labelKey)}
80+
</NavigationMenuLink>
81+
))}
82+
</NavigationMenuContent>
83+
</NavigationMenuItem>
84+
</NavigationMenuList>
85+
</NavigationMenu>
86+
87+
{/* Desktop navigation */}
88+
<nav className="hidden items-center gap-1 lg:flex">
89+
{NAV_ITEMS.map((item) => (
90+
<Link key={item.to} to={item.to}>
91+
<Button
92+
variant={isActive(item.to, item.matchPrefix) ? 'secondary' : 'ghost'}
93+
size="sm"
94+
>
95+
<HugeiconsIcon
96+
icon={item.icon}
97+
size={16}
98+
strokeWidth={2}
99+
data-slot="icon"
100+
/>
101+
{t(item.labelKey)}
102+
</Button>
103+
</Link>
104+
))}
132105
</nav>
133106
</div>
134107

135-
<div className="flex shrink-0 items-center gap-2 max-sm:gap-1">
108+
<div className="flex shrink-0 items-center gap-2">
136109
<CreateTaskModal open={createTaskOpen} onOpenChange={setCreateTaskOpen} />
137110
<Button
138111
variant="ghost"

0 commit comments

Comments
 (0)