From b3f3b39aa08e125df9a9fbdfdc268d46533143ec Mon Sep 17 00:00:00 2001 From: Emi Matchu Date: Sat, 7 Dec 2024 10:41:52 -0800 Subject: [PATCH] Add helpful layer interactions on pet appearance edit page When you hover the row for a layer in the table, it highlights the corresponding layer in the outfit viewer. And when you click anywhere in the row, it opens the first link (usually the PNG image). --- .../pet_states/support-outfit-viewer.js | 42 +++++++++++++++++++ .../application/outfit-viewer.sass | 15 +++++++ .../pet_states/support-outfit-viewer.sass | 12 +++++- .../_support_outfit_viewer.html.haml | 6 +-- 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/pet_states/support-outfit-viewer.js b/app/assets/javascripts/pet_states/support-outfit-viewer.js index e69de29b..07211ee8 100644 --- a/app/assets/javascripts/pet_states/support-outfit-viewer.js +++ b/app/assets/javascripts/pet_states/support-outfit-viewer.js @@ -0,0 +1,42 @@ +class SupportOutfitViewer extends HTMLElement { + #internals = this.attachInternals(); + + connectedCallback() { + this.addEventListener("mouseenter", this.#onMouseEnter, { capture: true }); + this.addEventListener("mouseleave", this.#onMouseLeave, { capture: true }); + this.addEventListener("click", this.#onClick); + this.#internals.states.add("ready"); + } + + // When a row is hovered, highlight its corresponding outfit viewer layer. + #onMouseEnter(e) { + if (!e.target.matches("tr")) return; + + const id = e.target.querySelector("[data-field=id]").innerText; + const layer = this.querySelector( + `outfit-viewer [data-asset-id="${CSS.escape(id)}"]`, + ); + layer.setAttribute("highlighted", ""); + } + + // When a row is unhovered, unhighlight its corresponding outfit viewer layer. + #onMouseLeave(e) { + if (!e.target.matches("tr")) return; + + const id = e.target.querySelector("[data-field=id]").innerText; + const layer = this.querySelector( + `outfit-viewer [data-asset-id="${CSS.escape(id)}"]`, + ); + layer.removeAttribute("highlighted"); + } + + // When clicking a row, redirect the click to the first link. + #onClick(e) { + const row = e.target.closest("tr"); + if (row == null) return; + + row.querySelector("[data-field=links] a").click(); + } +} + +customElements.define("support-outfit-viewer", SupportOutfitViewer); diff --git a/app/assets/stylesheets/application/outfit-viewer.sass b/app/assets/stylesheets/application/outfit-viewer.sass index 974ab9c1..b3bfa13d 100644 --- a/app/assets/stylesheets/application/outfit-viewer.sass +++ b/app/assets/stylesheets/application/outfit-viewer.sass @@ -108,3 +108,18 @@ outfit-viewer &:has(outfit-layer:state(loading)) +outfit-viewer-loading + + // If a layer has the `[highlighted]` attribute, it's brought to the front, + // and other layers are grayed out and blurred. We use this in the support + // outfit viewer, when you hover over a layer. + &:has(outfit-layer[highlighted]) + outfit-layer[highlighted] + z-index: 999 + + // Filter everything behind the bottom-most highlighted layer, using a + // backdrop filter. This gives us the best visual consistency by applying + // effects to the entire backdrop, instead of each layer and then + // re-compositing them. + backdrop-filter: grayscale(1) brightness(1.5) blur(1px) + & ~ outfit-layer[highlighted] + backdrop-filter: none diff --git a/app/assets/stylesheets/pet_states/support-outfit-viewer.sass b/app/assets/stylesheets/pet_states/support-outfit-viewer.sass index 77def8d3..4624ada6 100644 --- a/app/assets/stylesheets/pet_states/support-outfit-viewer.sass +++ b/app/assets/stylesheets/pet_states/support-outfit-viewer.sass @@ -18,14 +18,22 @@ support-outfit-viewer border-radius: .5em th, td - border: 1px solid $soft-border-color + border: 1px solid $module-border-color font-size: .85em padding: .25em .5em text-align: left > tbody - > tr > :nth-child(3) // links column + [data-field=links] ul list-style-type: none display: flex gap: .5em + + // Once the component is ready, add some hints about potential interactions. + &:state(ready) + > table + > tbody > tr + cursor: zoom-in + &:hover + background: $module-bg-color diff --git a/app/views/pet_states/_support_outfit_viewer.html.haml b/app/views/pet_states/_support_outfit_viewer.html.haml index 1a80ddc4..e9df8126 100644 --- a/app/views/pet_states/_support_outfit_viewer.html.haml +++ b/app/views/pet_states/_support_outfit_viewer.html.haml @@ -9,12 +9,12 @@ %tbody - outfit.visible_layers.each do |swf_asset| %tr - %th{scope: "row"} + %th{scope: "row", "data-field": "id"} = swf_asset.id %td = swf_asset.zone.label (##{swf_asset.zone.id}) - %td + %td{"data-field": "links"} %ul - if swf_asset.image_url? %li= link_to "PNG", swf_asset.image_url, target: "_blank" @@ -22,4 +22,4 @@ %li= link_to "SVG", swf_asset.svg_url, target: "_blank" %li= link_to "SWF", swf_asset.url, target: "_blank" - if swf_asset.manifest_url? - %li= link_to "Manifest", swf_asset.manifest_url, target: "_blank" \ No newline at end of file + %li= link_to "Manifest", swf_asset.manifest_url, target: "_blank"