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:
39
app/components/post_navbar_component.rb
Normal file
39
app/components/post_navbar_component.rb
Normal 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
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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 %>
|
||||
@@ -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>
|
||||
@@ -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("«".html_safe, post_path(pool.post_ids.first, pool_id: pool.id), class: "first", title: "to page 1") %>
|
||||
<% else -%>
|
||||
<span class="first">«</span>
|
||||
<% end -%>
|
||||
|
||||
<% pool.previous_post_id(post.id).tap do |previous_post_id| -%>
|
||||
<% if previous_post_id %>
|
||||
<%= link_to "‹ 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">‹ 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 ›".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 ›</span>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
<% if !pool.last_post?(post.id) && pool.post_ids.last -%>
|
||||
<%= link_to("»".html_safe, post_path(pool.post_ids.last, pool_id: pool.id), class: "last", title: "to page #{pool.post_count}") -%>
|
||||
<% else -%>
|
||||
<span class="last">»</span>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
@@ -1,9 +0,0 @@
|
||||
<div id="search-seq-nav">
|
||||
<ul>
|
||||
<li data-selected="true">
|
||||
<%= link_to "‹ 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 ›".html_safe, show_seq_post_path(post, q: params[:q], seq: "next"), rel: "next", class: "next" %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -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">
|
||||
|
||||
52
test/components/post_navbar_component_test.rb
Normal file
52
test/components/post_navbar_component_test.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user