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).
This commit is contained in:
parent
d92e3288ab
commit
b3f3b39aa0
4 changed files with 70 additions and 5 deletions
|
@ -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);
|
|
@ -108,3 +108,18 @@ outfit-viewer
|
||||||
|
|
||||||
&:has(outfit-layer:state(loading))
|
&:has(outfit-layer:state(loading))
|
||||||
+outfit-viewer-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
|
||||||
|
|
|
@ -18,14 +18,22 @@ support-outfit-viewer
|
||||||
border-radius: .5em
|
border-radius: .5em
|
||||||
|
|
||||||
th, td
|
th, td
|
||||||
border: 1px solid $soft-border-color
|
border: 1px solid $module-border-color
|
||||||
font-size: .85em
|
font-size: .85em
|
||||||
padding: .25em .5em
|
padding: .25em .5em
|
||||||
text-align: left
|
text-align: left
|
||||||
|
|
||||||
> tbody
|
> tbody
|
||||||
> tr > :nth-child(3) // links column
|
[data-field=links]
|
||||||
ul
|
ul
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
display: flex
|
display: flex
|
||||||
gap: .5em
|
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
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
%tbody
|
%tbody
|
||||||
- outfit.visible_layers.each do |swf_asset|
|
- outfit.visible_layers.each do |swf_asset|
|
||||||
%tr
|
%tr
|
||||||
%th{scope: "row"}
|
%th{scope: "row", "data-field": "id"}
|
||||||
= swf_asset.id
|
= swf_asset.id
|
||||||
%td
|
%td
|
||||||
= swf_asset.zone.label
|
= swf_asset.zone.label
|
||||||
(##{swf_asset.zone.id})
|
(##{swf_asset.zone.id})
|
||||||
%td
|
%td{"data-field": "links"}
|
||||||
%ul
|
%ul
|
||||||
- if swf_asset.image_url?
|
- if swf_asset.image_url?
|
||||||
%li= link_to "PNG", swf_asset.image_url, target: "_blank"
|
%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 "SVG", swf_asset.svg_url, target: "_blank"
|
||||||
%li= link_to "SWF", swf_asset.url, target: "_blank"
|
%li= link_to "SWF", swf_asset.url, target: "_blank"
|
||||||
- if swf_asset.manifest_url?
|
- if swf_asset.manifest_url?
|
||||||
%li= link_to "Manifest", swf_asset.manifest_url, target: "_blank"
|
%li= link_to "Manifest", swf_asset.manifest_url, target: "_blank"
|
||||||
|
|
Loading…
Reference in a new issue