Emi Matchu
4c44f8d6a4
Here, I remember the trick I learned when building the outfit viewer: web components are great for making sure stuff stays initialized well in a Turbo environment! The problem was, after submitting the form and getting a new preview loaded via Turbo, the part where we remove `inert` would get undone. Additionally, this script only loads *once* per session, so if you Turbo-nav to a different item then that part of the page never ran. Instead, we use web components to remove the attributes on mount, then again if they're ever reapplied by Idiomorph.
225 lines
4.8 KiB
Sass
225 lines
4.8 KiB
Sass
@import "../partials/clean/constants"
|
|
@import "../partials/clean/mixins"
|
|
@import "../partials/item_header"
|
|
|
|
body.items-show
|
|
.item-header
|
|
+item-header
|
|
|
|
#item-contributors
|
|
+subtle-banner
|
|
clear: both
|
|
margin:
|
|
bottom: 0
|
|
top: 2em
|
|
|
|
header
|
|
display: inline
|
|
font-weight: bold
|
|
margin-right: .25em
|
|
|
|
footer
|
|
display: inline
|
|
|
|
ul
|
|
display: inline
|
|
list-style: none
|
|
|
|
li
|
|
display: inline
|
|
|
|
&::after
|
|
content: ", "
|
|
|
|
&:last-child::after
|
|
content: "."
|
|
|
|
.nc-icon
|
|
height: 16px
|
|
width: 16px
|
|
|
|
outfit-viewer
|
|
display: block
|
|
position: relative
|
|
width: 300px
|
|
height: 300px
|
|
border: 1px solid $module-border-color
|
|
border-radius: 1em
|
|
overflow: hidden
|
|
margin: 0 auto .75em
|
|
|
|
// There's no useful text in here, but double-clicking the play/pause
|
|
// button can cause a weird selection state. Disable text selection.
|
|
user-select: none
|
|
-webkit-user-select: none
|
|
|
|
outfit-layer
|
|
display: block
|
|
position: absolute
|
|
inset: 0
|
|
|
|
// We disable pointer-events most importantly for the iframes, which
|
|
// will ignore our `cursor: wait` and show a plain cursor for the
|
|
// inside of its own document. But also, the context menus for these
|
|
// elements are kinda actively misleading, too!
|
|
pointer-events: none
|
|
|
|
img, iframe
|
|
width: 100%
|
|
height: 100%
|
|
|
|
.loading-indicator
|
|
position: absolute
|
|
z-index: 1000
|
|
bottom: 0px
|
|
right: 4px
|
|
padding: 8px
|
|
background: radial-gradient(circle closest-side, white 45%, #ffffff00)
|
|
|
|
opacity: 0
|
|
transition: opacity .5s
|
|
|
|
.play-pause-button
|
|
position: absolute
|
|
z-index: 1001
|
|
left: 8px
|
|
bottom: 8px
|
|
display: none
|
|
align-items: center
|
|
justify-content: center
|
|
color: white
|
|
background: rgba(0, 0, 0, 0.64)
|
|
width: 2.5em
|
|
height: 2.5em
|
|
border-radius: 100%
|
|
border: 2px solid transparent
|
|
transition: all .25s
|
|
|
|
.playing-label, .paused-label
|
|
display: none
|
|
width: 1em
|
|
height: 1em
|
|
|
|
.play-pause-toggle
|
|
// Visually hidden
|
|
clip: rect(0 0 0 0)
|
|
clip-path: inset(50%)
|
|
height: 1px
|
|
overflow: hidden
|
|
position: absolute
|
|
white-space: nowrap
|
|
width: 1px
|
|
|
|
&:checked ~ .playing-label
|
|
display: block
|
|
|
|
&:not(:checked) ~ .paused-label
|
|
display: block
|
|
|
|
&:hover, &:has(.play-pause-toggle:focus)
|
|
border: 2px solid $module-border-color
|
|
background: $module-bg-color
|
|
color: $text-color
|
|
|
|
&:has(.play-pause-toggle:active)
|
|
transform: translateY(2px)
|
|
|
|
&:has(outfit-layer:state(has-animations))
|
|
.play-pause-button
|
|
display: flex
|
|
|
|
.error-indicator
|
|
font-size: 85%
|
|
color: $error-color
|
|
margin-top: .25em
|
|
margin-bottom: .5em
|
|
display: none
|
|
|
|
// When loading, fade in the loading spinner after a brief delay. (We only
|
|
// apply the delay here, because fading *out* on load should be instant.)
|
|
// We are loading when the <turbo-frame> is busy, or when at least one layer
|
|
// is loading.
|
|
#item-preview[busy] outfit-viewer, outfit-viewer:has(outfit-layer:state(loading))
|
|
cursor: wait
|
|
.loading-indicator
|
|
opacity: 1
|
|
transition-delay: 2s
|
|
|
|
#item-preview:has(outfit-layer:state(error))
|
|
outfit-viewer
|
|
border: 2px solid red
|
|
.error-indicator
|
|
display: block
|
|
|
|
.species-color-picker
|
|
.error-icon
|
|
cursor: help
|
|
margin-right: .25em
|
|
|
|
&[data-is-valid="false"]
|
|
select
|
|
border-color: $error-border-color
|
|
color: $error-color
|
|
|
|
species-face-picker
|
|
display: block
|
|
position: relative
|
|
|
|
input[type=radio]
|
|
position: absolute
|
|
left: -10000px
|
|
top: auto
|
|
width: 1px
|
|
height: 1px
|
|
overflow: hidden
|
|
|
|
&:not(:checked) + img
|
|
opacity: .5
|
|
|
|
&:disabled + img
|
|
filter: grayscale(1)
|
|
|
|
label:has(input[type=radio]:disabled)
|
|
cursor: not-allowed
|
|
|
|
noscript
|
|
position: absolute
|
|
inset: 0
|
|
background: rgba(white, .75)
|
|
z-index: 1
|
|
cursor: auto
|
|
|
|
display: flex
|
|
align-items: center
|
|
justify-content: center
|
|
text-align: center
|
|
|
|
&:has(species-face-picker-options[inert])
|
|
cursor: wait
|
|
|
|
.item-zones-info
|
|
margin-top: .5em
|
|
|
|
h3
|
|
display: inline
|
|
font: inherit
|
|
font-weight: bold
|
|
&:after
|
|
content: ": "
|
|
|
|
ul
|
|
list-style-type: none
|
|
display: inline
|
|
|
|
li
|
|
display: inline
|
|
&:not(:last-of-type):after
|
|
content: ", "
|
|
|
|
.no-zones
|
|
font-style: italic
|
|
opacity: .85
|
|
|
|
.zone-species-info
|
|
font-style: italic
|
|
text-decoration: underline dotted
|