votes: add vote buttons beneath thumbnails.

Add upvote and downvote buttons beneath thumbnails on the post index page.

This is disabled by default. To enable it, click the "..." menu in the top
right of the page, then click "Show scores".

This is currently a per-search setting, not an account setting. If you
enable it in one tab, it won't be enabled in other tabs.
This commit is contained in:
evazion
2021-11-18 01:49:50 -06:00
parent 5585d1f7d6
commit bd8672681f
16 changed files with 61 additions and 30 deletions

View File

@@ -28,7 +28,7 @@ div.popup-menu {
li a { li a {
display: block; display: block;
padding: 0.125em 2em 0.125em 0; padding: 0.125em 0 0.125em 0;
.icon { .icon {
width: 1rem; width: 1rem;

View File

@@ -3,18 +3,19 @@
class PostPreviewComponent < ApplicationComponent class PostPreviewComponent < ApplicationComponent
with_collection_parameter :post with_collection_parameter :post
attr_reader :post, :tags, :show_deleted, :show_cropped, :link_target, :pool, :similarity, :recommended, :compact, :size, :current_user, :options attr_reader :post, :tags, :show_deleted, :show_cropped, :link_target, :pool, :similarity, :recommended, :show_votes, :compact, :size, :current_user, :options
delegate :external_link_to, :time_ago_in_words_tagged, :duration_to_hhmmss, :empty_heart_icon, :sound_icon, to: :helpers delegate :external_link_to, :time_ago_in_words_tagged, :duration_to_hhmmss, :render_post_votes, :empty_heart_icon, :sound_icon, to: :helpers
delegate :image_width, :image_height, :file_ext, :file_size, :duration, :is_animated?, to: :media_asset delegate :image_width, :image_height, :file_ext, :file_size, :duration, :is_animated?, to: :media_asset
delegate :media_asset, to: :post delegate :media_asset, to: :post
def initialize(post:, tags: "", show_deleted: false, show_cropped: true, link_target: post, pool: nil, similarity: nil, recommended: nil, compact: nil, size: nil, current_user: CurrentUser.user, **options) def initialize(post:, tags: "", show_deleted: false, show_cropped: true, show_votes: true, link_target: post, pool: nil, similarity: nil, recommended: nil, compact: nil, size: nil, current_user: CurrentUser.user, **options)
super super
@post = post @post = post
@tags = tags.presence @tags = tags.presence
@show_deleted = show_deleted @show_deleted = show_deleted
@show_cropped = show_cropped @show_cropped = show_cropped
@show_votes = show_votes
@link_target = link_target @link_target = link_target
@pool = pool @pool = pool
@similarity = similarity.round(1) if similarity.present? @similarity = similarity.round(1) if similarity.present?

View File

@@ -23,8 +23,7 @@
<p class="desc"> <p class="desc">
<%= link_to pool.pretty_name.truncate(80), pool %> <%= link_to pool.pretty_name.truncate(80), pool %>
</p> </p>
<% end -%> <% elsif similarity -%>
<% if similarity -%>
<p class="desc"> <p class="desc">
<% if post.source =~ %r!\Ahttps?://!i %> <% if post.source =~ %r!\Ahttps?://!i %>
<%= external_link_to post.normalized_source, post.source_domain %> <%= external_link_to post.normalized_source, post.source_domain %>
@@ -33,20 +32,19 @@
<%= time_ago_in_words_tagged(post.created_at, compact: true) %> <%= time_ago_in_words_tagged(post.created_at, compact: true) %>
<% end %> <% end %>
</p> </p>
<% end %>
<% if size -%>
<p class="desc"> <p class="desc">
<%= link_to number_to_human_size(size), post.file_url %> <%= link_to number_to_human_size(size), post.file_url %>
(<%= post.image_width %>x<%= post.image_height %>) (<%= post.image_width %>x<%= post.image_height %>)
</p> </p>
<% end -%>
<% if similarity -%>
<p class="desc"> <p class="desc">
<%= link_to "#{similarity}%", iqdb_queries_path(post_id: post.id) %> similarity <%= link_to "#{similarity}%", iqdb_queries_path(post_id: post.id) %> similarity
</p> </p>
<% end -%> <% elsif size -%>
<p class="desc">
<% if recommended -%> <%= link_to number_to_human_size(size), post.file_url %>
(<%= post.image_width %>x<%= post.image_height %>)
</p>
<% elsif recommended -%>
<p class="desc recommended"> <p class="desc recommended">
<%= link_to recommended_posts_path(search: { post_id: post.id }), class: "more-recommended-posts", "data-post-id": post.id do %> <%= link_to recommended_posts_path(search: { post_id: post.id }), class: "more-recommended-posts", "data-post-id": post.id do %>
<%= post.fav_count %> <%= post.fav_count %>
@@ -56,5 +54,9 @@
<br>more » <br>more »
<% end %> <% end %>
</p> </p>
<% elsif show_votes -%>
<p class="desc">
<%= render_post_votes post, current_user: current_user %>
</p>
<% end -%> <% end -%>
<% end -%> <% end -%>

View File

@@ -1,7 +1,6 @@
@import "../../javascript/src/styles/base/000_vars.scss"; @import "../../javascript/src/styles/base/000_vars.scss";
article.post-preview { article.post-preview {
height: 154px;
width: 154px; width: 154px;
margin: 0 10px 10px 0; margin: 0 10px 10px 0;
text-align: center; text-align: center;

View File

@@ -15,7 +15,7 @@ class PostVotesComponent < ApplicationComponent
end end
def current_vote def current_vote
post.votes.find_by(user: current_user) post.vote_by_current_user
end end
def upvoted? def upvoted?

View File

@@ -1,15 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
class TagListComponent < ApplicationComponent class TagListComponent < ApplicationComponent
attr_reader :tags, :current_query, :show_extra_links attr_reader :tags, :current_query, :show_extra_links, :search_params
delegate :humanized_number, to: :helpers delegate :humanized_number, to: :helpers
def initialize(tags: [], current_query: nil, show_extra_links: false) def initialize(tags: [], current_query: nil, show_extra_links: false, search_params: {})
super super
@tags = tags @tags = tags
@current_query = current_query @current_query = current_query
@show_extra_links = show_extra_links @show_extra_links = show_extra_links
@search_params = search_params
end end
def self.tags_from_names(tag_names) def self.tags_from_names(tag_names)

View File

@@ -11,11 +11,11 @@
<% end %> <% end %>
<% if show_extra_links && current_query.present? %> <% if show_extra_links && current_query.present? %>
<%= link_to "+", posts_path(tags: "#{current_query} #{t.name}"), class: "search-inc-tag" %> <%= link_to "+", posts_path(tags: "#{current_query} #{t.name}", **search_params), class: "search-inc-tag" %>
<%= link_to "-", posts_path(tags: "#{current_query} -#{t.name}"), class: "search-exl-tag" %> <%= link_to "-", posts_path(tags: "#{current_query} -#{t.name}", **search_params), class: "search-exl-tag" %>
<% end %> <% end %>
<%= link_to t.pretty_name, posts_path(tags: t.name), class: "search-tag" %> <%= link_to t.pretty_name, posts_path(tags: t.name, **search_params), class: "search-tag" %>
<%= tag.span humanized_number(t.post_count), class: "post-count", title: t.post_count %> <%= tag.span humanized_number(t.post_count), class: "post-count", title: t.post_count %>
</li> </li>
<% end %> <% end %>

View File

@@ -10,7 +10,7 @@ class PostsController < ApplicationController
end end
else else
tag_query = params[:tags] || params.dig(:post, :tags) tag_query = params[:tags] || params.dig(:post, :tags)
@post_set = PostSets::Post.new(tag_query, params[:page], params[:limit], random: params[:random], format: params[:format]) @post_set = PostSets::Post.new(tag_query, params[:page], params[:limit], random: params[:random], format: params[:format], view: params[:view])
@posts = authorize @post_set.posts, policy_class: PostPolicy @posts = authorize @post_set.posts, policy_class: PostPolicy
@post_set.log! @post_set.log!
respond_with(@posts) do |format| respond_with(@posts) do |format|

View File

@@ -98,7 +98,6 @@ menu {
> li { > li {
margin: 0; margin: 0;
padding: 0 0.2em;
display: inline; display: inline;
} }
} }

View File

@@ -82,6 +82,8 @@ $spacer: 0.25rem; /* 4px */
.items-center { align-items: center; } .items-center { align-items: center; }
.justify-center { justify-content: center; } .justify-center { justify-content: center; }
.float-right { float: right; }
.thin-scrollbar { .thin-scrollbar {
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;

View File

@@ -135,8 +135,6 @@ div#c-posts {
font-size: var(--text-lg); font-size: var(--text-lg);
li { li {
padding: 0 1em 0 0;
&.active { &.active {
font-weight: bold; font-weight: bold;
} }

View File

@@ -7,10 +7,10 @@ module PostSets
MAX_PER_PAGE = 200 MAX_PER_PAGE = 200
MAX_SIDEBAR_TAGS = 25 MAX_SIDEBAR_TAGS = 25
attr_reader :page, :random, :format, :tag_string, :query, :normalized_query attr_reader :page, :random, :format, :tag_string, :query, :normalized_query, :view
delegate :post_count, to: :normalized_query delegate :post_count, to: :normalized_query
def initialize(tags, page = 1, per_page = nil, user: CurrentUser.user, random: false, format: "html") def initialize(tags, page = 1, per_page = nil, user: CurrentUser.user, random: false, format: "html", view: "simple")
@query = PostQueryBuilder.new(tags, user, tag_limit: user.tag_query_limit, safe_mode: CurrentUser.safe_mode?, hide_deleted_posts: user.hide_deleted_posts?) @query = PostQueryBuilder.new(tags, user, tag_limit: user.tag_query_limit, safe_mode: CurrentUser.safe_mode?, hide_deleted_posts: user.hide_deleted_posts?)
@normalized_query = query.normalized_query @normalized_query = query.normalized_query
@tag_string = tags @tag_string = tags
@@ -18,6 +18,7 @@ module PostSets
@per_page = per_page @per_page = per_page
@random = random.to_s.truthy? @random = random.to_s.truthy?
@format = format.to_s @format = format.to_s
@view = view.presence || "simple"
end end
def humanized_tag_string def humanized_tag_string
@@ -107,7 +108,7 @@ module PostSets
if is_random? if is_random?
get_random_posts.paginate(page, search_count: false, limit: per_page, max_limit: max_per_page).load get_random_posts.paginate(page, search_count: false, limit: per_page, max_limit: max_per_page).load
else else
normalized_query.paginated_posts(page, includes: :media_asset, count: post_count, search_count: !post_count.nil?, limit: per_page, max_limit: max_per_page).load normalized_query.paginated_posts(page, includes: includes, count: post_count, search_count: !post_count.nil?, limit: per_page, max_limit: max_per_page).load
end end
end end
end end
@@ -139,6 +140,18 @@ module PostSets
end end
end end
def show_votes?
view == "score"
end
def includes
if show_votes?
[:media_asset, :vote_by_current_user]
else
[:media_asset]
end
end
def search_stats def search_stats
{ {
query: normalized_query.to_s, query: normalized_query.to_s,

View File

@@ -40,6 +40,7 @@ class Post < ApplicationRecord
has_one :upload, :dependent => :destroy has_one :upload, :dependent => :destroy
has_one :artist_commentary, :dependent => :destroy has_one :artist_commentary, :dependent => :destroy
has_one :pixiv_ugoira_frame_data, class_name: "PixivUgoiraFrameData", foreign_key: :md5, primary_key: :md5 has_one :pixiv_ugoira_frame_data, class_name: "PixivUgoiraFrameData", foreign_key: :md5, primary_key: :md5
has_one :vote_by_current_user, -> { where(user_id: CurrentUser.id) }, class_name: "PostVote" # XXX using current user here is wrong
has_many :flags, :class_name => "PostFlag", :dependent => :destroy has_many :flags, :class_name => "PostFlag", :dependent => :destroy
has_many :appeals, :class_name => "PostAppeal", :dependent => :destroy has_many :appeals, :class_name => "PostAppeal", :dependent => :destroy
has_many :votes, :class_name => "PostVote", :dependent => :destroy has_many :votes, :class_name => "PostVote", :dependent => :destroy

View File

@@ -7,7 +7,7 @@
<section id="tag-box"> <section id="tag-box">
<h2>Tags</h2> <h2>Tags</h2>
<%= render_search_tag_list(@post_set.related_tags, current_query: params[:tags], show_extra_links: policy(Post).show_extra_links?) %> <%= render_search_tag_list(@post_set.related_tags, current_query: params[:tags], show_extra_links: policy(Post).show_extra_links?, search_params: { view: params[:view] }) %>
</section> </section>
<%= render "posts/partials/index/options" %> <%= render "posts/partials/index/options" %>
@@ -16,7 +16,7 @@
<% end %> <% end %>
<% content_for(:content) do %> <% content_for(:content) do %>
<menu id="post-sections" class="mb-4"> <menu id="post-sections" class="mb-4 space-x-2">
<li class="active"><a href="#" id="show-posts-link">Posts</a></li> <li class="active"><a href="#" id="show-posts-link">Posts</a></li>
<% if @post_set.artist.present? %> <% if @post_set.artist.present? %>
@@ -31,6 +31,18 @@
<li class="blank-wiki-excerpt-link"><%= link_to "Wiki", new_wiki_page_path(wiki_page: { title: @post_set.tag.name }), id: "show-excerpt-link" %></li> <li class="blank-wiki-excerpt-link"><%= link_to "Wiki", new_wiki_page_path(wiki_page: { title: @post_set.tag.name }), id: "show-excerpt-link" %></li>
<% end %> <% end %>
<li class="float-right">
<%= render PopupMenuComponent.new do |menu| %>
<% menu.item do %>
<% if params[:view] == "score" %>
<%= link_to "Hide scores", posts_path(tags: params[:tags], view: nil) %>
<% else %>
<%= link_to "Show scores", posts_path(tags: params[:tags], view: "score") %>
<% end %>
<% end %>
<% end %>
</li>
<li id="searchbox-redirect-link" class="mobile-only"><a href="#search-box">Search &raquo;</a></li> <li id="searchbox-redirect-link" class="mobile-only"><a href="#search-box">Search &raquo;</a></li>
</menu> </menu>

View File

@@ -6,6 +6,9 @@
<% if params[:random] %> <% if params[:random] %>
<%= hidden_field_tag :random, params[:random] %> <%= hidden_field_tag :random, params[:random] %>
<% end %> <% end %>
<% if params[:view] %>
<%= hidden_field_tag :view, params[:view] %>
<% end %>
<%= text_field_tag("tags", tags, :id => tags_dom_id, :class => "flex-auto", :"data-shortcut" => "q", :"data-autocomplete" => "tag-query") %> <%= text_field_tag("tags", tags, :id => tags_dom_id, :class => "flex-auto", :"data-shortcut" => "q", :"data-autocomplete" => "tag-query") %>
<button id="search-box-submit" type="submit"><%= search_icon %></button> <button id="search-box-submit" type="submit"><%= search_icon %></button>
<% end %> <% end %>

View File

@@ -3,7 +3,7 @@
<% if post_set.shown_posts.empty? %> <% if post_set.shown_posts.empty? %>
<%= render "post_sets/blank" %> <%= render "post_sets/blank" %>
<% else %> <% else %>
<%= post_previews_html(post_set.posts, show_deleted: post_set.show_deleted?, show_cropped: true, tags: post_set.tag_string) %> <%= post_previews_html(post_set.posts, show_deleted: post_set.show_deleted?, show_cropped: true, tags: post_set.tag_string, show_votes: post_set.show_votes?) %>
<% end %> <% end %>
</div> </div>