[UI] Redesign the navigation menu (#840)

This commit is contained in:
Cinder 2025-01-20 07:14:42 -08:00 committed by GitHub
parent 66bc394f3a
commit 0eb02c6728
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 446 additions and 209 deletions

View File

@ -14,6 +14,24 @@ module ApplicationHelper
render "diff_list", diff: diff
end
def decorated_nav_link_to(text, icon, url, **options)
klass = options.delete(:class)
if nav_link_match(params[:controller], url)
klass = "#{klass} current"
end
id = "nav-#{text.downcase.gsub(/[^a-z ]/, '').parameterize}"
tag.li(id: id, class: klass) do
link_to(url, id: "#{id}-link", **options) do
concat tag.i(class: icon)
concat " "
concat tag.span(text)
end
end
end
def nav_link_to(text, url, **options)
klass = options.delete(:class)

View File

@ -0,0 +1,17 @@
const Navigation = {};
Navigation.init = function () {
const wrapper = $("body");
$("#nav-toggle").on("click", (event) => {
event.preventDefault();
wrapper.toggleClass("nav-toggled");
});
};
$(() => {
if (!$("nav.navigation").length) return;
Navigation.init();
});
export default Navigation;

View File

@ -1,8 +0,0 @@
$(function () {
$("#maintoggle").on("click.danbooru", function (e) {
e.preventDefault();
$("#nav").toggle();
$("#maintoggle-on").toggle();
$("#maintoggle-off").toggle();
});
});

View File

@ -24,9 +24,9 @@
@import "common/jquery_ui_custom.scss";
@import "common/link_decorator.scss";
@import "common/main_layout.scss";
@import "common/navigation.scss";
@import "common/news.scss";
@import "common/notices.scss";
@import "common/page_header.scss";
@import "common/paginator.scss";
@import "common/scores";
@import "common/simple_form.scss";

View File

@ -0,0 +1,328 @@
nav.navigation {
display: grid;
grid-template-areas: "logo logo controls";
grid-template-columns: min-content auto;
grid-template-rows: min-content auto min-content min-content;
width: 100%; // otherwise narrow when fixed
z-index: 10; // otherwise post labels layered above
pointer-events: none; // allow clicking through offset
& > menu { pointer-events: auto; }
/* Top bar, always visible */
.nav-logo {
grid-area: logo;
a.nav-logo-link {
display: flex;
height: 3rem;
width: 3rem;
margin: 0.5rem;
background-image: url("main-logo.png");
background-repeat: no-repeat;
background-size: contain;
background-position-y: center;
}
}
.nav-controls {
grid-area: controls;
display: flex;
flex-flow: row-reverse;
align-items: center;
gap: 0.5em;
font-size: 1.15rem;
padding-right: 0.5em;
& > a {
display: flex;
gap: 0.25em;
padding: 0.25rem 0.5rem;
background: themed("color-foreground");
border-radius: 6px;
& > i {
font-size: 1.5rem;
color: themed("color-link-active");
}
}
}
/* Prevent toggled menus from being too wide */
.nav-offset {
grid-area: offset;
pointer-events: none;
display: none; // flex
}
/* Toggled menus, hidden by default */
.nav-primary {
grid-area: primary;
display: none; // flex
flex-flow: column;
background-color: themed("color-section");
font-size: 1.5em;
li {
padding: 0;
a {
display: block;
border-bottom: 1px solid themed("color-foreground");
padding: 0.5em;
i {
width: 1.5rem;
color: themed("color-link-active");
text-align: center;
}
}
&.current a { background-color: themed("color-foreground"); }
}
}
.nav-secondary {
grid-area: secondary;
display: none; // flex
flex-flow: column;
background-color: themed("color-foreground");
font-size: 1.35em;
li {
padding: 0;
a {
display: block;
border-bottom: 1px solid themed("color-section");
padding: 0.5em;
}
&.divider {
border-bottom: 1px solid themed("color-section");
height: 0.25em;
}
form input[type="text"] { width: 100%; }
}
}
.nav-tools {
grid-area: tools;
display: none; // grid
grid-template-columns: 1fr 1fr;
grid-template-rows: min-content;
padding: 1rem;
gap: 1rem;
background-color: themed("color-section");
border-top: 1px solid themed("color-foreground");
li {
padding: 0;
&.nav-tools-login { grid-column: 1 / -1; }
& > a {
display: block;
background: themed("color-section-lighten-5");
border-radius: 6px;
font-size: 125%;
padding: 0.5rem 1rem;
text-align: center;
i { color: themed("color-link-active"); }
}
}
&.anonymous li.nav-tools-themes {
grid-column: 1 / -1;
}
}
.nav-help {
grid-area: help;
display: none; // grid
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: min-content;
padding: 1rem;
gap: 1rem;
background: themed("color-section");
li {
padding: 0;
&.nav-help-discord { grid-column: 1 / -1; }
& > a {
display: block;
background: themed("color-section-darken-5");
border-radius: 6px;
font-size: 125%;
padding: 0.5rem 1rem;
text-align: center;
i { color: themed("color-link-active"); }
}
}
}
}
// Mobile toggle
body.nav-toggled {
padding-top: 4rem;
nav.navigation {
grid-template-areas:
"logo logo controls"
"offset primary secondary "
"offset tools tools "
"offset help help ";
grid-template-columns: auto minmax(auto, 180px) minmax(auto, 180px);
position: fixed;
top: 0;
height: 100vh;
max-height: 800px;
max-width: 100vw; // prevent bug when page overflows viewport
// Allow scrolling when the menu is too long
overflow-y: scroll;
.nav-logo, .nav-controls {
background-color: themed("color-background");
}
.nav-primary, .nav-secondary, .nav-offset {
display: flex;
}
.nav-tools, .nav-help {
display: grid;
}
}
}
// Desktop
nav.navigation, body.nav-toggled nav.navigation {
@include window-larger-than(800px) {
grid-template-areas:
"logo primary help tools "
"logo secondary secondary secondary"
;
grid-template-columns: min-content min-content 1fr min-content;
grid-template-rows: 1fr 1fr;
padding: 0 1em 1em;
box-sizing: border-box;
height: unset;
.nav-logo {
a.nav-logo-link { margin: 0.5em 0.25em 0 0; }
}
.nav-offset, .nav-controls { display: none; }
.nav-primary {
display: flex;
flex-flow: row;
background: unset;
font-size: 1.05em;
padding: 0 0.25em;
li {
display: flex;
a {
align-content: center;
border-bottom: 0;
padding: 0 0.75em;
i { display: none; }
}
}
}
.nav-secondary {
display: flex;
flex-flow: row;
align-items: center;
padding: 0 0.25em;
font-size: 1.05em;
border-radius: 6px;
// Silly fix for too many links
overflow: hidden;
li {
a {
border-bottom: 0;
padding: 0 0.75em;
white-space: nowrap;
}
&.divider {
display: flex;
align-items: center;
&::after { content: "|"; }
}
}
}
.nav-tools, .nav-help {
display: flex;
padding: 0;
background: unset;
border: none;
gap: 0;
li {
display: flex;
a {
align-content: center;
background: unset;
font-size: 1.05em;
padding: 0 0.75em;
text-align: unset;
white-space: nowrap;
border-radius: 0;
}
}
}
.nav-tools {
li a {
span { display: none; }
i { color: themed("color-link"); }
&:hover i { color: themed("color-link-hover"); }
}
}
.nav-help {
li.current a {
background-color: themed("color-foreground");
i { display: none; }
}
}
}
}

View File

@ -1,92 +0,0 @@
#maintoggle {
display: none;
}
#nav {
display: grid;
grid-template-columns: 3.75em 1fr;
grid-template-areas: "logo main" "logo secondary";
.logo {
grid-area: logo;
margin-top: 6px;
background-image: url("main-logo.png");
background-repeat: no-repeat;
background-size: contain;
background-position-y: center;
}
.mobile-logo {
display: none;
}
.main {
grid-area: main;
}
.secondary {
grid-area: secondary;
}
}
header#top {
font-size: 1.05em;
margin: 0 $base-padding 0.8rem;
color: themed("color-text");
background-color: themed("color-background");
background-image: themed("image-background");
#subnav-height-placeholder {
visibility: hidden;
}
menu {
margin-top: -2px;
background-color: themed("color-foreground");
border-radius: $border-radius-full;
padding: 6px;
form {
display: inline-block;
input {
width: 9.5em;
vertical-align: baseline;
font-size: revert;
padding-top: 0;
padding-bottom: 0;
}
}
li {
margin: 0;
padding: 0;
white-space: nowrap;
}
li a {
padding: 6px 10px;
}
}
menu.main {
margin-top: 0;
background-color: themed("color-background");
li.current a {
background-color: themed("color-foreground");
font-weight: bold;
}
li#nav-sign-in a {
font-weight: bold;
color: $page-header-sign-in-link-color;
}
li.forum-updated a {
font-style: italic;
}
}
}

View File

@ -130,12 +130,6 @@
}
}
#maintoggle {
display: block;
font-weight: bold;
font-size: 2em;
}
/* Make the quick search box in the navbar full width. */
header#top menu form input {
width: auto;
@ -216,47 +210,6 @@
}
}
#nav {
font-size: 2em;
line-height: 2em;
display: none;
}
header#top {
input {
font-size: 18pt;
}
menu.main {
padding: 5px 10px;
.mobile-logo {
display: inline-block;
width: 1.5em;
box-sizing: border-box;
a {
display: inline-block;
padding: 6px 10px;
background-image: url("main-logo.png");
background-repeat: no-repeat;
background-size: contain;
// Gives the link height
&::after {
content: "Placeholder";
visibility: hidden;
}
}
}
}
menu.secondary.empty {
display: none;
}
}
header {
text-align: center;
line-height: 2em;

View File

@ -8,7 +8,7 @@
<%= subnav_link_to "Recent changes", artist_versions_path %>
<%= subnav_link_to "URLs", artist_urls_path %>
<% if @artist && !@artist.new_record? %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Posts (#{@artist.tag.try(:post_count).to_i})", posts_path(tags: @artist.name) %>
<%= subnav_link_to "Show", artist_path(@artist) %>
<% if @artist.editable_by?(CurrentUser.user) %>
@ -19,7 +19,7 @@
<%= subnav_link_to "Delete", artist_path(@artist), method: :delete, data: { confirm: "Are you sure you want to delete this artist? This cannot be undone." } %>
<% end %>
<% if @artist.is_dnp? %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "DNP", avoid_posting_path(@artist.avoid_posting) %>
<% end %>
<% else %>

View File

@ -18,6 +18,6 @@
<% else %>
<%= subnav_link_to "History", avoid_posting_versions_path %>
<% end %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Static", avoid_posting_static_path %>
<% end %>

View File

@ -3,7 +3,7 @@
<%= subnav_link_to "List", blips_path %>
<%= subnav_link_to "New", new_blip_path %>
<% unless @blip&.response_to.nil? %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Parent", blip_path(@blip.response_to) %>
<% end %>
<% end %>

View File

@ -3,9 +3,9 @@
<%= subnav_link_to "All", all_dmails_path(set_default_folder: true) %>
<%= subnav_link_to "Received", received_dmails_path(set_default_folder: true) %>
<%= subnav_link_to "Sent", sent_dmails_path(set_default_folder: true) %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "New", new_dmail_path %>
<%= subnav_link_to "Mark all as read", mark_all_as_read_dmails_path, method: :put %></li>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Help", help_page_path(id: "dmail") %>
<% end %>

View File

@ -13,7 +13,7 @@
<%= subnav_link_to "Search", search_forum_posts_path %>
<%= subnav_link_to "Help", help_page_path(id: "forum") %>
<% if CurrentUser.is_member? && @forum_topic && !@forum_topic.new_record? %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Reply", new_forum_post_path(forum_post: { topic_id: @forum_topic.id }) %>
<% if @forum_topic.user_subscription(CurrentUser.user) %>
<%= subnav_link_to "Unsubscribe", unsubscribe_forum_topic_path(@forum_topic), method: :post %>

View File

@ -15,7 +15,7 @@
<% if (related_array = @help.related_array).any? %>
<% help_pages = HelpPage.help_index %>
<li>|</li>
<li class="divider"></li>
<% related_array.each do |related| %>
<li><%= subnav_link_to HelpPage.pretty_related_title(related, help_pages), help_page_path(related) %></li>
<% end %>

View File

@ -1,23 +1,7 @@
<%= nav_link_to("", "/", class: "mobile-logo") %>
<% if CurrentUser.is_anonymous? %>
<%= nav_link_to("Sign in", new_session_path) %>
<% else %>
<%= nav_link_to("Account #{unread_dmails(CurrentUser.user)}", home_users_path) %>
<% end %>
<%= nav_link_to("Posts", posts_path) %>
<%= nav_link_to("Comments", comments_path(group_by: "post")) %>
<%= nav_link_to("Artists", artists_path) %>
<%= nav_link_to("Tags", tags_path) %>
<%= nav_link_to("Blips", blips_path) %>
<%= nav_link_to("Pools", gallery_pools_path) %>
<%= nav_link_to("Sets", post_sets_path) %>
<%= nav_link_to("Wiki", wiki_pages_path(title: "help:home")) %>
<%= nav_link_to("Forum", forum_topics_path, class: (CurrentUser.has_forum_been_updated? ? "forum-updated" : nil)) %>
<% if CurrentUser.is_moderator? %>
<%= nav_link_to("Dashboard", moderator_dashboard_path) %>
<% end %>
<% if !CurrentUser.is_anonymous? %>
<%= nav_link_to("Discord", discord_get_path) %>
<% end %>
<%= nav_link_to("Help", help_pages_path) %>
<%= nav_link_to("More »", site_map_path) %>
<%= decorated_nav_link_to("Posts", "fas fa-images", posts_path) %>
<%= decorated_nav_link_to("Pools", "fas fa-book", gallery_pools_path) %>
<%= decorated_nav_link_to("Sets", "fas fa-clone", post_sets_path) %>
<%= decorated_nav_link_to("Tags", "fas fa-tags", tags_path) %>
<%= decorated_nav_link_to("Blips", "fas fa-bullhorn", blips_path) %>
<%= decorated_nav_link_to("Comments", "fas fa-comment-alt", comments_path(group_by: "post")) %>
<%= decorated_nav_link_to("Forum", "fas fa-chalkboard", forum_topics_path, class: (CurrentUser.has_forum_been_updated? ? "forum-updated" : nil)) %>

View File

@ -0,0 +1,56 @@
<nav class="navigation">
<menu class="nav-logo">
<a href="/" class="nav-logo-link"></a>
</menu>
<menu class="nav-primary">
<%= render "layouts/main_links" %>
</menu>
<menu class="nav-offset"></menu>
<menu class="nav-secondary <%= "empty" unless content_for(:secondary_links) %>">
<% if content_for(:secondary_links) %>
<%= yield :secondary_links %>
<% else %>
<%= subnav_link_to "Height Placeholder", "" %>
<% end %>
</menu>
<menu class="nav-controls">
<a href="" id="nav-toggle">
<i class="fas fa-bars"></i>
</a>
<% if CurrentUser.is_anonymous? %>
<%= link_to(new_session_path, class: "nav-tools-login") do %>
<i class="fas fa-sign-in-alt"></i>
Sign in
<% end %>
<% else %>
<%= link_to(user_path(CurrentUser.user), class: "nav-tools-login") do %>
<i class="far fa-user-circle"></i>
Profile
<% end %>
<% end %>
</menu>
<menu class="nav-tools <%= CurrentUser.is_anonymous? ? "anonymous" : "" %>">
<%= decorated_nav_link_to("Themes", "fas fa-swatchbook", theme_path, class: "nav-tools-themes") %>
<% if CurrentUser.is_anonymous? %>
<%= decorated_nav_link_to("Sign in", "fas fa-sign-in-alt", new_session_path, class: "nav-tools-login") %>
<% else %>
<%= decorated_nav_link_to("Settings", "fas fa-cog", edit_user_path(CurrentUser.user), class: "nav-tools-settings") %>
<%= decorated_nav_link_to("Account #{unread_dmails(CurrentUser.user)}", "far fa-user-circle", user_path(CurrentUser.user), class: "nav-tools-login") %>
<% end %>
</menu>
<menu class="nav-help <%= CurrentUser.is_anonymous? ? "anonymous" : "" %>">
<% if !CurrentUser.is_anonymous? %>
<%= nav_link_to("Discord", discord_get_path, class: "nav-help-discord") %>
<% end %>
<%= nav_link_to("Wiki", wiki_pages_path(title: "help:home"), class: "nav-help-wiki") %>
<%= nav_link_to("Help", help_pages_path, class: "nav-help-help") %>
<%= nav_link_to("More", site_map_path, class: "nav-help-map") %>
</menu>
</nav>

View File

@ -6,26 +6,7 @@
<%= tag.body(**body_attributes(CurrentUser.user)) do %>
<%= render "layouts/theme_include" %>
<header id="top">
<div id="maintoggle">
<a href="#"><i id="maintoggle-on" class="fa-solid fa-bars"></i></a>
<a href="#"><i id="maintoggle-off" class="fa-solid fa-xmark" style="display: none;"></i></a>
</div>
<nav id="nav">
<a href="/" class="logo"></a>
<menu class="main">
<%= render "layouts/main_links" %>
</menu>
<menu class="secondary <%= "empty" unless content_for(:secondary_links) %>">
<% if content_for(:secondary_links) %>
<%= yield :secondary_links %>
<% else %>
<%= subnav_link_to "Height Placeholder", "" %>
<% end %>
</menu>
</nav>
</header>
<%= render "layouts/nav" %>
<div id="page">
<%= render "news_updates/notice", news_update: NewsUpdate.recent %>

View File

@ -5,7 +5,7 @@
<%= subnav_link_to "New", new_pool_path %>
<%= subnav_link_to "Help", help_page_path(id: "pools") %>
<% if @pool && !@pool.new_record? %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Show", pool_path(@pool) %>
<%= subnav_link_to "Posts", posts_path(tags: "pool:#{@pool.id}") %>
<% if CurrentUser.is_member? %>

View File

@ -7,7 +7,7 @@
<%= subnav_link_to "Invites", post_set_maintainers_path %>
<% end %>
<% if @post_set&.id %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Posts", posts_path(tags: "set:#{@post_set.shortname}") %>
<%= subnav_link_to "Maintainers", maintainers_post_set_path(@post_set) %>

View File

@ -12,7 +12,7 @@
<li><a href="#" id="blacklist-edit-link">Blacklist</a></li>
<%= subnav_link_to "Help", help_page_path(id: "posts") %>
<% if CurrentUser.can_approve_posts? %>
<li>|</li>
<li class="divider"></li>
<li><a href="#" id="janitor-toolbar-toggle">Approvals: Off</a></li>
<% end %>
<% end %>

View File

@ -9,7 +9,7 @@
<%= subnav_link_to "Cheatsheet", help_page_path(id: "cheatsheet") %>
<%= subnav_link_to "Help", help_page_path(id: "tags") %>
<% if @tag %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Posts (#{@tag.post_count})", posts_path(tags: @tag.name) %>
<%= subnav_link_to "Wiki Page", show_or_new_wiki_pages_path(title: @tag.name) %>
<%= subnav_link_to "Edit", edit_tag_path(@tag) %>

View File

@ -11,7 +11,7 @@
<%= subnav_link_to "Listing", user_feedbacks_path %>
<%= subnav_link_to "Search", search_user_feedbacks_path %>
<% if CurrentUser.is_moderator? %>
<li>|</li>
<li class="divider"></li>
<% if @user_feedback %>
<%= subnav_link_to "Ban", new_ban_path(ban: { user_id: @user_feedback.user_id }) %>
<% elsif params.dig(:search, :user_id) %>

View File

@ -8,7 +8,7 @@
<% end %>
<% if @user && !@user.new_record? && !CurrentUser.user.is_anonymous? %>
<li>|</li>
<li class="divider"></li>
<% if @user.id == CurrentUser.user.id %>
<%= subnav_link_to "Settings", edit_user_path(CurrentUser.user) %>
<%= subnav_link_to "Profile", user_path(CurrentUser.user) %>
@ -33,7 +33,7 @@
<% end %>
<% end %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Sign out", session_path, method: :delete %>
<% end %>
<% end %>

View File

@ -12,7 +12,7 @@
<%= subnav_link_to "Help", help_page_path(id: "wiki") %>
<% if @wiki_page %>
<li>|</li>
<li class="divider"></li>
<% if @wiki_page.tag.present? %>
<%= subnav_link_to "Posts (#{@wiki_page.tag.post_count})", posts_path(tags: @wiki_page.title) %>
@ -41,7 +41,7 @@
<% end %>
<% end %>
<% elsif @wiki_page_version %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Newest", wiki_page_path(@wiki_page_version.wiki_page_id) %>
@ -53,7 +53,7 @@
<%= subnav_link_to "Revert to", revert_wiki_page_path(@wiki_page_version.wiki_page_id, version_id: @wiki_page_version.id), method: :put, data: { confirm: "Are you sure you want to revert to this version?" } %>
<% end %>
<% elsif @thispage %>
<li>|</li>
<li class="divider"></li>
<%= subnav_link_to "Newest", wiki_page_path(@thispage.wiki_page_id) %>