From 879363b5854ca89d2c03b1ea957515066f39589c Mon Sep 17 00:00:00 2001 From: evazion Date: Sun, 13 Feb 2022 12:27:25 -0600 Subject: [PATCH] media assets: show placeholder thumbnail when image is missing. Make media assets show a placeholder thumbnail when the image is missing. This can happen if the upload is still processing, or if the media asset's image was expunged, or if the asset failed during upload (usually because of some temporary network failure when trying to distribute thumbnails to the backend image servers). Fixes a problem where new images on the My Uploads or All Uploads pages could have broken thumbnails if they were still in the uploading phase. --- .../media_asset_preview_component.rb | 10 ++-- .../media_asset_preview_component.html.erb | 60 ++++++++++++------- .../media_asset_preview_component.scss | 4 ++ app/javascript/src/styles/base/040_colors.css | 4 ++ .../src/styles/common/utilities.scss | 12 ++++ app/views/media_assets/_table.html.erb | 2 +- app/views/uploads/_table.html.erb | 6 +- 7 files changed, 67 insertions(+), 31 deletions(-) diff --git a/app/components/media_asset_preview_component.rb b/app/components/media_asset_preview_component.rb index 243b76f48..c8bb35f7e 100644 --- a/app/components/media_asset_preview_component.rb +++ b/app/components/media_asset_preview_component.rb @@ -5,25 +5,25 @@ class MediaAssetPreviewComponent < ApplicationComponent DEFAULT_SIZE = 180 - attr_reader :media_asset, :size, :fit, :link_target, :shrink_to_fit, :save_data + attr_reader :media_asset, :size, :link_target, :classes, :save_data delegate :duration_to_hhmmss, :sound_icon, to: :helpers + renders_one :header + renders_one :missing_image renders_one :footer # @param media_asset [MediaAsset] The media asset to show the thumbnail for. # @param size [String] The size of the thumbnail. One of 150, 180, 225, 270, or 360. # @param link_target [ApplicationRecord] What the thumbnail links to (default: the media asset). - # @param shrink_to_fit [Boolean] If true, allow the thumbnail to shrink to fit the containing element. - # If false, make the thumbnail a fixed width and height. # @param save_data [Boolean] If true, save data by not serving higher quality thumbnails # on 2x pixel density displays. Default: false. - def initialize(media_asset:, size: DEFAULT_SIZE, link_target: media_asset, shrink_to_fit: true, save_data: CurrentUser.save_data) + def initialize(media_asset:, size: DEFAULT_SIZE, link_target: media_asset, classes: [], save_data: CurrentUser.save_data) super @media_asset = media_asset @size = size.presence&.to_i || DEFAULT_SIZE @link_target = link_target + @classes = classes @save_data = save_data - @shrink_to_fit = shrink_to_fit end def variant diff --git a/app/components/media_asset_preview_component/media_asset_preview_component.html.erb b/app/components/media_asset_preview_component/media_asset_preview_component.html.erb index b13dd9777..daaea96f6 100644 --- a/app/components/media_asset_preview_component/media_asset_preview_component.html.erb +++ b/app/components/media_asset_preview_component/media_asset_preview_component.html.erb @@ -1,28 +1,44 @@ -<%= tag.article class: "media-asset-preview media-asset-preview-#{size}" do -%> - <%= link_to link_target, class: "inline-block relative flex justify-center", draggable: "false" do -%> - <% if media_asset.is_animated? %> -
- - <%= duration_to_hhmmss(media_asset.duration) %> - -
- <% end %> +<%= tag.article class: ["media-asset-preview media-asset-preview-#{size}", *classes] do -%> + <%= link_to link_target, class: "inline-block relative", draggable: "false" do -%> + <%= header %> - - <% unless save_data %> - <% case size %> - <% when 150, 180 %> - <%= tag.source type: "image/jpeg", srcset: "#{media_asset.variant("180x180").file_url} 1x, #{media_asset.variant("360x360").file_url} 2x" %> - <% when 225, 270, 360 %> - <%= tag.source type: "image/webp", srcset: "#{media_asset.variant("360x360").file_url} 1x, #{media_asset.variant("720x720").file_url} 2x" %> - <% end %> + <% if media_asset.nil? %> +
+ <%= missing_image || "No image" %> +
+ <% elsif media_asset.active? %> + <% if media_asset.is_animated? %> +
+ + <%= duration_to_hhmmss(media_asset.duration) %> + +
<% end %> - <%= tag.img src: variant.file_url, width: variant.width, height: variant.height, class: "media-asset-preview-image w-auto h-auto max-h-#{size}px #{"max-w-full" if shrink_to_fit}", crossorigin: "anonymous", draggable: "false" -%> -
+ + <% unless save_data %> + <% case size %> + <% when 150, 180 %> + <%= tag.source type: "image/jpeg", srcset: "#{media_asset.variant("180x180").file_url} 1x, #{media_asset.variant("360x360").file_url} 2x" %> + <% when 225, 270, 360 %> + <%= tag.source type: "image/webp", srcset: "#{media_asset.variant("360x360").file_url} 1x, #{media_asset.variant("720x720").file_url} 2x" %> + <% end %> + <% end %> + + <%= tag.img src: variant.file_url, width: variant.width, height: variant.height, class: "media-asset-preview-image w-auto h-auto max-h-#{size}px max-w-full", crossorigin: "anonymous", draggable: "false" -%> + + <% else %> +
+ <% if media_asset.processing? %> + Loading + <% elsif media_asset.failed? %> + Failed + <% else %> + Deleted + <% end %> +
+ <% end %> <% end %> -
- <%= footer %> -
+ <%= footer %> <% end %> diff --git a/app/components/media_asset_preview_component/media_asset_preview_component.scss b/app/components/media_asset_preview_component/media_asset_preview_component.scss index 3288e8bd7..0e57de337 100644 --- a/app/components/media_asset_preview_component/media_asset_preview_component.scss +++ b/app/components/media_asset_preview_component/media_asset_preview_component.scss @@ -2,3 +2,7 @@ color: var(--preview-icon-color); background: var(--preview-icon-background); } + +.media-asset-placeholder { + background-color: var(--media-asset-placeholder-background-color); +} diff --git a/app/javascript/src/styles/base/040_colors.css b/app/javascript/src/styles/base/040_colors.css index cfc700211..c46846baa 100644 --- a/app/javascript/src/styles/base/040_colors.css +++ b/app/javascript/src/styles/base/040_colors.css @@ -163,6 +163,8 @@ html { --preview-icon-color: var(--inverse-text-color); --preview-icon-background: rgba(0, 0, 0, 0.7); + --media-asset-placeholder-background-color: var(--grey-1); + --modqueue-tag-warning-color: var(--red-1); --file-upload-component-background-color: var(--body-background-color); @@ -374,6 +376,8 @@ body[data-current-user-theme="dark"] { --preview-has-parent-color: var(--orange-3); --preview-selected-color: rgba(255, 255, 255, 0.25); + --media-asset-placeholder-background-color: var(--grey-8); + --modqueue-tag-warning-color: var(--red-7); --file-upload-component-background-color: var(--grey-8); diff --git a/app/javascript/src/styles/common/utilities.scss b/app/javascript/src/styles/common/utilities.scss index 2ffaa408d..b2e4c3333 100644 --- a/app/javascript/src/styles/common/utilities.scss +++ b/app/javascript/src/styles/common/utilities.scss @@ -116,10 +116,17 @@ $spacer: 0.25rem; /* 4px */ .pr-4 { padding-right: 4 * $spacer; } .w-auto { width: auto; } +.w-min { width: min-content; } +.w-max { width: max-content; } .w-sm { width: 24rem; } .w-md { width: 28rem; } .w-1\/4 { width: 25%; } .w-full { width: 100%; } +.w-150px { width: 150px; } +.w-180px { width: 180px; } +.w-225px { width: 225px; } +.w-270px { width: 270px; } +.w-360px { width: 360px; } .max-w-full { max-width: 100%; } @@ -130,6 +137,11 @@ $spacer: 0.25rem; /* 4px */ .h-8 { height: 8 * $spacer; } .h-10 { height: 10 * $spacer; } .h-12 { height: 12 * $spacer; } +.h-150px { height: 150px; } +.h-180px { height: 180px; } +.h-225px { height: 225px; } +.h-270px { height: 270px; } +.h-360px { height: 360px; } .max-h-150px { max-height: 150px; } .max-h-180px { max-height: 180px; } diff --git a/app/views/media_assets/_table.html.erb b/app/views/media_assets/_table.html.erb index eb444b80b..f9334821a 100644 --- a/app/views/media_assets/_table.html.erb +++ b/app/views/media_assets/_table.html.erb @@ -1,7 +1,7 @@ <%= table_for @media_assets, class: "striped autofit" do |t| %> <% t.column "File", td: { class: "text-center" } do |media_asset| %> <% if policy(media_asset).can_see_image? %> - <%= render MediaAssetPreviewComponent.new(media_asset: media_asset, save_data: CurrentUser.save_data, shrink_to_fit: false) %> + <%= render MediaAssetPreviewComponent.new(media_asset: media_asset, save_data: CurrentUser.save_data) %> <% end %> <% end %> diff --git a/app/views/uploads/_table.html.erb b/app/views/uploads/_table.html.erb index 033ac407e..186e6a85d 100644 --- a/app/views/uploads/_table.html.erb +++ b/app/views/uploads/_table.html.erb @@ -7,14 +7,14 @@ -<%= table_for @uploads, class: "striped autofit", width: "100%" do |t| %> +<%= table_for @uploads, class: "striped", width: "100%" do |t| %> <% t.column "Upload", td: { class: "text-center" } do |upload| %> <% upload.media_assets.first.tap do |media_asset| %> <% if media_asset.present? %> <% if media_asset.post.present? %> - <%= render MediaAssetPreviewComponent.new(media_asset: media_asset, link_target: media_asset.post, save_data: CurrentUser.save_data, shrink_to_fit: false) %> + <%= render MediaAssetPreviewComponent.new(media_asset: media_asset, link_target: media_asset.post, save_data: CurrentUser.save_data) %> <% else %> - <%= render MediaAssetPreviewComponent.new(media_asset: media_asset, link_target: upload, save_data: CurrentUser.save_data, shrink_to_fit: false) %> + <%= render MediaAssetPreviewComponent.new(media_asset: media_asset, link_target: upload, save_data: CurrentUser.save_data) %> <% end %> <% end %> <% end %>