From 4ad554e28b1cecda959a8dbfc9b58fb940ec843c Mon Sep 17 00:00:00 2001 From: evazion Date: Sun, 30 Jan 2022 22:27:07 -0600 Subject: [PATCH] uploads: show videos and ugoiras on upload page. * On the upload page, show the video when uploading a video or ugoira. * On the upload page, show the filesize and resolution beneath the image, instead of above it. * On the media asset show page, show the full video or ugoira instead of just the thumbnail. --- app/components/media_asset_component.rb | 13 +++++ .../media_asset_component.html.erb | 15 +++++ .../media_asset_component.js | 56 +++++++++++++++++++ .../media_asset_component.scss | 11 ++++ app/javascript/packs/application.js | 2 + app/javascript/src/javascripts/uploads.js | 42 -------------- .../src/styles/common/utilities.scss | 6 ++ .../src/styles/specific/uploads.scss | 32 +---------- app/views/media_assets/show.html.erb | 2 +- app/views/uploads/new.html.erb | 2 +- app/views/uploads/show.html.erb | 21 ++++--- test/components/media_asset_component.rb | 45 +++++++++++++++ 12 files changed, 161 insertions(+), 86 deletions(-) create mode 100644 app/components/media_asset_component.rb create mode 100644 app/components/media_asset_component/media_asset_component.html.erb create mode 100644 app/components/media_asset_component/media_asset_component.js create mode 100644 app/components/media_asset_component/media_asset_component.scss create mode 100644 test/components/media_asset_component.rb diff --git a/app/components/media_asset_component.rb b/app/components/media_asset_component.rb new file mode 100644 index 000000000..dc60d4752 --- /dev/null +++ b/app/components/media_asset_component.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# A component for showing a full-sized image or video for a media asset. +class MediaAssetComponent < ApplicationComponent + attr_reader :media_asset + + delegate :image_width, :image_height, :variant, :is_image?, :is_video?, :is_ugoira?, :is_flash?, to: :media_asset + + def initialize(media_asset:) + super + @media_asset = media_asset + end +end diff --git a/app/components/media_asset_component/media_asset_component.html.erb b/app/components/media_asset_component/media_asset_component.html.erb new file mode 100644 index 000000000..b618101ee --- /dev/null +++ b/app/components/media_asset_component/media_asset_component.html.erb @@ -0,0 +1,15 @@ +
+ + + <% if is_image? %> + <%= tag.img src: variant(:original).file_url, width: image_width, height: image_height, draggable: "false", class: "media-asset-image select-none" -%> + <% elsif is_video? %> + <%= tag.video src: variant(:original).file_url, width: image_width, height: image_height, autoplay: true, loop: true, controls: "controls" %> + <% elsif is_ugoira? %> + <%= tag.video src: variant(:sample).file_url, width: image_width, height: image_height, autoplay: true, loop: true, controls: "controls" %> + <% elsif is_flash? %> + <%= tag.div class: "ruffle-container", "data-swf": variant(:original).file_url %> + <% end %> +
diff --git a/app/components/media_asset_component/media_asset_component.js b/app/components/media_asset_component/media_asset_component.js new file mode 100644 index 000000000..3abec25e7 --- /dev/null +++ b/app/components/media_asset_component/media_asset_component.js @@ -0,0 +1,56 @@ +export default class MediaAssetComponent { + static initialize() { + $(".media-asset-component").toArray().forEach(element => { + new MediaAssetComponent(element); + }); + } + + constructor(element) { + this.$component = $(element); + + if (this.$image.length) { + this.$image.on("click.danbooru", e => this.toggleFit()); + new ResizeObserver(() => this.updateZoom()).observe(this.$image.get(0)); + this.updateZoom(); + } + } + + toggleFit() { + this.$component.toggleClass("fit-screen"); + this.updateZoom(); + } + + updateZoom() { + this.$image.removeClass("cursor-zoom-in cursor-zoom-out"); + this.$zoomLevel.addClass("hidden").text(`${Math.round(100 * this.zoomLevel)}%`); + + if (this.isDownscaled) { + this.$image.addClass("cursor-zoom-out"); + this.$zoomLevel.removeClass("hidden"); + } else if (this.isTooBig) { + this.$image.addClass("cursor-zoom-in"); + } + } + + get zoomLevel() { + return this.$image.width() / Number(this.$image.attr("width")); + } + + get isDownscaled() { + return this.$image.width() < Number(this.$image.attr("width")); + } + + get isTooBig() { + return this.$image.width() > this.$component.width(); + } + + get $image() { + return this.$component.find(".media-asset-image"); + } + + get $zoomLevel() { + return this.$component.find(".media-asset-zoom-level"); + } +} + +$(MediaAssetComponent.initialize); diff --git a/app/components/media_asset_component/media_asset_component.scss b/app/components/media_asset_component/media_asset_component.scss new file mode 100644 index 000000000..067066dc4 --- /dev/null +++ b/app/components/media_asset_component/media_asset_component.scss @@ -0,0 +1,11 @@ +.media-asset-component.fit-screen img, .media-asset-component.fit-screen video { + max-width: 100%; + max-height: 90vh; + width: auto; + height: auto; +} + +.media-asset-zoom-level { + color: var(--preview-icon-color); + background: var(--preview-icon-background); +} diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index a40a6d6da..c2238ccc6 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -43,6 +43,7 @@ import FileUploadComponent from "../../components/file_upload_component/file_upl import ForumPostComponent from "../../components/forum_post_component/forum_post_component.js"; import IqdbQuery from "../src/javascripts/iqdb_queries.js"; import Note from "../src/javascripts/notes.js"; +import MediaAssetComponent from "../../components/media_asset_component/media_asset_component.js"; import PopupMenuComponent from "../../components/popup_menu_component/popup_menu_component.js"; import Post from "../src/javascripts/posts.js"; import PostModeMenu from "../src/javascripts/post_mode_menu.js"; @@ -68,6 +69,7 @@ Danbooru.FavoritesTooltipComponent = FavoritesTooltipComponent; Danbooru.FileUploadComponent = FileUploadComponent; Danbooru.ForumPostComponent = ForumPostComponent; Danbooru.IqdbQuery = IqdbQuery; +Danbooru.MediaAssetComponent = MediaAssetComponent; Danbooru.Note = Note; Danbooru.PopupMenuComponent = PopupMenuComponent; Danbooru.Post = Post; diff --git a/app/javascript/src/javascripts/uploads.js b/app/javascript/src/javascripts/uploads.js index 87de7422e..44b8cec70 100644 --- a/app/javascript/src/javascripts/uploads.js +++ b/app/javascript/src/javascripts/uploads.js @@ -6,7 +6,6 @@ Upload.IQDB_HIGH_SIMILARITY = 70; Upload.initialize_all = function() { if ($("#c-uploads #a-show").length) { - this.initialize_image(); this.initialize_similar(); $("#toggle-artist-commentary").on("click.danbooru", function(e) { @@ -38,47 +37,6 @@ Upload.initialize_similar = function() { }); } -Upload.initialize_image = function() { - $(document).on("click.danbooru", "#image", Upload.toggle_size); - $(document).on("click.danbooru", "#upload-image-view-small", Upload.view_small); - $(document).on("click.danbooru", "#upload-image-view-large", Upload.view_large); - $(document).on("click.danbooru", "#upload-image-view-full", Upload.view_full); -} - -Upload.view_small = function(e) { - $("#image").addClass("fit-width fit-height"); - $("#a-show").attr("data-image-size", "small"); - e.preventDefault(); -} - -Upload.view_large = function(e) { - $("#image").removeClass("fit-height").addClass("fit-width"); - $("#a-show").attr("data-image-size", "large"); - e.preventDefault(); -} - -Upload.view_full = function(e) { - $("#image").removeClass("fit-width fit-height"); - $("#a-show").attr("data-image-size", "full"); - e.preventDefault(); -} - -Upload.toggle_size = function(e) { - let window_aspect_ratio = $(window).width() / $(window).height(); - let image_aspect_ratio = $("#image").width() / $("#image").height(); - let image_size = $("#a-show").attr("data-image-size"); - - if (image_size === "small" && image_aspect_ratio >= window_aspect_ratio) { - Upload.view_full(e); - } else if (image_size === "small" && image_aspect_ratio < window_aspect_ratio) { - Upload.view_large(e); - } else if (image_size === "large") { - Upload.view_small(e); - } else if (image_size === "full") { - Upload.view_small(e); - } -} - Upload.toggle_commentary = function() { if ($(".artist-commentary").is(":visible")) { $("#toggle-artist-commentary").text("show ยป"); diff --git a/app/javascript/src/styles/common/utilities.scss b/app/javascript/src/styles/common/utilities.scss index 88ae1c377..385d394db 100644 --- a/app/javascript/src/styles/common/utilities.scss +++ b/app/javascript/src/styles/common/utilities.scss @@ -13,6 +13,8 @@ $spacer: 0.25rem; /* 4px */ .font-bold { font-weight: bold; } .cursor-pointer { cursor: pointer; } +.cursor-zoom-in { cursor: zoom-in; } +.cursor-zoom-out { cursor: zoom-out; } .hidden { display: none !important; } .inline-block { display: inline-block; } @@ -36,6 +38,8 @@ $spacer: 0.25rem; /* 4px */ .break-all { word-break: break-all; } .whitespace-nowrap { white-space: nowrap; } +.pointer-events-none { pointer-events: none; } +.select-none { user-select: none; } .leading-none { line-height: 1; } .absolute { position: absolute; } @@ -83,6 +87,7 @@ $spacer: 0.25rem; /* 4px */ .p-0 { padding: 0; } .p-px { padding: 1px; } .p-0\.5 { padding: 0.5 * $spacer; } +.p-1 { padding: 1 * $spacer; } .p-4 { padding: 4 * $spacer; } .px-4 { padding-left: 4 * $spacer; padding-right: 4 * $spacer; } @@ -116,6 +121,7 @@ $spacer: 0.25rem; /* 4px */ .max-h-270px { max-height: 270px; } .max-h-360px { max-height: 360px; } .max-h-720px { max-height: 720px; } +.max-h-screen { max-height: 100vh; } .space-x-1 > * + * { margin-left: 1 * $spacer; } .space-x-2 > * + * { margin-left: 2 * $spacer; } diff --git a/app/javascript/src/styles/specific/uploads.scss b/app/javascript/src/styles/specific/uploads.scss index 33be911bf..10920e39a 100644 --- a/app/javascript/src/styles/specific/uploads.scss +++ b/app/javascript/src/styles/specific/uploads.scss @@ -1,35 +1,5 @@ div#c-uploads { div#a-show { - &[data-image-size="small"] { - #image { - cursor: zoom-in; - } - - a#upload-image-view-small { - font-weight: bold; - } - } - - &[data-image-size="large"] { - #image { - cursor: zoom-out; - } - - a#upload-image-view-large { - font-weight: bold; - } - } - - &[data-image-size="full"] { - #image { - cursor: zoom-out; - } - - a#upload-image-view-full { - font-weight: bold; - } - } - .artist-commentary { margin-top: 1em; } @@ -42,7 +12,7 @@ div#c-uploads { margin-bottom: 2em; } - ul#upload-image-metadata, ul#links { + ul#links { margin-bottom: 1em; } diff --git a/app/views/media_assets/show.html.erb b/app/views/media_assets/show.html.erb index 38d902516..0417d99fc 100644 --- a/app/views/media_assets/show.html.erb +++ b/app/views/media_assets/show.html.erb @@ -2,7 +2,7 @@

Media Asset

- <%= render MediaAssetPreviewComponent.new(media_asset: @media_asset, link_target: @media_asset.variant("original").file_url, save_data: CurrentUser.save_data) %> + <%= render MediaAssetComponent.new(media_asset: @media_asset) %> <% if @post.present? %> diff --git a/app/views/uploads/new.html.erb b/app/views/uploads/new.html.erb index 81c042983..aa9916d33 100644 --- a/app/views/uploads/new.html.erb +++ b/app/views/uploads/new.html.erb @@ -1,5 +1,5 @@
-
+

Upload

diff --git a/app/views/uploads/show.html.erb b/app/views/uploads/show.html.erb index 50d0b1f9b..feefe6522 100644 --- a/app/views/uploads/show.html.erb +++ b/app/views/uploads/show.html.erb @@ -1,5 +1,5 @@
-
+

Upload

<% if @upload.is_pending? || @upload.is_processing? %> @@ -32,17 +32,16 @@ <% @upload_media_asset = @upload.upload_media_assets.first %> <% @media_asset = @upload_media_asset.media_asset %> -

- Size - <%= number_to_human_size(@media_asset.file_size) %> - <%= @media_asset.image_width %>x<%= @media_asset.image_height %> - - (small | large | full) - -

-
- <%= tag.img src: @media_asset.variant("original").file_url, title: "Preview", id: "image", class: "fit-width fit-height", "data-shortcut": "z" %> + <%= render MediaAssetComponent.new(media_asset: @media_asset) %> + +

+ Size + <%= link_to @media_asset.variant(:original).file_url do %> + <%= number_to_human_size(@media_asset.file_size) %> .<%= @media_asset.file_ext %> + <% end %> + (<%= @media_asset.image_width %>x<%= @media_asset.image_height %>) +

<%= render "uploads/related_posts", source: @upload.source_strategy %> diff --git a/test/components/media_asset_component.rb b/test/components/media_asset_component.rb new file mode 100644 index 000000000..c16d85545 --- /dev/null +++ b/test/components/media_asset_component.rb @@ -0,0 +1,45 @@ +require "test_helper" + +class MediaAssetComponentTest < ViewComponent::TestCase + def render_component(media_asset, **options) + render_inline(MediaAssetComponent.new(media_asset: media_asset, **options)) + end + + context "The MediaAssetComponent" do + context "for an image" do + should "render the image" do + media_asset = create(:media_asset, file_ext: "jpg") + node = render_component(media_asset) + + assert_equal(media_asset.variant(:original).file_url, node.css(".media-asset-component img").attr("src").value) + end + end + + context "for a video" do + should "render the video" do + media_asset = create(:media_asset, file_ext: "mp4", duration: 30) + node = render_component(media_asset) + + assert_equal(media_asset.variant(:original).file_url, node.css(".media-asset-component video").attr("src").value) + end + end + + context "for a ugoira" do + should "render the ugoira" do + media_asset = create(:media_asset, file_ext: "zip") + node = render_component(media_asset) + + assert_equal(media_asset.variant(:sample).file_url, node.css(".media-asset-component video").attr("src").value) + end + end + + context "for a flash file" do + should "render the flash" do + media_asset = create(:media_asset, file_ext: "swf") + node = render_component(media_asset) + + assert_equal(media_asset.variant(:original).file_url, node.css(".media-asset-component div.ruffle-container").attr("data-swf").value) + end + end + end +end