Compare commits
5 commits
0a9193aed7
...
81a58f8656
Author | SHA1 | Date | |
---|---|---|---|
81a58f8656 | |||
76d2cc6c21 | |||
e9145251a9 | |||
3c415e9cd3 | |||
857812610a |
6 changed files with 45 additions and 48 deletions
31
app/assets/javascripts/outfit-viewer.js
Normal file
31
app/assets/javascripts/outfit-viewer.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
class OutfitLayer extends HTMLElement {
|
||||
#internals;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.#internals = this.attachInternals();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
setTimeout(() => this.#initializeImage(), 0);
|
||||
}
|
||||
|
||||
#initializeImage() {
|
||||
this.image = this.querySelector("img");
|
||||
if (!this.image) {
|
||||
throw new Error(`<outfit-layer> must contain an <img> tag`);
|
||||
}
|
||||
|
||||
this.image.addEventListener("load", () => this.#setStatus("loaded"));
|
||||
this.image.addEventListener("error", () => this.#setStatus("error"));
|
||||
|
||||
this.#setStatus(this.image.complete ? "loaded" : "loading");
|
||||
}
|
||||
|
||||
#setStatus(newStatus) {
|
||||
this.#internals.states.clear();
|
||||
this.#internals.states.add(newStatus);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("outfit-layer", OutfitLayer);
|
|
@ -49,7 +49,7 @@ body.items-show
|
|||
|
||||
margin: 0 auto .75em
|
||||
|
||||
.outfit-layer
|
||||
outfit-layer
|
||||
display: block
|
||||
position: absolute
|
||||
inset: 0
|
||||
|
@ -58,7 +58,7 @@ body.items-show
|
|||
width: 100%
|
||||
height: 100%
|
||||
|
||||
&:has(.outfit-layer[data-status="loading"])
|
||||
&:has(outfit-layer:state(loading))
|
||||
background: gray
|
||||
|
||||
.species-color-picker
|
||||
|
|
|
@ -244,15 +244,5 @@ module ItemsHelper
|
|||
def item_header_user_lists_form_state
|
||||
cookies.fetch("DTIItemPageUserListsFormState", "closed")
|
||||
end
|
||||
|
||||
def outfit_viewer_layers(swf_assets)
|
||||
swf_assets.map { |a| outfit_viewer_layer(a) }.join("\n").html_safe
|
||||
end
|
||||
|
||||
def outfit_viewer_layer(swf_asset)
|
||||
content_tag :div, class: "outfit-layer" do
|
||||
image_tag swf_asset.image_url, alt: ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
// When we load in a new preview, set the status on the images. We use this in
|
||||
// our CSS to show a loading state when needed.
|
||||
function setImageStatuses() {
|
||||
for (const layer of document.querySelectorAll(".outfit-layer")) {
|
||||
const isLoaded = layer.querySelector("img").complete;
|
||||
layer.setAttribute("data-status", isLoaded ? "loaded" : "loading");
|
||||
}
|
||||
}
|
||||
document.addEventListener("turbo:frame-render", () => setImageStatuses());
|
||||
document.addEventListener("turbo:load", () => setImageStatuses());
|
||||
|
||||
// When a preview image loads or fails, update its status. (Note that `load`
|
||||
// does not fire for images that were loaded from cache, which is why we need
|
||||
// both this and `setImageStatuses` when rendering new images!)
|
||||
document.addEventListener(
|
||||
"load",
|
||||
({ target }) => {
|
||||
if (target.matches(".outfit-layer img")) {
|
||||
target.closest(".outfit-layer").setAttribute("data-status", "loaded");
|
||||
}
|
||||
},
|
||||
{ capture: true },
|
||||
);
|
||||
document.addEventListener(
|
||||
"error",
|
||||
({ target }) => {
|
||||
if (target.matches(".outfit-layer img")) {
|
||||
target.closest(".outfit-layer").setAttribute("data-status", "error");
|
||||
}
|
||||
},
|
||||
{ capture: true },
|
||||
);
|
9
app/views/items/_outfit_viewer.html.haml
Normal file
9
app/views/items/_outfit_viewer.html.haml
Normal file
|
@ -0,0 +1,9 @@
|
|||
.outfit-viewer
|
||||
- outfit.visible_layers.each do |swf_asset|
|
||||
%outfit-layer{
|
||||
data: {
|
||||
"asset-id": swf_asset.id,
|
||||
"zone": swf_asset.zone.label,
|
||||
},
|
||||
}
|
||||
= image_tag swf_asset.image_url, alt: ""
|
|
@ -14,8 +14,7 @@
|
|||
sorry!
|
||||
|
||||
= turbo_frame_tag "item-preview" do
|
||||
.outfit-viewer
|
||||
= outfit_viewer_layers @preview_outfit.visible_layers
|
||||
= render partial: "outfit_viewer", locals: {outfit: @preview_outfit}
|
||||
|
||||
= form_for item_path(@item), method: :get, class: "species-color-picker",
|
||||
data: {"is-valid": @preview_error.nil?} do |f|
|
||||
|
@ -40,6 +39,6 @@
|
|||
%li= link_to(contributor.name, user_contributions_path(contributor)) + format_contribution_count(count)
|
||||
%footer= t '.contributors.footer'
|
||||
|
||||
- content_for :javascripts_body do
|
||||
= javascript_include_tag 'item-page', defer: true
|
||||
- content_for :javascripts do
|
||||
= javascript_include_tag 'outfit-viewer', async: true
|
||||
|
||||
|
|
Loading…
Reference in a new issue