posts: factor out post navbar into component.

* Factor out the post navbar into a component. The post navbar is the
  part of the post containing the current search, the list of pools, and
  the list of favgroups, along with next/prev navigation links.

* Change navbar markup: remove various unused CSS classes/IDs, change
  pools to use same markup as favgroups, replace nested <div>'s with
  flat <ul>/<li> list.

* Use CSS to truncate long searches/pool names/favgroup names if they're
  too wide for the screen (especially on mobile).
This commit is contained in:
evazion
2021-01-29 18:36:15 -06:00
parent 151a9b026e
commit 1e778dbbf6
16 changed files with 203 additions and 186 deletions

View File

@@ -0,0 +1,39 @@
class PostNavbarComponent < ApplicationComponent
extend Memoist
attr_reader :post, :current_user, :search, :pool_id, :favgroup_id
def initialize(post:, current_user:, search: nil, pool_id: nil, favgroup_id: nil)
@post = post
@current_user = current_user
@search = search.presence || "status:any"
@pool_id = pool_id&.to_i
@favgroup_id = favgroup_id&.to_i
end
def render?
has_search_navbar? || pools.any? || favgroups.any?
end
def pools
post.pools.undeleted.sort_by do |pool|
[pool.id == pool_id ? 0 : 1, pool.is_series? ? 0 : 1, pool.name]
end
end
def favgroups
current_user.favorite_groups.for_post(post.id).sort_by do |favgroup|
[favgroup.id == favgroup_id ? 0 : 1, favgroup.name]
end
end
def has_search_navbar?
!has_order_metatag? && pool_id.blank? && favgroup_id.blank?
end
def has_order_metatag?
PostQueryBuilder.new(search).has_metatag?(:order, :ordfav, :ordpool)
end
memoize :pools, :favgroups
end

View File

@@ -0,0 +1,69 @@
<ul class="notice post-notice post-notice-search">
<% if has_search_navbar? %>
<li class="search-navbar" data-selected="true">
<%= link_to " prev", show_seq_post_path(post, q: search, seq: "prev"), rel: "nofollow prev", class: "prev" %>
<span class="search-name">Search: <%= link_to search, posts_path(tags: search), rel: "nofollow" %></span>
<%= link_to "next ", show_seq_post_path(post, q: search, seq: "next"), rel: "nofollow next", class: "next" %>
</li>
<% end %>
<% pools.each do |pool| %>
<% selected = pool_id == pool.id %>
<% first_post_id = pool.post_ids.first %>
<% last_post_id = pool.post_ids.last %>
<% previous_post_id = pool.previous_post_id(post.id) %>
<% next_post_id = pool.next_post_id(post.id) %>
<%= tag.li class: "pool-navbar pool-category-#{pool.category}", "data-selected": selected do %>
<span class="first">
<%= link_to_unless first_post_id == post.id, "«", post_path(first_post_id, pool_id: pool.id), rel: "nofollow", title: "to page 1" %>
</span>
<span class="prev">
<%= link_to_if previous_post_id, " prev", post_path(previous_post_id.to_i, pool_id: pool.id), rel: ["nofollow", ("prev" if selected)], title: "to page #{pool.page_number(previous_post_id)}" %>
</span>
<span class="pool-name">
<%= link_to "Pool: #{pool.pretty_name}", pool, title: "page #{pool.page_number(post.id)}/#{pool.post_count}" %>
</span>
<span class="next">
<%= link_to_if next_post_id, "next ", post_path(next_post_id.to_i, pool_id: pool.id), rel: ["nofollow", ("next" if selected)], title: "to page #{pool.page_number(next_post_id)}" %>
</span>
<span class="last">
<%= link_to_unless last_post_id == post.id, "»", post_path(last_post_id, pool_id: pool.id), rel: "nofollow", title: "to page #{pool.post_count}" %>
</span>
<% end %>
<% end %>
<% favgroups.each do |favgroup| %>
<% selected = favgroup_id == favgroup.id %>
<% first_post_id = favgroup.post_ids.first %>
<% last_post_id = favgroup.post_ids.last %>
<% previous_post_id = favgroup.previous_post_id(post.id) %>
<% next_post_id = favgroup.next_post_id(post.id) %>
<%= tag.li class: "favgroup-navbar", "data-selected": selected do %>
<span class="first">
<%= link_to_unless first_post_id == post.id, "«", post_path(first_post_id, favgroup_id: favgroup.id), rel: "nofollow" %>
</span>
<span class="prev">
<%= link_to_if previous_post_id, " prev", post_path(previous_post_id.to_i, favgroup_id: favgroup.id), rel: ["nofollow", ("prev" if selected)] %>
</span>
<span class="favgroup-name">
<%= link_to "Favgroup: #{favgroup.pretty_name}", favgroup %>
</span>
<span class="next">
<%= link_to_if next_post_id, "next ", post_path(next_post_id.to_i, favgroup_id: favgroup.id), rel: ["nofollow", ("next" if selected)] %>
</span>
<span class="last">
<%= link_to_unless last_post_id == post.id, "»", post_path(last_post_id, favgroup_id: favgroup.id), rel: "nofollow" %>
</span>
<% end %>
<% end %>
</ul>

View File

@@ -0,0 +1,31 @@
.post-notice-search {
li {
display: flex;
&[data-selected="true"] {
font-weight: bold;
}
.first, .prev, .next, .last {
flex: 0;
margin: 0 0.25em;
white-space: nowrap;
}
.first, .last {
flex-basis: 1em;
}
&.search-navbar .prev, &.search-navbar .next {
margin: 0 1.75em;
}
.pool-name, .favgroup-name, .search-name {
flex: 1;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}

View File

@@ -18,4 +18,8 @@ module ComponentsHelper
def render_post_votes(post, **options)
render PostVotesComponent.new(post: post, **options)
end
def render_post_navbar(post, **options)
render PostNavbarComponent.new(post: post, **options)
end
end

View File

@@ -41,11 +41,4 @@ module PostsHelper
source
end
end
def is_pool_selected?(pool)
return false if params.key?(:q)
return false if params.key?(:favgroup_id)
return false if !params.key?(:pool_id)
return params[:pool_id].to_i == pool.id
end
end

View File

@@ -178,18 +178,8 @@ Post.swipe_prev = function(e) {
Post.nav_prev = function(e) {
var href = "";
if ($("#search-seq-nav").length) {
href = $("#search-seq-nav a[rel~=prev]").attr("href");
if (href) {
location.href = href;
}
} else if ($(".paginator a[rel~=prev]").length) {
if ($(".paginator a[rel~=prev], .post-notice-search a[rel~=prev]").length) {
location.href = $("a[rel~=prev]").attr("href");
} else {
href = $("#pool-nav li[data-selected=true] a[rel=prev], #favgroup-nav li[data-selected=true] a[rel=prev]").attr("href");
if (href) {
location.href = href;
}
}
e.preventDefault();
@@ -198,16 +188,8 @@ Post.nav_prev = function(e) {
Post.nav_next = function(e) {
var href = "";
if ($("#search-seq-nav").length) {
href = $("#search-seq-nav a[rel~=next]").attr("href");
location.href = href;
} else if ($(".paginator a[rel~=next]").length) {
location.href = $(".paginator a[rel~=next]").attr("href");
} else {
href = $("#pool-nav li[data-selected=true] a[rel=next], #favgroup-nav li[data-selected=true] a[rel=next]").attr("href");
if (href) {
location.href = href;
}
if ($(".paginator a[rel~=next], .post-notice-search a[rel~=next]").length) {
location.href = $("a[rel~=next]").attr("href");
}
e.preventDefault();

View File

@@ -208,10 +208,6 @@ div#c-posts {
margin: 1em 0 0.5em;
}
.pool-name, .search-name {
word-wrap: break-word;
}
textarea {
margin-bottom: 0.25em;
}
@@ -225,51 +221,11 @@ div#c-posts {
word-wrap: break-word;
}
#search-seq-nav + #pool-nav, #search-seq-nav + #favgroup-nav, #pool-nav + #favgroup-nav {
margin-top: 0.5em;
}
#recommended.loading-recommended-posts {
pointer-events: none;
opacity: 0.5;
}
#pool-nav, #search-seq-nav, #favgroup-nav {
li {
position: relative;
text-align: center;
padding: 0 5.5em;
&[data-selected="true"] {
font-weight: bold;
}
.prev {
position: absolute;
left: 2em;
top: 0;
}
.next {
position: absolute;
right: 2em;
top: 0;
}
.first {
position: absolute;
left: 0.5em;
top: 0;
}
.last {
position: absolute;
right: 0.5em;
top: 0;
}
}
}
span.close-button {
position: absolute;
top: 5px;

View File

@@ -17,14 +17,4 @@ class PostPresenter
def filename_for_download
"#{humanized_essential_tag_string} - #{@post.md5}.#{@post.file_ext}"
end
def has_nav_links?(template)
has_sequential_navigation?(template.params) || @post.pools.undeleted.any? || CurrentUser.favorite_groups.for_post(@post.id).any?
end
def has_sequential_navigation?(params)
return false if PostQueryBuilder.new(params[:q]).has_metatag?(:order, :ordfav, :ordpool)
return false if params[:pool_id].present? || params[:favgroup_id].present?
true
end
end

View File

@@ -1,34 +0,0 @@
<div id="favgroup-nav">
<ul>
<% favgroups = favgroups.sort_by { |favgroup| [(favgroup.id == params[:favgroup_id].to_i) ? 0 : 1, favgroup.name] } %>
<% favgroups.each do |favgroup| %>
<% selected = favgroup.id == params[:favgroup_id].to_i %>
<%= tag.li id: "nav-link-for-favgroup-#{favgroup.id}", "data-selected": selected do %>
<span class="first">
<%= link_to_unless favgroup.first_post?(post.id), "«", post_path(favgroup.post_ids.first, favgroup_id: favgroup.id) %>
</span>
<% favgroup.previous_post_id(post.id).tap do |previous_post_id| %>
<span class="prev">
<%= link_to_if previous_post_id, " prev", post_path(previous_post_id.to_i, favgroup_id: favgroup.id), rel: ("prev" if selected) %>
</span>
<% end %>
<span class="favgroup-name">
<%= link_to "Favorite group: #{favgroup.pretty_name}", favgroup %>
</span>
<% favgroup.next_post_id(post.id).tap do |next_post_id| %>
<span class="next">
<%= link_to_if next_post_id, "next ", post_path(next_post_id.to_i, favgroup_id: favgroup.id), rel: ("next" if selected) %>
</span>
<% end %>
<span class="last">
<%= link_to_unless favgroup.last_post?(post.id), "»", post_path(favgroup.post_ids.last, favgroup_id: favgroup.id) %>
</span>
<% end %>
<% end %>
</ul>
</div>

View File

@@ -1,15 +0,0 @@
<% if (position == "bottom" && CurrentUser.user.new_post_navigation_layout) || (position == "top" && !CurrentUser.user.new_post_navigation_layout) %>
<div id="nav-links" class="notice post-notice post-notice-search">
<% if post.presenter.has_sequential_navigation?(params) %>
<%= render "posts/partials/show/search_seq", :post => post %>
<% end %>
<% if post.pools.undeleted.present? %>
<%= render "posts/partials/show/pool_list", post: post, pools: post.pools.undeleted %>
<% end %>
<% if CurrentUser.user.favorite_groups.for_post(post.id).present? %>
<%= render "posts/partials/show/favorite_groups", post: post, favgroups: CurrentUser.user.favorite_groups.for_post(post.id).order(name: :asc) %>
<% end %>
</div>
<% end %>

View File

@@ -1,8 +0,0 @@
<div id="pool-nav">
<ul>
<% pools = pools.sort_by { |pool| [is_pool_selected?(pool) ? 0 : 1, pool.is_series? ? 0 : 1, pool.name] } %>
<% pools.each do |pool| %>
<%= render "posts/partials/show/pool_list_item", pool: pool, post: post, selected: is_pool_selected?(pool) %>
<% end %>
</ul>
</div>

View File

@@ -1,33 +0,0 @@
<%= tag.li id: "nav-link-for-pool-#{pool.id}", class: "pool-category-#{pool.category}", "data-selected": selected do -%>
<% if !pool.first_post?(post.id) && pool.post_ids.first -%>
<%= link_to("&laquo;".html_safe, post_path(pool.post_ids.first, pool_id: pool.id), class: "first", title: "to page 1") %>
<% else -%>
<span class="first">&laquo;</span>
<% end -%>
<% pool.previous_post_id(post.id).tap do |previous_post_id| -%>
<% if previous_post_id %>
<%= link_to "&lsaquo;&thinsp;prev".html_safe, post_path(previous_post_id, pool_id: pool.id), rel: selected ? "prev" : nil, class: "prev", title: "to page #{pool.page_number(previous_post_id)}" -%>
<% else -%>
<span class="prev">&lsaquo;&thinsp;prev</span>
<% end %>
<% end -%>
<span class="pool-name">
<%= link_to("Pool: #{pool.pretty_name}", pool_path(pool), title: "page #{pool.page_number(post.id)}/#{pool.post_count}") -%>
</span>
<% pool.next_post_id(post.id).tap do |next_post_id| -%>
<% if next_post_id %>
<%= link_to("next&thinsp;&rsaquo;".html_safe, post_path(next_post_id, pool_id: pool.id), rel: selected ? "next" : nil, class: "next", title: "to page #{pool.page_number(next_post_id)}") -%>
<% else -%>
<span class="next">next&thinsp;&rsaquo;</span>
<% end -%>
<% end -%>
<% if !pool.last_post?(post.id) && pool.post_ids.last -%>
<%= link_to("&raquo;".html_safe, post_path(pool.post_ids.last, pool_id: pool.id), class: "last", title: "to page #{pool.post_count}") -%>
<% else -%>
<span class="last">&raquo;</span>
<% end -%>
<% end -%>

View File

@@ -1,9 +0,0 @@
<div id="search-seq-nav">
<ul>
<li data-selected="true">
<%= link_to "&lsaquo;&thinsp;prev".html_safe, show_seq_post_path(post, q: params[:q], seq: "prev"), rel: "prev", class: "prev" %>
<span class="search-name">Search: <%= params[:q].presence || "status:any" %></span>
<%= link_to "next&thinsp;&rsaquo;".html_safe, show_seq_post_path(post, q: params[:q], seq: "next"), rel: "next", class: "next" %>
</li>
</ul>
</div>

View File

@@ -38,8 +38,8 @@
<% end %>
<% content_for(:content) do %>
<% if @post.presenter.has_nav_links?(self) %>
<%= render "posts/partials/show/nav_links", :post => @post, :position => "top" %>
<% if !CurrentUser.user.new_post_navigation_layout %>
<%= render_post_navbar(@post, current_user: CurrentUser.user, search: params[:q], pool_id: params[:pool_id], favgroup_id: params[:favgroup_id]) %>
<% end %>
<%= render "posts/partials/show/notices", :post => @post %>
@@ -82,8 +82,8 @@
</div>
<% end %>
<% if @post.presenter.has_nav_links?(self) %>
<%= render "posts/partials/show/nav_links", :post => @post, :position => "bottom" %>
<% if CurrentUser.user.new_post_navigation_layout %>
<%= render_post_navbar(@post, current_user: CurrentUser.user, search: params[:q], pool_id: params[:pool_id], favgroup_id: params[:favgroup_id]) %>
<% end %>
<menu id="post-sections">

View File

@@ -0,0 +1,52 @@
require "test_helper"
class PostNavbarComponentTest < ViewComponent::TestCase
def render_post_navbar(post, **options)
render_inline(PostNavbarComponent.new(post: post, **options))
end
setup do
@post = create(:post)
@user = create(:user)
end
context "The PostNavbarComponent" do
context "for a post with a search" do
should "render" do
render_post_navbar(@post, current_user: @user, search: "touhou")
assert_css(".search-navbar", text: "Search: touhou")
end
end
context "for a post with pools" do
should "render" do
as(@user) do
@pool1 = create(:pool, category: "series")
@pool2 = create(:pool, category: "collection")
@post.update(tag_string: "pool:#{@pool1.id} pool:#{@pool2.id}")
end
render_post_navbar(@post, current_user: @user, pool_id: @pool1.id)
assert_css(".pool-name", text: "Pool: #{@pool1.pretty_name}")
assert_css(".pool-name", text: "Pool: #{@pool2.pretty_name}")
end
end
context "for a post with favgroups" do
should "render" do
as(@user) do
@favgroup1 = create(:favorite_group, creator: @user)
@favgroup2 = create(:favorite_group, creator: @user)
@post.update(tag_string: "favgroup:#{@favgroup1.id} favgroup:#{@favgroup2.id}")
end
render_post_navbar(@post, current_user: @user, favgroup_id: @favgroup1.id)
assert_css(".favgroup-name", text: "Favgroup: #{@favgroup1.pretty_name}")
assert_css(".favgroup-name", text: "Favgroup: #{@favgroup2.pretty_name}")
end
end
end
end

View File

@@ -556,7 +556,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
get post_path(@post)
assert_response :success
assert_select "#pool-nav .pool-name", /Pool: comic/
assert_select ".pool-navbar .pool-name", /Pool: comic/
end
end