From 0a9193aed75b230566da1264d4466de4fd2c2ac3 Mon Sep 17 00:00:00 2001 From: Matchu Date: Mon, 1 Jul 2024 17:59:07 -0700 Subject: [PATCH] Add basic loading tracking to new item page preview The UI for it is just basic for my own testing rn: it sets the preview background to gray while loading, then back to white when done! This uses the new CSS `:has()` selector: we have JS manage the loading state on each layer, then the container just restyles itself based on whether any currently-loading layers are present. --- app/assets/stylesheets/items/_show.sass | 3 +++ app/javascript/item-page.js | 34 +++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/items/_show.sass b/app/assets/stylesheets/items/_show.sass index 26f5dafb..0d866409 100644 --- a/app/assets/stylesheets/items/_show.sass +++ b/app/assets/stylesheets/items/_show.sass @@ -58,6 +58,9 @@ body.items-show width: 100% height: 100% + &:has(.outfit-layer[data-status="loading"]) + background: gray + .species-color-picker .error-icon cursor: help diff --git a/app/javascript/item-page.js b/app/javascript/item-page.js index afc9235c..11ce034a 100644 --- a/app/javascript/item-page.js +++ b/app/javascript/item-page.js @@ -1,2 +1,32 @@ -// eslint-disable-next-line no-console -console.log("OwO!"); +// 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 }, +);