mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 07:53:49 +08:00
UX: Use dominant color while loading onebox images (#21091)
When we "pull hotlinked images" on onebox images, they are added to the uploads table and their dominant color is calculated. This commit adds the data to the HTML so that it can be used by the client in the same way as non-onebox images. It also adds specific handling to the new `discourse-lazy-videos` plugin.
This commit is contained in:
@ -410,6 +410,7 @@ class CookedPostProcessor
|
|||||||
still_an_image = false
|
still_an_image = false
|
||||||
elsif info&.downloaded? && upload = info&.upload
|
elsif info&.downloaded? && upload = info&.upload
|
||||||
img["src"] = UrlHelper.cook_url(upload.url, secure: @with_secure_uploads)
|
img["src"] = UrlHelper.cook_url(upload.url, secure: @with_secure_uploads)
|
||||||
|
img["data-dominant-color"] = upload.dominant_color(calculate_if_missing: true).presence
|
||||||
img.delete(PrettyText::BLOCKED_HOTLINKED_SRC_ATTR)
|
img.delete(PrettyText::BLOCKED_HOTLINKED_SRC_ATTR)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<div
|
<div
|
||||||
class={{concat-class "video-thumbnail" @videoAttributes.providerName}}
|
class={{concat-class "video-thumbnail" @videoAttributes.providerName}}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
style={{this.thumbnailStyle}}
|
||||||
{{on "click" this.loadEmbed}}
|
{{on "click" this.loadEmbed}}
|
||||||
{{on "keypress" this.loadEmbed}}
|
{{on "keypress" this.loadEmbed}}
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
|
|
||||||
export default class LazyVideo extends Component {
|
export default class LazyVideo extends Component {
|
||||||
@tracked isLoaded = false;
|
@tracked isLoaded = false;
|
||||||
@ -20,4 +21,11 @@ export default class LazyVideo extends Component {
|
|||||||
this.loadEmbed();
|
this.loadEmbed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get thumbnailStyle() {
|
||||||
|
const color = this.args.videoAttributes.dominantColor;
|
||||||
|
if (color?.match(/^[0-9A-Fa-f]+$/)) {
|
||||||
|
return htmlSafe(`background-color: #${color};`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,12 @@ export default function getVideoAttributes(cooked) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = cooked.querySelector("a")?.getAttribute("href");
|
const url = cooked.querySelector("a")?.getAttribute("href");
|
||||||
const thumbnail = cooked.querySelector("img")?.getAttribute("src");
|
const img = cooked.querySelector("img");
|
||||||
|
const thumbnail = img?.getAttribute("src");
|
||||||
|
const dominantColor = img?.dataset?.dominantColor;
|
||||||
const title = cooked.dataset.videoTitle;
|
const title = cooked.dataset.videoTitle;
|
||||||
const providerName = cooked.dataset.providerName;
|
const providerName = cooked.dataset.providerName;
|
||||||
const id = cooked.dataset.videoId;
|
const id = cooked.dataset.videoId;
|
||||||
|
|
||||||
return { url, thumbnail, title, providerName, id };
|
return { url, thumbnail, title, providerName, id, dominantColor };
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ module("Discourse Lazy Videos | Component | lazy-video", function (hooks) {
|
|||||||
title: "15 Sorting Algorithms in 6 Minutes",
|
title: "15 Sorting Algorithms in 6 Minutes",
|
||||||
providerName: "youtube",
|
providerName: "youtube",
|
||||||
id: "kPRA0W1kECg",
|
id: "kPRA0W1kECg",
|
||||||
|
dominantColor: "00ffff",
|
||||||
};
|
};
|
||||||
|
|
||||||
test("displays the correct video title", async function (assert) {
|
test("displays the correct video title", async function (assert) {
|
||||||
@ -26,6 +27,14 @@ module("Discourse Lazy Videos | Component | lazy-video", function (hooks) {
|
|||||||
assert.dom(".icon.youtube-icon").exists();
|
assert.dom(".icon.youtube-icon").exists();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("uses tthe dominant color from the dom", async function (assert) {
|
||||||
|
await render(hbs`<LazyVideo @videoAttributes={{this.attributes}} />`);
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(".video-thumbnail")
|
||||||
|
.hasAttribute("style", "background-color: #00ffff;");
|
||||||
|
});
|
||||||
|
|
||||||
test("loads the iframe when clicked", async function (assert) {
|
test("loads the iframe when clicked", async function (assert) {
|
||||||
await render(hbs`<LazyVideo @videoAttributes={{this.attributes}}/>`);
|
await render(hbs`<LazyVideo @videoAttributes={{this.attributes}}/>`);
|
||||||
assert.dom(".lazy-video-container.video-loaded").doesNotExist();
|
assert.dom(".lazy-video-container.video-loaded").doesNotExist();
|
||||||
|
@ -1080,7 +1080,7 @@ RSpec.describe CookedPostProcessor do
|
|||||||
.returns("<img class='onebox' src='#{image_url}' />")
|
.returns("<img class='onebox' src='#{image_url}' />")
|
||||||
|
|
||||||
post = Fabricate(:post, raw: url)
|
post = Fabricate(:post, raw: url)
|
||||||
upload.update!(url: "https://test.s3.amazonaws.com/something.png")
|
upload.update!(url: "https://test.s3.amazonaws.com/something.png", dominant_color: "00ffff")
|
||||||
|
|
||||||
PostHotlinkedMedia.create!(
|
PostHotlinkedMedia.create!(
|
||||||
url: "//image.com/avatar.png",
|
url: "//image.com/avatar.png",
|
||||||
@ -1094,7 +1094,7 @@ RSpec.describe CookedPostProcessor do
|
|||||||
cpp.post_process_oneboxes
|
cpp.post_process_oneboxes
|
||||||
|
|
||||||
expect(cpp.doc.to_s).to eq(
|
expect(cpp.doc.to_s).to eq(
|
||||||
"<p><img class=\"onebox\" src=\"#{upload.url}\" width=\"100\" height=\"200\"></p>",
|
"<p><img class=\"onebox\" src=\"#{upload.url}\" data-dominant-color=\"00ffff\" width=\"100\" height=\"200\"></p>",
|
||||||
)
|
)
|
||||||
|
|
||||||
upload.destroy!
|
upload.destroy!
|
||||||
@ -1124,7 +1124,10 @@ RSpec.describe CookedPostProcessor do
|
|||||||
.returns("<img class='onebox' src='#{image_url}' />")
|
.returns("<img class='onebox' src='#{image_url}' />")
|
||||||
|
|
||||||
post = Fabricate(:post, raw: url)
|
post = Fabricate(:post, raw: url)
|
||||||
upload.update!(url: "https://test.s3.amazonaws.com/something.png")
|
upload.update!(
|
||||||
|
url: "https://test.s3.amazonaws.com/something.png",
|
||||||
|
dominant_color: "00ffff",
|
||||||
|
)
|
||||||
|
|
||||||
PostHotlinkedMedia.create!(
|
PostHotlinkedMedia.create!(
|
||||||
url: "//image.com/avatar.png",
|
url: "//image.com/avatar.png",
|
||||||
@ -1141,7 +1144,7 @@ RSpec.describe CookedPostProcessor do
|
|||||||
cpp.post_process_oneboxes
|
cpp.post_process_oneboxes
|
||||||
|
|
||||||
expect(cpp.doc.to_s).to eq(
|
expect(cpp.doc.to_s).to eq(
|
||||||
"<p><img class=\"onebox\" src=\"#{cooked_url}\" width=\"100\" height=\"200\"></p>",
|
"<p><img class=\"onebox\" src=\"#{cooked_url}\" data-dominant-color=\"00ffff\" width=\"100\" height=\"200\"></p>",
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user