Refactor nav menu

This commit is contained in:
Andy Smith
2025-11-10 14:20:56 -06:00
parent b7011469de
commit 9c20cc034b
6 changed files with 93 additions and 88 deletions
+16 -14
View File
@@ -1,4 +1,7 @@
@layer components {
/* Trigger
/* ------------------------------------------------------------------------ */
.nav__trigger {
--input-background: var(--color-canvas);
--input-border-color: transparent;
@@ -46,22 +49,34 @@
}
}
/* Dialog
/* ------------------------------------------------------------------------ */
.nav__menu.popup {
--panel-border-color: var(--color-selected-dark);
--panel-border-radius: 1.4em;
--panel-padding: var(--block-space) var(--block-space) 0 var(--block-space);
--panel-size: 45ch;
--popup-display: grid;
align-items: stretch;
box-shadow: 0 0 0 1px oklch(var(--lch-blue-medium) / 5%),
0 0.2em 0.2em oklch(var(--lch-blue-medium) / 5%),
0 0.4em 0.4em oklch(var(--lch-blue-medium) / 5%),
0 0.8em 0.8em oklch(var(--lch-blue-medium) / 5%);
flex-direction: column;
display: grid;
grid-template-rows: auto 1fr auto;
gap: 2px;
overflow: hidden;
scrollbar-gutter: stable both-edges;
}
.nav__scroll-container {
margin-inline: -1ch;
overflow: auto;
padding-inline: 1ch; /* room for scrollbar */
}
.nav__close {
@media (any-hover: hover) {
display: none;
@@ -133,27 +148,14 @@
}
}
/* Safari doesn't position the sticky footer properly during the
* transition, so we need to delay the footer entrance. */
.nav__footer {
animation: safari-sticky-footer-hack 0s;
animation-delay: var(--dialog-duration);
animation-fill-mode: both;
background-color: var(--color-canvas);
border-block-start: 1px solid var(--color-ink-lighter);
font-size: var(--text-small);
inset: auto 0 0;
inset-inline: var(--block-space);
line-height: 1.6;
margin-block-start: var(--block-space-half);
padding: 1.5ch;
position: sticky;
text-align: center;
z-index: 1;
}
@keyframes safari-sticky-footer-hack {
0% { position: absolute; }
100% { position: sticky; }
}
}
+3 -2
View File
@@ -6,6 +6,7 @@
--panel-size: auto;
--popup-icon-size: 24px;
--popup-item-padding-inline: 0.5rem;
--popup-display: flex;
inset: 0 auto auto 50%;
min-inline-size: min(25ch, calc(100dvw - var(--block-space-double)));
@@ -16,7 +17,7 @@
z-index: var(--z-popup);
&[open] {
display: flex;
display: var(--popup-display);
}
&.orient-left {
@@ -52,11 +53,11 @@
background: var(--color-canvas);
font-size: var(--text-small);
font-weight: bold;
inset-block-start: 0;
list-style: none;
padding: var(--block-space-half) var(--inline-space-half);
position: sticky;
text-transform: uppercase;
top: calc(-1 * var(--block-space));
z-index: 1;
&:is(summary) {
+1 -1
View File
@@ -14,7 +14,7 @@
navigable_list_focus_on_selection_value: false,
navigable_list_actionable_items_value: true } do %>
<%= turbo_frame_tag "my_menu", src: my_menu_path, loading: :lazy, target: "_top" do %>
<%= render "my/menus/navigation" %>
<%= render "my/menus/jump" %>
<% end %>
<% end %>
</nav>
+8
View File
@@ -0,0 +1,8 @@
<div class="flex gap">
<%= jump_field_tag %>
<button class="nav__close btn borderless txt-small" data-action="dialog#close">
<%= icon_tag "close" %>
<span class="for-screen-reader">Close menu</span>
</button>
</div>
-17
View File
@@ -1,17 +0,0 @@
<div class="flex gap">
<%= jump_field_tag %>
<button class="nav__close btn borderless txt-small" data-action="dialog#close">
<%= icon_tag "close" %>
<span class="for-screen-reader">Close menu</span>
</button>
</div>
<div class="nav__hotkeys margin-block-end-half" role="list">
<%= filter_hotkey_link "Home", root_path, 1, "home" %>
<%= filter_hotkey_link "Assigned to me", cards_path(assignee_ids: [Current.user.id]), 2, "clipboard" %>
<%= filter_hotkey_link "Added by me", cards_path(creator_ids: [Current.user.id]), 3, "person-add" %>
<%= filter_hotkey_link "Notifications", notifications_path, 4, "bell" %>
<%= filter_hotkey_link "My Profile", user_path(Current.user), 5, "person" %>
<%= filter_hotkey_link "Settings", account_settings_path, 6, "settings" %>
</div>
+65 -54
View File
@@ -1,68 +1,79 @@
<%= turbo_frame_tag "my_menu", target: "_top" do %>
<%= render "my/menus/navigation" %>
<%= render "my/menus/jump" %>
<%= collapsible_nav_section "Saved filters", id: "my-filters" do %>
<%= form_with url: cards_path, method: :get, data: { controller: "form" } do |form| %>
<li class="popup__item overflow-ellipsis" data-navigable-list-target="item" data-filter-target="item" id="filter-custom-create">
<%= icon_tag "bookmark", class: "popup__icon" %>
<%= link_to cards_path(expand_all: true), class: "popup__btn btn" do %>
<span>Add a filter</span>
<div class="nav__scroll-container">
<div class="nav__hotkeys margin-block-end-half" role="list">
<%= filter_hotkey_link "Home", root_path, 1, "home" %>
<%= filter_hotkey_link "Assigned to me", cards_path(assignee_ids: [Current.user.id]), 2, "clipboard" %>
<%= filter_hotkey_link "Added by me", cards_path(creator_ids: [Current.user.id]), 3, "person-add" %>
<%= filter_hotkey_link "Notifications", notifications_path, 4, "bell" %>
<%= filter_hotkey_link "My Profile", user_path(Current.user), 5, "person" %>
<%= filter_hotkey_link "Settings", account_settings_path, 6, "settings" %>
</div>
<%= collapsible_nav_section "Saved filters", id: "my-filters" do %>
<%= form_with url: cards_path, method: :get, data: { controller: "form" } do |form| %>
<li class="popup__item overflow-ellipsis" data-navigable-list-target="item" data-filter-target="item" id="filter-custom-create">
<%= icon_tag "bookmark", class: "popup__icon" %>
<%= link_to cards_path(expand_all: true), class: "popup__btn btn" do %>
<span>Add a filter</span>
<% end %>
</li>
<% @filters.each do |filter| %>
<%= my_menu_filter_item(filter) %>
<% end %>
<% end %>
<% end %>
<%= collapsible_nav_section "Boards" do %>
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
<%= icon_tag "add", class: "popup__icon" %>
<%= link_to new_board_path, class: "popup__btn btn" do %>
<span class="overflow-ellipsis">Add a board</span>
<% end %>
</li>
<% @filters.each do |filter| %>
<%= my_menu_filter_item(filter) %>
<% @boards.each do |board| %>
<%= my_menu_board_item(board) %>
<% end %>
<% end %>
<% end %>
<%= collapsible_nav_section "Boards" do %>
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
<%= icon_tag "add", class: "popup__icon" %>
<%= link_to new_board_path, class: "popup__btn btn" do %>
<span class="overflow-ellipsis">Add a board</span>
<% end %>
</li>
<% @boards.each do |board| %>
<%= my_menu_board_item(board) %>
<% end %>
<% end %>
<%= collapsible_nav_section "Tags" do %>
<% @tags.each do |tag| %>
<%= my_menu_tag_item(tag) %>
<% end %>
<% end %>
<%= collapsible_nav_section "People" do %>
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
<%= icon_tag "add", class: "popup__icon" %>
<%= link_to account_join_code_path, class: "popup__btn btn" do %>
<span class="overflow-ellipsis">Invite people</span>
<% end %>
</li>
<% @users.each do |user| %>
<%= my_menu_user_item(user) %>
<% end %>
<% end %>
<%= collapsible_nav_section "Jump to…" do %>
<%= filter_place_menu_item account_settings_path, "Account Settings", "settings" %>
<%= filter_place_menu_item user_path(Current.user), "My Profile", "person" %>
<%= filter_place_menu_item notifications_path, "Notifications", "bell" %>
<%= filter_place_menu_item notifications_settings_path, "Notification Settings", "settings" %>
<%= tag.li class: "popup__item", data: { filter_target: "item", navigable_list_target: "item" } do %>
<%= icon_tag "logout", class: "popup__icon" %>
<%= button_to session_url(script_name: nil), method: :delete, class: "popup__btn btn", data: { turbo: false } do %>
<span>Sign out</span>
<%= collapsible_nav_section "Tags" do %>
<% @tags.each do |tag| %>
<%= my_menu_tag_item(tag) %>
<% end %>
<% end %>
<% end %>
<%= turbo_frame_tag Current.identity, :account_menu, src: session_menu_url(script_name: nil, menu_section: true, without: ApplicationRecord.current_tenant) %>
<%= collapsible_nav_section "People" do %>
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
<%= icon_tag "add", class: "popup__icon" %>
<%= link_to account_join_code_path, class: "popup__btn btn" do %>
<span class="overflow-ellipsis">Invite people</span>
<% end %>
</li>
<% @users.each do |user| %>
<%= my_menu_user_item(user) %>
<% end %>
<% end %>
<%= collapsible_nav_section "Jump to…" do %>
<%= filter_place_menu_item account_settings_path, "Account Settings", "settings" %>
<%= filter_place_menu_item user_path(Current.user), "My Profile", "person" %>
<%= filter_place_menu_item notifications_path, "Notifications", "bell" %>
<%= filter_place_menu_item notifications_settings_path, "Notification Settings", "settings" %>
<%= tag.li class: "popup__item", data: { filter_target: "item", navigable_list_target: "item" } do %>
<%= icon_tag "logout", class: "popup__icon" %>
<%= button_to session_url(script_name: nil), method: :delete, class: "popup__btn btn", data: { turbo: false } do %>
<span>Sign out</span>
<% end %>
<% end %>
<% end %>
<%= turbo_frame_tag Current.identity, :account_menu, src: session_menu_url(script_name: nil, menu_section: true, without: ApplicationRecord.current_tenant) %>
</div>
<footer class="nav__footer">
Fizzy&trade; is designed, built, and backed by <strong class="txt-nowrap"><%= icon_tag "37signals", class: "v-align-middle" %> <a href="https://37signals.com" target="_blank" class="txt-ink">37signals&trade;</a></strong>