commit ddfc4272e7f7f61702f586a9cfff36bd26eb55d8
Author: Coder Agent <coder@agents.omni>
Date: Wed Feb 18 13:48:18 2026
Unify task web navbar to double-bar pattern matching news/files
Replace the hamburger sidebar navbar with a clean double-bar layout:
- Top bar: omni brand link + top-level nav (tasks, news, files, stats)
using shared on-nav classes from Omni.Web.Style
- Sub-nav bar: context-sensitive task section links (ready, blocked,
needs help, all, epics, kb) using new subnav/subnav-link classes
Remove hamburger toggle, dropdown menus, and associated CSS. Keep
navbar-dropdown styles (still used by sort dropdown widget).
Task-Id: t-636
diff --git a/Omni/Task/Web/Components.hs b/Omni/Task/Web/Components.hs
index 91a9d665..0cdb164f 100644
--- a/Omni/Task/Web/Components.hs
+++ b/Omni/Task/Web/Components.hs
@@ -555,39 +555,21 @@ taskBreadcrumbs allTasks task =
-- * Navbar
navbar :: (Monad m) => Lucid.HtmlT m ()
-navbar =
- Lucid.nav_ [Lucid.class_ "navbar"] <| do
- Lucid.a_ [Lucid.href_ "/tasks", Lucid.class_ "navbar-brand"] "omni"
- Lucid.input_
- [ Lucid.type_ "checkbox",
- Lucid.id_ "navbar-toggle",
- Lucid.class_ "navbar-toggle-checkbox"
- ]
- Lucid.label_
- [ Lucid.for_ "navbar-toggle",
- Lucid.class_ "navbar-hamburger"
- ]
- <| do
- Lucid.span_ [Lucid.class_ "hamburger-line"] ""
- Lucid.span_ [Lucid.class_ "hamburger-line"] ""
- Lucid.span_ [Lucid.class_ "hamburger-line"] ""
- Lucid.div_ [Lucid.class_ "navbar-links"] <| do
- Lucid.a_ [Lucid.href_ "/tasks", Lucid.class_ "navbar-link"] "tasks"
- Lucid.a_ [Lucid.href_ "/news/", Lucid.class_ "navbar-link"] "news"
- Lucid.a_ [Lucid.href_ "/files/", Lucid.class_ "navbar-link"] "files"
- Lucid.div_ [Lucid.class_ "navbar-dropdown"] <| do
- Lucid.button_ [Lucid.class_ "navbar-dropdown-btn"] "tasks ▾"
- Lucid.div_ [Lucid.class_ "navbar-dropdown-content"] <| do
- Lucid.a_ [Lucid.href_ "/ready", Lucid.class_ "navbar-dropdown-item"] "ready"
- Lucid.a_ [Lucid.href_ "/blocked", Lucid.class_ "navbar-dropdown-item"] "blocked"
- Lucid.a_ [Lucid.href_ "/intervention", Lucid.class_ "navbar-dropdown-item"] "needs help"
- Lucid.a_ [Lucid.href_ "/tasks", Lucid.class_ "navbar-dropdown-item"] "all"
- Lucid.div_ [Lucid.class_ "navbar-dropdown"] <| do
- Lucid.button_ [Lucid.class_ "navbar-dropdown-btn"] "plans ▾"
- Lucid.div_ [Lucid.class_ "navbar-dropdown-content"] <| do
- Lucid.a_ [Lucid.href_ "/epics", Lucid.class_ "navbar-dropdown-item"] "epics"
- Lucid.a_ [Lucid.href_ "/kb", Lucid.class_ "navbar-dropdown-item"] "kb"
- Lucid.a_ [Lucid.href_ "/stats", Lucid.class_ "navbar-link"] "stats"
+navbar = do
+ Lucid.nav_ [Lucid.class_ "on-nav"] <| do
+ Lucid.a_ [Lucid.href_ "/", Lucid.class_ "on-nav-brand"] "omni"
+ Lucid.div_ [Lucid.class_ "on-nav-links"] <| do
+ Lucid.a_ [Lucid.href_ "/tasks", Lucid.class_ "on-nav-link on-active"] "tasks"
+ Lucid.a_ [Lucid.href_ "/news/", Lucid.class_ "on-nav-link"] "news"
+ Lucid.a_ [Lucid.href_ "/files/", Lucid.class_ "on-nav-link"] "files"
+ Lucid.a_ [Lucid.href_ "/stats", Lucid.class_ "on-nav-link"] "stats"
+ Lucid.div_ [Lucid.class_ "subnav"] <| do
+ Lucid.a_ [Lucid.href_ "/ready", Lucid.class_ "subnav-link"] "ready"
+ Lucid.a_ [Lucid.href_ "/blocked", Lucid.class_ "subnav-link"] "blocked"
+ Lucid.a_ [Lucid.href_ "/intervention", Lucid.class_ "subnav-link"] "needs help"
+ Lucid.a_ [Lucid.href_ "/tasks", Lucid.class_ "subnav-link"] "all"
+ Lucid.a_ [Lucid.href_ "/epics", Lucid.class_ "subnav-link"] "epics"
+ Lucid.a_ [Lucid.href_ "/kb", Lucid.class_ "subnav-link"] "kb"
-- * Badges
diff --git a/Omni/Task/Web/Style.hs b/Omni/Task/Web/Style.hs
index f500d5f9..7a8d0f2c 100644
--- a/Omni/Task/Web/Style.hs
+++ b/Omni/Task/Web/Style.hs
@@ -147,65 +147,26 @@ layoutStyles = do
navigationStyles :: Css
navigationStyles = do
- ".navbar" ? do
- fontFamily WebStyle.fontMono [monospace]
- backgroundColor WebStyle.cBg
- padding (px 8) (px 16) (px 8) (px 16)
- borderBottom (px 1) solid WebStyle.cBorder
- display flex
- alignItems center
- justifyContent spaceBetween
- flexWrap Flexbox.wrap
- Stylesheet.key "gap" ("8px" :: Text)
- position sticky
- top nil
- zIndex 100
- Stylesheet.key "backdrop-filter" ("blur(12px)" :: Text)
- Stylesheet.key "-webkit-backdrop-filter" ("blur(12px)" :: Text)
- ".navbar-brand" ? do
- fontSize (px 14)
- fontWeight bold
- color WebStyle.cAccent
- textDecoration none
- Stylesheet.key "letter-spacing" ("0.05em" :: Text)
- ".navbar-brand" # hover ? do
- textDecoration none
- opacity 0.8
- ".navbar-toggle-checkbox" ? display none
- ".navbar-hamburger" ? do
- display none
- flexDirection column
- justifyContent center
- alignItems center
- width (px 32)
- height (px 32)
- cursor pointer
- Stylesheet.key "gap" ("4px" :: Text)
- ".hamburger-line" ? do
- display block
- width (px 20)
- height (px 2)
- backgroundColor WebStyle.cFgMuted
- borderRadius (px 1) (px 1) (px 1) (px 1)
- transition "all" (ms 200) ease (sec 0)
- ".navbar-links" ? do
+ -- Sub-navigation bar (second bar, section-specific links)
+ ".subnav" ? do
display flex
Stylesheet.key "gap" ("2px" :: Text)
- flexWrap Flexbox.wrap
- alignItems center
- ".navbar-link" ? do
- display inlineBlock
+ padding (px 4) (px 16) (px 4) (px 16)
+ borderBottom (px 1) solid WebStyle.cBorderSubtle
+ fontFamily WebStyle.fontMono [monospace]
+ fontSize (px 12)
+ ".subnav-link" ? do
+ fontSize (px 12)
+ color WebStyle.cFgFaint
padding (px 4) (px 10) (px 4) (px 10)
- color WebStyle.cFgMuted
- textDecoration none
borderRadius WebStyle.radiusSm WebStyle.radiusSm WebStyle.radiusSm WebStyle.radiusSm
- fontSize (px 12)
- fontWeight (weight 500)
+ textDecoration none
transition "all" (ms 150) ease (sec 0)
- ".navbar-link" # hover ? do
- backgroundColor WebStyle.cBgHover
+ ".subnav-link" # hover ? do
color WebStyle.cFg
+ backgroundColor WebStyle.cBgHover
textDecoration none
+ -- Dropdown styles (used by sort dropdown)
".navbar-dropdown" ? do
position relative
display inlineBlock
@@ -1901,40 +1862,11 @@ responsiveStyles = do
query Media.screen [Media.maxWidth (px 600)] <| do
body ? fontSize (px 15)
".container" ? padding (px 8) (px 10) (px 8) (px 10)
- ".navbar" ? do
- padding (px 8) (px 10) (px 8) (px 10)
+ ".subnav" ? do
+ padding (px 4) (px 8) (px 4) (px 8)
flexWrap Flexbox.wrap
- ".navbar-hamburger" ? do
- display flex
- Stylesheet.key "order" ("2" :: Text)
- ".navbar-links" ? do
- display none
- width (pct 100)
- Stylesheet.key "order" ("3" :: Text)
- flexDirection column
- alignItems flexStart
- paddingTop (px 8)
- Stylesheet.key "gap" ("0" :: Text)
- ".navbar-toggle-checkbox" # checked |+ ".navbar-hamburger" |+ ".navbar-links" ? do
- display flex
- ".navbar-link" ? do
- padding (px 10) (px 8) (px 10) (px 8)
- fontSize (px 14)
- width (pct 100)
- ".navbar-dropdown" ? do
- width (pct 100)
- ".navbar-dropdown-btn" ? do
- padding (px 10) (px 8) (px 10) (px 8)
- fontSize (px 14)
- width (pct 100)
- textAlign (alignSide sideLeft)
- ".navbar-dropdown-content" ? do
- position static
- Stylesheet.key "box-shadow" ("none" :: Text)
- paddingLeft (px 12)
- backgroundColor transparent
- ".navbar-dropdown-item" ? do
- padding (px 8) (px 10) (px 8) (px 10)
+ ".subnav-link" ? do
+ padding (px 6) (px 8) (px 6) (px 8)
fontSize (px 13)
".nav-content" ? do
flexDirection column