posts: add adjustable thumbnail sizes (#4932).

Add a menu in the top right of the post index page that lets you select
the thumbnail size.

This menu is currently hidden until the new thumbnails have been generated.

On desktop, there are five thumbnail sizes:

* Small:    150x150 (https://danbooru.donmai.us/posts?size=150)
* Medium:   180x180 (https://danbooru.donmai.us/posts?size=180)
* Large:    225x225 (https://danbooru.donmai.us/posts?size=225)
* Huge:     270x270 (https://danbooru.donmai.us/posts?size=270)
* Gigantic: 360x360 (https://danbooru.donmai.us/posts?size=360)

On mobile, there are four sizes:

* Small:  150x150 / 3 posts per row (https://danbooru.donmai.us/posts?size=150)
* Medium: 180x180 / 2 posts per row (https://danbooru.donmai.us/posts?size=180)
* Large:  225x225 / 2 posts per row (https://danbooru.donmai.us/posts?size=225)
* Huge:   360x360 / 1 posts per row (https://danbooru.donmai.us/posts?size=360)

There are two extra sizes that aren't listed in the menu:

* 225x360 (https://danbooru.donmai.us/posts?size=225w)
* 270x360 (https://danbooru.donmai.us/posts?size=270w)

These sizes are good for tall thumbnails, but not so much for wide
thumbnails. They aren't listed because in practice they're a bit too big.

The 225x225 and 270x270 sizes are really just 360x360 thumbnails scaled
down in HTML. This means 225x225 and 360x360 thumbnails both use the
same amount of bandwidth.

Thumbnail size is currently a per-search option, not a persistent
account-level setting.

This changes the HTML structure of thumbnails somewhat, so this may
break userscripts and custom CSS.
This commit is contained in:
evazion
2021-12-04 06:04:13 -06:00
parent 17537084fe
commit 8841de68ac
20 changed files with 224 additions and 95 deletions

View File

@@ -2,7 +2,14 @@
class PopupMenuComponent < ApplicationComponent class PopupMenuComponent < ApplicationComponent
include ViewComponent::SlotableV2 include ViewComponent::SlotableV2
delegate :ellipsis_icon, to: :helpers
attr_reader :classes
renders_one :button
renders_many :items renders_many :items
# @param classes [String] A list of CSS classes for the root element.
def initialize(classes: nil)
@classes = classes
end
end end

View File

@@ -1,6 +1,10 @@
<div class="popup-menu"> <div class="popup-menu <%= classes %>">
<a class="popup-menu-button" href="javascript:void(0)"> <a class="popup-menu-button" href="javascript:void(0)">
<%= ellipsis_icon %> <% if button.present? %>
<%= button %>
<% else %>
<%= helpers.ellipsis_icon %>
<% end %>
</a> </a>
<ul class="popup-menu-content"> <ul class="popup-menu-content">

View File

@@ -9,7 +9,8 @@ div.popup-menu {
justify-content: center; justify-content: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 50%; border-radius: 4px;
padding: 4px 8px;
color: var(--muted-text-color); color: var(--muted-text-color);
// the popup menu is open // the popup menu is open

View File

@@ -7,7 +7,7 @@
# * Inline galleries that fit on a single row, as seen in parent/child post sets. # * Inline galleries that fit on a single row, as seen in parent/child post sets.
# #
class PostGalleryComponent < ApplicationComponent class PostGalleryComponent < ApplicationComponent
attr_reader :posts, :current_user, :inline, :options attr_reader :posts, :current_user, :inline, :size, :options
delegate :post_preview, :numbered_paginator, to: :helpers delegate :post_preview, :numbered_paginator, to: :helpers
@@ -18,14 +18,22 @@ class PostGalleryComponent < ApplicationComponent
# @param current_user [User] The current user. # @param current_user [User] The current user.
# @param inline [Boolean] If true, the gallery is rendered as a single row with a # @param inline [Boolean] If true, the gallery is rendered as a single row with a
# horizontal scrollbar. If false, the gallery is rendered as a grid of thumbnails. # horizontal scrollbar. If false, the gallery is rendered as a grid of thumbnails.
# @param size [String] The size of thumbnails in the gallery. Can be "150",
# "180", "225", "225w", "270", "270w", or "360".
# @param options [Hash] A set of options given to the thumbnail in `post_preview`. # @param options [Hash] A set of options given to the thumbnail in `post_preview`.
def initialize(posts:, current_user:, inline: false, **options) def initialize(posts:, current_user:, inline: false, size: PostPreviewComponent::DEFAULT_SIZE, **options)
super super
@posts = posts @posts = posts
@posts = @posts.includes(:media_asset) if posts.is_a?(ActiveRecord::Relation) @posts = @posts.includes(:media_asset) if posts.is_a?(ActiveRecord::Relation)
@current_user = current_user @current_user = current_user
@inline = inline @inline = inline
@options = options @options = options
if size.to_s.in?(PostPreviewComponent::SIZES)
@size = size
else
@size = PostPreviewComponent::DEFAULT_SIZE
end
end end
def gallery_type def gallery_type

View File

@@ -1,8 +1,8 @@
<div class="post-gallery post-gallery-<%= gallery_type %>"> <div class="post-gallery post-gallery-<%= gallery_type %> post-gallery-<%= size %>">
<% if empty? %> <% if empty? %>
<p>No posts found.</p> <p>No posts found.</p>
<% else %> <% else %>
<div class="posts-container grid gap-1 grid-cols-2 md:block"> <div class="posts-container grid gap-2">
<% posts.each do |post| -%> <% posts.each do |post| -%>
<% %><%= post_preview(post, **options) -%> <% %><%= post_preview(post, **options) -%>
<% end -%> <% end -%>

View File

@@ -12,12 +12,30 @@
} }
} }
@media screen and (max-width: 660px) { .post-gallery {
.post-gallery-full { .posts-container {
.posts-container { place-items: center;
&.user-disable-cropped-false article.post-preview img.has-cropped-true { }
object-fit: none;
} .post-preview-image {
} max-width: 100%;
}
&.post-gallery-150 .posts-container { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
&.post-gallery-180 .posts-container { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
&.post-gallery-225 .posts-container { grid-template-columns: repeat(auto-fill, minmax(225px, 1fr)); }
&.post-gallery-225w .posts-container { grid-template-columns: repeat(auto-fill, minmax(225px, 1fr)); }
&.post-gallery-270 .posts-container { grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); }
&.post-gallery-270w .posts-container { grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); }
&.post-gallery-360 .posts-container { grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); }
@media screen and (max-width: 660px) {
&.post-gallery-150 .posts-container { grid-template-columns: repeat(3, auto); }
&.post-gallery-180 .posts-container { grid-template-columns: repeat(2, auto); }
&.post-gallery-225 .posts-container { grid-template-columns: repeat(2, auto); }
&.post-gallery-225w .posts-container { grid-template-columns: repeat(2, auto); }
&.post-gallery-270 .posts-container { grid-template-columns: repeat(2, auto); }
&.post-gallery-270w .posts-container { grid-template-columns: repeat(2, auto); }
&.post-gallery-360 .posts-container { grid-template-columns: repeat(1, auto); }
} }
} }

View File

@@ -1,18 +1,33 @@
# frozen_string_literal: true # frozen_string_literal: true
class PostPreviewComponent < ApplicationComponent class PostPreviewComponent < ApplicationComponent
DEFAULT_SIZE = "150"
SIZES = %w[150 180 225 225w 270 270w 360]
with_collection_parameter :post with_collection_parameter :post
attr_reader :post, :tags, :show_deleted, :link_target, :pool, :similarity, :recommended, :show_votes, :compact, :size, :current_user, :options attr_reader :post, :tags, :size, :show_deleted, :link_target, :pool, :similarity, :recommended, :show_votes, :compact, :show_size, :current_user, :options
delegate :external_link_to, :time_ago_in_words_tagged, :duration_to_hhmmss, :render_post_votes, :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_votes: false, link_target: post, pool: nil, similarity: nil, recommended: nil, compact: nil, size: nil, current_user: CurrentUser.user, **options) # @param post [Post] The post to show the thumbnail for.
# @param tags [String] The current tag search, if any.
# @param size [String] The size of the thumbnail. One of "150", "180", "225",
# "225w", "270", "270w", or "360".
# @param show_deleted [Boolean] If true, show thumbnails for deleted posts.
# If false, hide thumbnails of deleted posts.
# @param show_votes [Boolean] If true, show scores and vote buttons beneath the thumbnail.
# @param show_size [Boolean] If true, show filesize and resolution beneath the thumbnail.
# @param link_target [ApplicationRecord] What the thumbnail links to (default: the post).
# @param current_user [User] The current user.
def initialize(post:, tags: "", size: DEFAULT_SIZE, show_deleted: false, show_votes: false, link_target: post, pool: nil, similarity: nil, recommended: nil, compact: nil, show_size: nil, current_user: CurrentUser.user, **options)
super super
@post = post @post = post
@tags = tags.presence @tags = tags.presence
@size = size.presence || DEFAULT_SIZE
@show_deleted = show_deleted @show_deleted = show_deleted
@show_votes = show_votes @show_votes = show_votes
@link_target = link_target @link_target = link_target
@@ -20,7 +35,7 @@ class PostPreviewComponent < ApplicationComponent
@similarity = similarity.round(1) if similarity.present? @similarity = similarity.round(1) if similarity.present?
@recommended = recommended.round(1) if recommended.present? @recommended = recommended.round(1) if recommended.present?
@compact = compact @compact = compact
@size = post.file_size if size.present? @show_size = show_size
@current_user = current_user @current_user = current_user
@options = options @options = options
end end
@@ -33,16 +48,33 @@ class PostPreviewComponent < ApplicationComponent
{ class: [classes, *preview_class].compact.join(" "), **data_attributes } { class: [classes, *preview_class].compact.join(" "), **data_attributes }
end end
def preview_width
variant.width
end
def preview_height
variant.height
end
def variant def variant
@variant ||= media_asset.variant(:preview) case size
when "150"
media_asset.variant("preview")
when "180"
media_asset.variant("180x180")
when "225", "225w"
media_asset.variant("360x360")
when "270", "270w"
media_asset.variant("360x360")
when "360"
media_asset.variant("360x360")
else
raise NotImplementedError
end
end
def preview_srcset
if size == "180"
"#{media_asset.variant("180x180").file_url} 1x, #{media_asset.variant("360x360").file_url} 2x"
else
nil
end
end
def preview_url
variant.file_url
end end
def tooltip def tooltip
@@ -51,13 +83,14 @@ class PostPreviewComponent < ApplicationComponent
def preview_class def preview_class
klass = ["post-preview"] klass = ["post-preview"]
klass << "captioned" if pool || size || similarity || recommended klass << "captioned" if pool || show_size || similarity || recommended
klass << "post-status-pending" if post.is_pending? klass << "post-status-pending" if post.is_pending?
klass << "post-status-flagged" if post.is_flagged? klass << "post-status-flagged" if post.is_flagged?
klass << "post-status-deleted" if post.is_deleted? klass << "post-status-deleted" if post.is_deleted?
klass << "post-status-has-parent" if post.parent_id klass << "post-status-has-parent" if post.parent_id
klass << "post-status-has-children" if post.has_visible_children? klass << "post-status-has-children" if post.has_visible_children?
klass << "post-preview-compact" if compact klass << "post-preview-compact" if compact
klass << "post-preview-#{size}"
klass klass
end end

View File

@@ -1,5 +1,5 @@
<%= tag.article id: "post_#{post.id}", **article_attrs do -%> <%= tag.article id: "post_#{post.id}", **article_attrs do -%>
<%= link_to polymorphic_path(link_target, q: tags) do -%> <%= link_to polymorphic_path(link_target, q: tags), class: "post-preview-link" do -%>
<% if is_animated? || has_sound? %> <% if is_animated? || has_sound? %>
<div class="post-animation-icon absolute top-0.5 left-0.5 p-0.5 m-0.5 leading-none rounded text-xs font-arial font-bold"> <div class="post-animation-icon absolute top-0.5 left-0.5 p-0.5 m-0.5 leading-none rounded text-xs font-arial font-bold">
<% if is_animated? %> <% if is_animated? %>
@@ -13,9 +13,7 @@
</div> </div>
<% end %> <% end %>
<%= tag.picture do -%> <%= tag.img srcset: preview_srcset, src: preview_url, width: variant.width, height: variant.height, class: "post-preview-image", title: tooltip, alt: "post ##{post.id}", crossorigin: "anonymous" -%>
<%= tag.img src: post.preview_file_url, style: "min-width: #{preview_width}px; min-height: #{preview_height}px;", title: tooltip, alt: "post ##{post.id}", crossorigin: "anonymous" -%>
<% end -%>
<% end -%> <% end -%>
<% if pool -%> <% if pool -%>
<p class="desc"> <p class="desc">
@@ -37,9 +35,9 @@
<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>
<% elsif size -%> <% elsif show_size -%>
<p class="desc"> <p class="desc">
<%= link_to number_to_human_size(size), post.file_url %> <%= link_to number_to_human_size(file_size), post.file_url %>
(<%= post.image_width %>x<%= post.image_height %>) (<%= post.image_width %>x<%= post.image_height %>)
</p> </p>
<% elsif recommended -%> <% elsif recommended -%>
@@ -53,7 +51,7 @@
<% end %> <% end %>
</p> </p>
<% elsif show_votes -%> <% elsif show_votes -%>
<div class="post-preview-score text-sm mt-1"> <div class="post-preview-score text-sm text-center mt-1">
<%= render_post_votes post, current_user: current_user %> <%= render_post_votes post, current_user: current_user %>
</div> </div>
<% end -%> <% end -%>

View File

@@ -1,12 +1,11 @@
@import "../../javascript/src/styles/base/000_vars.scss"; @import "../../javascript/src/styles/base/000_vars.scss";
article.post-preview { article.post-preview {
text-align: center;
display: inline-block; display: inline-block;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
a { .post-preview-link {
display: inline-block; display: inline-block;
position: relative; position: relative;
@@ -30,17 +29,16 @@ article.post-preview {
font-size: var(--text-sm); font-size: var(--text-sm);
margin-bottom: 0; margin-bottom: 0;
} }
img {
margin: auto;
}
} }
/* Avoid dead space around thumbnails in tables. */ .post-preview-image {
table article.post-preview {
height: auto;
width: auto; width: auto;
margin: 0; height: auto;
}
@media screen and (min-width: 660px) {
.post-preview-225 .post-preview-image { max-height: 225px; }
.post-preview-270 .post-preview-image { max-height: 270px; }
} }
.post-preview { .post-preview {
@@ -117,16 +115,8 @@ body[data-current-user-can-approve-posts="true"] .post-preview {
} }
} }
@media screen and (min-width: 660px) {
article.post-preview {
width: 154px;
margin: 0 10px 10px 0;
vertical-align: top;
}
}
@media screen and (max-width: 660px) { @media screen and (max-width: 660px) {
article.post-preview img { .post-preview-image {
border: none !important; border: none !important;
} }
} }

View File

@@ -11,7 +11,7 @@ class PostsController < ApplicationController
elsif params[:random].to_s.truthy? elsif params[:random].to_s.truthy?
post_set = PostSets::Post.new(params[:tags], params[:page], params[:limit], format: request.format.symbol, view: params[:view]) post_set = PostSets::Post.new(params[:tags], params[:page], params[:limit], format: request.format.symbol, view: params[:view])
query = "#{post_set.normalized_query.to_s} random:#{post_set.per_page}".strip query = "#{post_set.normalized_query.to_s} random:#{post_set.per_page}".strip
redirect_to posts_path(tags: query, page: params[:page], limit: params[:limit], format: request.format.symbol, view: params[:view]) redirect_to posts_path(tags: query, page: params[:page], limit: params[:limit], format: request.format.symbol, view: params[:view], size: params[:size])
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], format: request.format.symbol, view: params[:view]) @post_set = PostSets::Post.new(tag_query, params[:page], params[:limit], format: request.format.symbol, view: params[:view])

View File

@@ -158,6 +158,10 @@ module IconHelper
icon_tag("fas fa-plus", **options) icon_tag("fas fa-plus", **options)
end end
def caret_down_icon(**options)
svg_icon_tag("caret-down-icon", "M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z", viewbox: "0 0 320 512", **options)
end
# https://fontawesome.com/v6.0/icons/volume-high # https://fontawesome.com/v6.0/icons/volume-high
def sound_icon(**options) def sound_icon(**options)
svg_icon_tag("sound-icon", "M412.6 182c-10.28-8.334-25.41-6.867-33.75 3.402c-8.406 10.24-6.906 25.35 3.375 33.74C393.5 228.4 400 241.8 400 255.1c0 14.17-6.5 27.59-17.81 36.83c-10.28 8.396-11.78 23.5-3.375 33.74c4.719 5.806 11.62 8.802 18.56 8.802c5.344 0 10.75-1.779 15.19-5.399C435.1 311.5 448 284.6 448 255.1S435.1 200.4 412.6 182zM473.1 108.2c-10.22-8.334-25.34-6.898-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C476.6 172.1 496 213.3 496 255.1s-19.44 82.1-53.31 110.7c-10.25 8.396-11.75 23.5-3.344 33.74c4.75 5.775 11.62 8.771 18.56 8.771c5.375 0 10.75-1.779 15.22-5.431C518.2 366.9 544 313 544 255.1S518.2 145 473.1 108.2zM534.4 33.4c-10.22-8.334-25.34-6.867-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C559.9 116.3 592 183.9 592 255.1s-32.09 139.7-88.06 185.5c-10.25 8.396-11.75 23.5-3.344 33.74C505.3 481 512.2 484 519.2 484c5.375 0 10.75-1.779 15.22-5.431C601.5 423.6 640 342.5 640 255.1S601.5 88.34 534.4 33.4zM301.2 34.98c-11.5-5.181-25.01-3.076-34.43 5.29L131.8 160.1H48c-26.51 0-48 21.48-48 47.96v95.92c0 26.48 21.49 47.96 48 47.96h83.84l134.9 119.8C272.7 477 280.3 479.8 288 479.8c4.438 0 8.959-.9314 13.16-2.835C312.7 471.8 320 460.4 320 447.9V64.12C320 51.55 312.7 40.13 301.2 34.98z", viewbox: "0 0 640 512", **options) svg_icon_tag("sound-icon", "M412.6 182c-10.28-8.334-25.41-6.867-33.75 3.402c-8.406 10.24-6.906 25.35 3.375 33.74C393.5 228.4 400 241.8 400 255.1c0 14.17-6.5 27.59-17.81 36.83c-10.28 8.396-11.78 23.5-3.375 33.74c4.719 5.806 11.62 8.802 18.56 8.802c5.344 0 10.75-1.779 15.19-5.399C435.1 311.5 448 284.6 448 255.1S435.1 200.4 412.6 182zM473.1 108.2c-10.22-8.334-25.34-6.898-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C476.6 172.1 496 213.3 496 255.1s-19.44 82.1-53.31 110.7c-10.25 8.396-11.75 23.5-3.344 33.74c4.75 5.775 11.62 8.771 18.56 8.771c5.375 0 10.75-1.779 15.22-5.431C518.2 366.9 544 313 544 255.1S518.2 145 473.1 108.2zM534.4 33.4c-10.22-8.334-25.34-6.867-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C559.9 116.3 592 183.9 592 255.1s-32.09 139.7-88.06 185.5c-10.25 8.396-11.75 23.5-3.344 33.74C505.3 481 512.2 484 519.2 484c5.375 0 10.75-1.779 15.22-5.431C601.5 423.6 640 342.5 640 255.1S601.5 88.34 534.4 33.4zM301.2 34.98c-11.5-5.181-25.01-3.076-34.43 5.29L131.8 160.1H48c-26.51 0-48 21.48-48 47.96v95.92c0 26.48 21.49 47.96 48 47.96h83.84l134.9 119.8C272.7 477 280.3 479.8 288 479.8c4.438 0 8.959-.9314 13.16-2.835C312.7 471.8 320 460.4 320 447.9V64.12C320 51.55 312.7 40.13 301.2 34.98z", viewbox: "0 0 640 512", **options)

View File

@@ -308,19 +308,19 @@ Post.initialize_excerpt = function() {
$("#excerpt").hide(); $("#excerpt").hide();
$("#show-posts-link").on("click.danbooru", function(e) { $("#show-posts-link").on("click.danbooru", function(e) {
$("#show-posts-link").parent("li").addClass("active"); $("#show-posts-link").addClass("active");
$("#show-excerpt-link").parent("li").removeClass("active"); $("#show-excerpt-link").removeClass("active");
$("#posts").show(); $("#posts").show();
$("#excerpt").hide(); $("#excerpt").hide();
e.preventDefault(); e.preventDefault();
}); });
$("#show-excerpt-link").on("click.danbooru", function(e) { $("#show-excerpt-link").on("click.danbooru", function(e) {
if ($(this).parent("li").hasClass("active")) { if ($(this).hasClass("active")) {
return; return;
} }
$("#show-posts-link").parent("li").removeClass("active"); $("#show-posts-link").removeClass("active");
$("#show-excerpt-link").parent("li").addClass("active"); $("#show-excerpt-link").addClass("active");
$("#posts").hide(); $("#posts").hide();
$("#excerpt").show(); $("#excerpt").show();
e.preventDefault(); e.preventDefault();
@@ -411,8 +411,9 @@ Post.update = async function(post_id, mode, params) {
let urlParams = new URLSearchParams(window.location.search); let urlParams = new URLSearchParams(window.location.search);
let view = urlParams.get("view"); let view = urlParams.get("view");
let size = urlParams.get("size");
await $.ajax({ type: "PUT", url: `/posts/${post_id}.js?mode=${mode}&view=${view}`, data: params }); await $.ajax({ type: "PUT", url: `/posts/${post_id}.js?mode=${mode}&view=${view}&size=${size}`, data: params });
Post.pending_update_count -= 1; Post.pending_update_count -= 1;
Post.show_pending_update_notice(); Post.show_pending_update_notice();

View File

@@ -171,10 +171,10 @@ ul.list-inline {
} }
.mobile-only { .mobile-only {
display: none; display: none !important;
@media (max-width: 660px) { display: initial; } @media (max-width: 660px) { display: initial !important; }
} }
.desktop-only { .desktop-only {
@media (max-width: 660px) { display: none; } @media (max-width: 660px) { display: none !important; }
} }

View File

@@ -12,6 +12,7 @@ $spacer: 0.25rem; /* 4px */
.font-monospace { font: var(--monospace-font); } .font-monospace { font: var(--monospace-font); }
.font-bold { font-weight: bold; } .font-bold { font-weight: bold; }
.hidden { display: none !important; }
.inline-block { display: inline-block; } .inline-block { display: inline-block; }
.block { display: block; } .block { display: block; }
.flex { display: flex; } .flex { display: flex; }
@@ -44,6 +45,7 @@ $spacer: 0.25rem; /* 4px */
.rounded-sm { border-radius: 0.5 * $spacer; } .rounded-sm { border-radius: 0.5 * $spacer; }
.rounded { border-radius: 1.0 * $spacer; } .rounded { border-radius: 1.0 * $spacer; }
.m-0 { margin: 0; }
.m-px { margin: 1px; } .m-px { margin: 1px; }
.m-0\.5 { margin: 0.5 * $spacer; } .m-0\.5 { margin: 0.5 * $spacer; }
@@ -62,6 +64,8 @@ $spacer: 0.25rem; /* 4px */
.ml-4 { margin-left: 4 * $spacer; } .ml-4 { margin-left: 4 * $spacer; }
.p-0 { padding: 0; }
.p-px { padding: 1px; }
.p-0\.5 { padding: 0.5 * $spacer; } .p-0\.5 { padding: 0.5 * $spacer; }
.p-4 { padding: 4 * $spacer; } .p-4 { padding: 4 * $spacer; }
@@ -80,6 +84,9 @@ $spacer: 0.25rem; /* 4px */
.space-y-4 > * + * { margin-top: 4 * $spacer; } .space-y-4 > * + * { margin-top: 4 * $spacer; }
.gap-1 { gap: 1 * $spacer; } .gap-1 { gap: 1 * $spacer; }
.gap-2 { gap: 2 * $spacer; }
.gap-3 { gap: 3 * $spacer; }
.gap-4 { gap: 4 * $spacer; }
.divide-y-1 > * + * { border-top: 1px solid var(--divider-border-color); } .divide-y-1 > * + * { border-top: 1px solid var(--divider-border-color); }
@@ -88,6 +95,7 @@ $spacer: 0.25rem; /* 4px */
.flex-1 { flex: 1 1 0%; } .flex-1 { flex: 1 1 0%; }
.flex-auto { flex: 1 1 auto; } .flex-auto { flex: 1 1 auto; }
.flex-grow-1 { flex-grow: 1; }
.items-center { align-items: center; } .items-center { align-items: center; }
.justify-center { justify-content: center; } .justify-center { justify-content: center; }

View File

@@ -14,13 +14,13 @@
<span class="iqdb-posts-high-similarity"> <span class="iqdb-posts-high-similarity">
<% @high_similarity_matches.each do |match| %> <% @high_similarity_matches.each do |match| %>
<%= post_preview(match["post"], show_deleted: true, similarity: match["score"], size: true) %> <%= post_preview(match["post"], show_deleted: true, similarity: match["score"], show_size: true) %>
<% end %> <% end %>
</span> </span>
<span class="iqdb-posts-low-similarity" style="display: none"> <span class="iqdb-posts-low-similarity" style="display: none">
<% @low_similarity_matches.each do |match| %> <% @low_similarity_matches.each do |match| %>
<%= post_preview(match["post"], show_deleted: true, similarity: match["score"], size: true) %> <%= post_preview(match["post"], show_deleted: true, similarity: match["score"], show_size: true) %>
<% end %> <% end %>
</span> </span>
</div> </div>

View File

@@ -1,6 +1,6 @@
<%= tag.div id: "post-#{post.id}", **PostPreviewComponent.new(post: post).article_attrs("post mod-queue-preview column-container") do %> <%= tag.div id: "post-#{post.id}", **PostPreviewComponent.new(post: post).article_attrs("post mod-queue-preview column-container") do %>
<aside class="column column-shrink"> <aside class="column column-shrink">
<%= post_preview(post, size: true, show_deleted: true) %> <%= post_preview(post, show_size: true, show_deleted: true) %>
</aside> </aside>
<section class="column column-expand"> <section class="column column-expand">

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?, search_params: { view: params[:view] }) %> <%= 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], size: params[:size] }) %>
</section> </section>
<%= render "posts/partials/index/options" %> <%= render "posts/partials/index/options" %>
@@ -16,34 +16,91 @@
<% end %> <% end %>
<% content_for(:content) do %> <% content_for(:content) do %>
<menu id="post-sections" class="mb-4 space-x-2"> <menu id="post-sections" class="flex">
<li class="active"><a href="#" id="show-posts-link">Posts</a></li> <li class="flex-grow-1 space-x-2">
<a href="#" id="show-posts-link" class="active">Posts</a>
<% if @post_set.artist.present? %> <% if @post_set.artist.present? %>
<li class="artist-excerpt-link"><%= link_to "Artist", artist_path(@post_set.artist), :id => "show-excerpt-link" %></li> <%= link_to "Artist", artist_path(@post_set.artist), id: "show-excerpt-link", class: "artist-excerpt-link" %>
<% elsif @post_set.wiki_page.present? %> <% elsif @post_set.wiki_page.present? %>
<li class="wiki-excerpt-link"><%= link_to "Wiki", wiki_page_path(@post_set.wiki_page), :id => "show-excerpt-link" %></li> <%= link_to "Wiki", wiki_page_path(@post_set.wiki_page), id: "show-excerpt-link", class: "wiki-excerpt-link" %>
<% elsif @post_set.pool.present? %> <% elsif @post_set.pool.present? %>
<li class="pool-excerpt-link"><%= link_to "Pool", pool_path(@post_set.pool), :id => "show-excerpt-link" %></li> <%= link_to "Pool", pool_path(@post_set.pool), id: "show-excerpt-link", class: "pool-excerpt-link" %>
<% elsif @post_set.favgroup.present? %> <% elsif @post_set.favgroup.present? %>
<li class="favgroup-excerpt-link"><%= link_to "Favorite Group", favorite_group_path(@post_set.favgroup), :id => "show-excerpt-link" %></li> <%= link_to "Favorite Group", favorite_group_path(@post_set.favgroup), id: "show-excerpt-link", class: "favgroup-excerpt-link" %>
<% elsif @post_set.has_blank_wiki? %> <% elsif @post_set.has_blank_wiki? %>
<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> <%= link_to "Wiki", new_wiki_page_path(wiki_page: { title: @post_set.tag.name }), id: "show-excerpt-link", class: "blank-wiki-excerpt-link" %>
<% 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], page: params[:page], limit: params[:limit], view: nil), rel: "nofollow" %>
<% else %>
<%= link_to "Show scores", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: "score"), rel: "nofollow" %>
<% end %>
<% end %>
<% end %> <% end %>
<a class="mobile-only" href="#search-box">Search &raquo;</a>
</li> </li>
<li id="searchbox-redirect-link" class="mobile-only"><a href="#search-box">Search &raquo;</a></li> <%= render PopupMenuComponent.new(classes: "hidden") do |menu| %>
<% menu.button do %>
<span class="text-sm">Size <%= caret_down_icon %></span>
<% end %>
<% menu.item do %>
<% if params.fetch(:size, PostPreviewComponent::DEFAULT_SIZE) == "150" %>
<%= link_to "Small", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "150"), class: "font-bold", rel: "nofollow" %>
<% else %>
<%= link_to "Small", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "150"), rel: "nofollow" %>
<% end %>
<% end %>
<% menu.item do %>
<% if params.fetch(:size, PostPreviewComponent::DEFAULT_SIZE) == "180" %>
<%= link_to "Medium", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "180"), class: "font-bold", rel: "nofollow" %>
<% else %>
<%= link_to "Medium", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "180"), rel: "nofollow" %>
<% end %>
<% end %>
<% menu.item do %>
<% if params.fetch(:size, PostPreviewComponent::DEFAULT_SIZE) == "225" %>
<%= link_to "Large", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "225"), class: "font-bold", rel: "nofollow" %>
<% else %>
<%= link_to "Large", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "225"), rel: "nofollow" %>
<% end %>
<% end %>
<%# Mobile only %>
<% menu.item do %>
<% if params.fetch(:size, PostPreviewComponent::DEFAULT_SIZE) == "360" %>
<%= link_to "Huge", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "360"), class: "mobile-only font-bold", rel: "nofollow" %>
<% else %>
<%= link_to "Huge", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "360"), class: "mobile-only", rel: "nofollow" %>
<% end %>
<% end %>
<%# Desktop only %>
<% menu.item do %>
<% if params.fetch(:size, PostPreviewComponent::DEFAULT_SIZE) == "270" %>
<%= link_to "Huge", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "270"), class: "desktop-only font-bold", rel: "nofollow" %>
<% else %>
<%= link_to "Huge", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "270"), class: "desktop-only", rel: "nofollow" %>
<% end %>
<% end %>
<%# Desktop only %>
<% menu.item do %>
<% if params.fetch(:size, PostPreviewComponent::DEFAULT_SIZE) == "360" %>
<%= link_to "Gigantic", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "360"), class: "desktop-only font-bold", rel: "nofollow" %>
<% else %>
<%= link_to "Gigantic", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: params[:view], size: "360"), class: "desktop-only", rel: "nofollow" %>
<% end %>
<% end %>
<% end %>
<%= render PopupMenuComponent.new do |menu| %>
<% menu.item do %>
<% if params[:view] == "score" %>
<%= link_to "Hide scores", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: nil, size: params[:size]), rel: "nofollow" %>
<% else %>
<%= link_to "Show scores", posts_path(tags: params[:tags], page: params[:page], limit: params[:limit], view: "score", size: params[:size]), rel: "nofollow" %>
<% end %>
<% end %>
<% end %>
</menu> </menu>
<%= render "posts/partials/index/edit" %> <%= render "posts/partials/index/edit" %>

View File

@@ -2,7 +2,7 @@
<% if post_set.shown_posts.empty? %> <% if post_set.shown_posts.empty? %>
<%= render "post_sets/blank" %> <%= render "post_sets/blank" %>
<% else %> <% else %>
<%= render_post_gallery(post_set.posts, show_deleted: post_set.show_deleted?, tags: post_set.tag_string, show_votes: post_set.show_votes?) do |gallery| %> <%= render_post_gallery(post_set.posts, show_deleted: post_set.show_deleted?, tags: post_set.tag_string, show_votes: post_set.show_votes?, size: params[:size]) do |gallery| %>
<% gallery.footer do %> <% gallery.footer do %>
<% if post_set.hidden_posts.present? %> <% if post_set.hidden_posts.present? %>
<div class="fineprint hidden-posts-notice"> <div class="fineprint hidden-posts-notice">

View File

@@ -1,6 +1,6 @@
<% if @post.valid? %> <% if @post.valid? %>
var $post = $("#post_<%= @post.id %>"); var $post = $("#post_<%= @post.id %>");
var $new_post = $("<%= j post_preview(@post, show_deleted: true, show_votes: params[:view] == "score") %>"); var $new_post = $("<%= j post_preview(@post, show_deleted: true, show_votes: params[:view] == "score", size: params[:size]) %>");
Danbooru.Blacklist.apply_post($new_post.get(0)); Danbooru.Blacklist.apply_post($new_post.get(0));
$("#post_<%= @post.id %>").replaceWith($new_post); $("#post_<%= @post.id %>").replaceWith($new_post);
<% if params[:mode] == "quick-edit" %> <% if params[:mode] == "quick-edit" %>

View File

@@ -10,7 +10,7 @@
<div> <div>
<% source.related_posts.each do |post| %> <% source.related_posts.each do |post| %>
<%= post_preview(post, show_deleted: true, size: true) %> <%= post_preview(post, show_deleted: true, show_size: true) %>
<% end %> <% end %>
</div> </div>
</div> </div>