Fix bug where item preview loading indicator sometimes doesn't delay
The loading indicator *should* fade in after two seconds, to avoid a flash of a loading indicator when the page loads quickly - but in some circumstances it wouldn't delay: 1. Visit an item page. (It delays correctly the first time!) 2. Click "Infinite Closet", then click a link to another item page. 3. The loading indicator appears immediately, because this time the web component JS is already loaded, so the `outfit-layer` elements enter `:state(loading)` *immediately*. The element starts at `opacity: 1`, and the delay doesn't matter, because it was never at anything else. In this change, we have the `outfit-viewer` web component take on a `:state(after-first-frame)`, after a `setTimeout(0)` resolves. That enables the loading state CSS to *never* apply on the first frame, but then sometimes kick in on the *second* frame, so that the element is correctly perceived as "transitioning" from hidden to visible, and the two-second delay will apply.
This commit is contained in:
parent
5001a50a60
commit
d69c37089e
2 changed files with 19 additions and 6 deletions
|
@ -21,6 +21,10 @@ class OutfitViewer extends HTMLElement {
|
||||||
this.#setIsPlaying(playPauseToggle.checked);
|
this.#setIsPlaying(playPauseToggle.checked);
|
||||||
this.#setIsPlayingCookie(playPauseToggle.checked);
|
this.#setIsPlayingCookie(playPauseToggle.checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Tell the CSS our first frame has rendered, which we use for loading
|
||||||
|
// state transitions.
|
||||||
|
this.#internals.states.add("after-first-frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
#setIsPlaying(isPlaying) {
|
#setIsPlaying(isPlaying) {
|
||||||
|
|
|
@ -135,12 +135,21 @@ body.items-show
|
||||||
margin-bottom: .5em
|
margin-bottom: .5em
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
// When loading, fade in the loading spinner after a brief delay. (We only
|
// When loading, fade in the loading spinner after a brief delay. We are
|
||||||
// apply the delay here, because fading *out* on load should be instant.)
|
// loading when the <turbo-frame> is busy, or when at least one layer
|
||||||
// We are loading when the <turbo-frame> is busy, or when at least one layer
|
|
||||||
// is loading.
|
// is loading.
|
||||||
|
//
|
||||||
|
// We only apply the delay here, not on the base styles, because fading
|
||||||
|
// *out* on load should be instant. We also wait for the outfit-viewer to
|
||||||
|
// execute a `setTimeout(0)`, to make sure we always *start* in the
|
||||||
|
// non-loading state. This is because it's sometimes possible for the page to
|
||||||
|
// start with the web component already in `state(loading)`, and we need to
|
||||||
|
// make sure we *start* in *non-loading* state for the transition delay to
|
||||||
|
// happen. (This can happen when you Turbo-navigate between multiple items.)
|
||||||
#item-preview[busy] outfit-viewer, outfit-viewer:has(outfit-layer:state(loading))
|
#item-preview[busy] outfit-viewer, outfit-viewer:has(outfit-layer:state(loading))
|
||||||
cursor: wait
|
cursor: wait
|
||||||
|
|
||||||
|
&:state(after-first-frame)
|
||||||
.loading-indicator
|
.loading-indicator
|
||||||
opacity: 1
|
opacity: 1
|
||||||
transition-delay: 2s
|
transition-delay: 2s
|
||||||
|
|
Loading…
Reference in a new issue