Skip to content

Commit a94c32e

Browse files
Add header_actions helper and split header partial (#85)
1 parent 339ccd4 commit a94c32e

18 files changed

Lines changed: 263 additions & 53 deletions

File tree

.claude/skills/layered-ui-rails/SKILL.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,28 @@ Populate layout regions with `content_for` (always above the render call):
7777
<% content_for :l_ui_logo_dark do %>
7878
<%= image_tag "my_logo_dark.svg", alt: "", class: "l-ui-header__logo l-ui-header__logo--dark" %>
7979
<% end %>
80+
81+
<%# Prepend or append items to the header actions group %>
82+
<% content_for :l_ui_header_actions_start do %>
83+
<%= link_to "Docs", docs_path, class: "l-ui-button l-ui-button--ghost l-ui-button--small" %>
84+
<% end %>
85+
<% content_for :l_ui_header_actions_end do %>
86+
<%= link_to "Help", help_path, class: "l-ui-button l-ui-button--ghost l-ui-button--small" %>
87+
<% end %>
88+
89+
<%# Or replace the default actions group entirely and compose with helpers %>
90+
<% content_for :l_ui_header_actions do %>
91+
<%= link_to "Docs", docs_path, class: "l-ui-button l-ui-button--ghost l-ui-button--small" %>
92+
<%= l_ui_theme_toggle %>
93+
<%= l_ui_authentication %>
94+
<%= l_ui_navigation_toggle %>
95+
<% end %>
96+
97+
<%# Inline header links (alongside the logo) %>
98+
<% content_for :l_ui_header_links do %>
99+
<%= link_to "Pricing", pricing_path %>
100+
<%= link_to "About", about_path %>
101+
<% end %>
80102
```
81103

82104
Body class modifiers:
@@ -116,6 +138,9 @@ Quick reference:
116138
| `l_ui_normalise_field(record, config)` | Normalise a raw field config hash into canonical form |
117139
| `l_ui_user_signed_in?` | Check if user is authenticated |
118140
| `l_ui_current_user` | Current user object |
141+
| `l_ui_theme_toggle` | Default header theme toggle button |
142+
| `l_ui_authentication` | Default header login/register buttons (Devise) |
143+
| `l_ui_navigation_toggle` | Default header sidebar toggle button |
119144

120145
## CSS classes
121146

.claude/skills/layered-ui-rails/references/HELPERS.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,25 @@ The button does not need to be inside the helper's wrapper, and no `data-control
287287

288288
Calling `dialog.showModal()` directly is not supported - it bypasses the `l-ui--modal` controller and skips scroll lock, focus restoration, open-count tracking, and the screen-reader announcement.
289289

290+
## Header
291+
292+
```ruby
293+
l_ui_theme_toggle # Renders the dark/light theme toggle button
294+
l_ui_authentication # Renders Devise login/register buttons (no-op when signed in or when Devise routes are absent)
295+
l_ui_navigation_toggle # Renders the hamburger that toggles the sidebar (only when navigation items exist or a user is signed in)
296+
```
297+
298+
Use these when overriding the header actions group with `:l_ui_header_actions` to compose your own bar from the default building blocks. The header also exposes `:l_ui_header_actions_start` and `:l_ui_header_actions_end` yields to prepend or append items without replacing the defaults, and `:l_ui_header_links` for inline links beside the logo.
299+
300+
```erb
301+
<% content_for :l_ui_header_actions do %>
302+
<%= link_to "Docs", docs_path, class: "l-ui-button l-ui-button--ghost l-ui-button--small" %>
303+
<%= l_ui_theme_toggle %>
304+
<%= l_ui_authentication %>
305+
<%= l_ui_navigation_toggle %>
306+
<% end %>
307+
```
308+
290309
## Authentication
291310

292311
```ruby
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Layered
2+
module Ui
3+
module HeaderHelper
4+
def l_ui_theme_toggle
5+
render "layouts/layered_ui/theme_toggle"
6+
end
7+
8+
def l_ui_authentication
9+
render "layouts/layered_ui/authentication"
10+
end
11+
12+
def l_ui_navigation_toggle
13+
render "layouts/layered_ui/navigation_toggle"
14+
end
15+
end
16+
end
17+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<% unless l_ui_user_signed_in? %>
2+
<% if respond_to?(:new_user_registration_path) %>
3+
<%= link_to "Register", main_app.new_user_registration_path, class: "l-ui-button l-ui-button--outline l-ui-button--small" %>
4+
<% end %>
5+
6+
<% if respond_to?(:new_user_session_path) %>
7+
<%= link_to "Login", main_app.new_user_session_path, class: "l-ui-button l-ui-button--primary l-ui-button--small" %>
8+
<% end %>
9+
<% end %>

app/views/layouts/layered_ui/_header.html.erb

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,42 +14,14 @@
1414
<% end %>
1515

1616
<nav class="l-ui-header__navigation" aria-label="Header navigation">
17-
<button
18-
type="button"
19-
data-controller="l-ui--theme"
20-
data-action="click->l-ui--theme#toggle"
21-
data-l-ui--theme-target="button"
22-
class="l-ui-button l-ui-button--icon l-ui-theme-toggle"
23-
aria-label="Toggle dark mode"
24-
aria-pressed="false"
25-
>
26-
<%= image_tag "layered_ui/icon_moon.svg", alt: "", class: "l-ui-icon l-ui-icon--sm l-ui-theme-toggle__icon l-ui-theme-toggle__icon--light", aria: { hidden: true } %>
27-
<%= image_tag "layered_ui/icon_sun.svg", alt: "", class: "l-ui-icon l-ui-icon--sm l-ui-theme-toggle__icon l-ui-theme-toggle__icon--dark", aria: { hidden: true } %>
28-
</button>
29-
30-
<% unless l_ui_user_signed_in? %>
31-
<% if respond_to?(:new_user_registration_path) %>
32-
<%= link_to "Register", main_app.new_user_registration_path, class: "l-ui-button l-ui-button--outline l-ui-button--small" %>
33-
<% end %>
34-
35-
<% if respond_to?(:new_user_session_path) %>
36-
<%= link_to "Login", main_app.new_user_session_path, class: "l-ui-button l-ui-button--primary l-ui-button--small" %>
37-
<% end %>
38-
<% end %>
39-
40-
<% if yield(:l_ui_navigation_items).present? || l_ui_user_signed_in? %>
41-
<button
42-
type="button"
43-
class="l-ui-button l-ui-button--navigation-toggle"
44-
data-action="click->l-ui--navigation#toggle"
45-
data-l-ui--navigation-target="toggleButton"
46-
aria-label="Toggle navigation menu"
47-
aria-expanded="false"
48-
aria-controls="l-ui-navigation"
49-
>
50-
<%= image_tag "layered_ui/icon_hamburger.svg", alt: "", class: "l-ui-icon l-ui-icon--md", data: { "l-ui--navigation-target": "openIcon" }, aria: { hidden: true } %>
51-
<%= image_tag "layered_ui/icon_close.svg", alt: "", class: "l-ui-icon l-ui-icon--md", style: "display: none;", data: { "l-ui--navigation-target": "closeIcon" }, aria: { hidden: true } %>
52-
</button>
17+
<% if content_for?(:l_ui_header_actions) %>
18+
<%= yield(:l_ui_header_actions) %>
19+
<% else %>
20+
<%= yield(:l_ui_header_actions_start) %>
21+
<%= l_ui_theme_toggle %>
22+
<%= l_ui_authentication %>
23+
<%= l_ui_navigation_toggle %>
24+
<%= yield(:l_ui_header_actions_end) %>
5325
<% end %>
5426
</nav>
5527
</div>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<% if yield(:l_ui_navigation_items).present? || l_ui_user_signed_in? %>
2+
<button
3+
type="button"
4+
class="l-ui-button l-ui-button--navigation-toggle"
5+
data-action="click->l-ui--navigation#toggle"
6+
data-l-ui--navigation-target="toggleButton"
7+
aria-label="Toggle navigation menu"
8+
aria-expanded="false"
9+
aria-controls="l-ui-navigation"
10+
>
11+
<%= image_tag "layered_ui/icon_hamburger.svg", alt: "", class: "l-ui-icon l-ui-icon--md", data: { "l-ui--navigation-target": "openIcon" }, aria: { hidden: true } %>
12+
<%= image_tag "layered_ui/icon_close.svg", alt: "", class: "l-ui-icon l-ui-icon--md", style: "display: none;", data: { "l-ui--navigation-target": "closeIcon" }, aria: { hidden: true } %>
13+
</button>
14+
<% end %>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<button
2+
type="button"
3+
data-controller="l-ui--theme"
4+
data-action="click->l-ui--theme#toggle"
5+
data-l-ui--theme-target="button"
6+
class="l-ui-button l-ui-button--icon l-ui-theme-toggle"
7+
aria-label="Toggle dark mode"
8+
aria-pressed="false"
9+
>
10+
<%= image_tag "layered_ui/icon_moon.svg", alt: "", class: "l-ui-icon l-ui-icon--sm l-ui-theme-toggle__icon l-ui-theme-toggle__icon--light", aria: { hidden: true } %>
11+
<%= image_tag "layered_ui/icon_sun.svg", alt: "", class: "l-ui-icon l-ui-icon--sm l-ui-theme-toggle__icon l-ui-theme-toggle__icon--dark", aria: { hidden: true } %>
12+
</button>

lib/layered/ui/engine.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class Engine < ::Rails::Engine
3333
helper Layered::Ui::TableHelper
3434
helper Layered::Ui::TitleBarHelper
3535
helper Layered::Ui::FormHelper
36+
helper Layered::Ui::HeaderHelper
3637
helper Layered::Ui::ModalHelper
3738
helper Layered::Ui::RansackHelper
3839
end

test/dummy/app/controllers/pages_controller.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ def layout_metadata
4949
def layout_navigation
5050
end
5151

52+
def layout_header
53+
end
54+
5255
def layout_panel
5356
end
5457

@@ -132,6 +135,12 @@ def test_logo_override
132135
def test_head_injection
133136
end
134137

138+
def test_header_actions
139+
end
140+
141+
def test_header_actions_replaced
142+
end
143+
135144
private
136145

137146
def load_users

test/dummy/app/views/layouts/application.html.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<%= l_ui_navigation_item "Head", layout_head_path %>
4141
<%= l_ui_navigation_item "Metadata", layout_metadata_path %>
4242
<%= l_ui_navigation_item "Navigation", layout_navigation_path %>
43+
<%= l_ui_navigation_item "Header", layout_header_path %>
4344
<%= l_ui_navigation_item "Breadcrumbs", layout_breadcrumbs_path %>
4445
<%= l_ui_navigation_item "Panel", layout_panel_path %>
4546
<% end %>

0 commit comments

Comments
 (0)