Compare commits

...

2 commits

Author SHA1 Message Date
d69c37089e 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.
2024-09-06 12:13:10 -07:00
5001a50a60 Add announcement about new item page, replacing the hidden Neopass one 2024-09-06 11:47:17 -07:00
9 changed files with 41 additions and 31 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View file

@ -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) {

View file

@ -135,15 +135,24 @@ 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
.loading-indicator
opacity: 1 &:state(after-first-frame)
transition-delay: 2s .loading-indicator
opacity: 1
transition-delay: 2s
#item-preview:has(outfit-layer:state(error)) #item-preview:has(outfit-layer:state(error))
outfit-viewer outfit-viewer

View file

@ -7,9 +7,8 @@ body.outfits-new
#pet-not-found #pet-not-found
display: none display: none
.neopass-announcement .announcement
border: 1px solid #cd8400 border: 1px solid $module-border-color
color: #764a00
padding: .5em padding: .5em
display: grid display: grid
grid-template-areas: "thumbnail content" grid-template-areas: "thumbnail content"
@ -24,9 +23,6 @@ body.outfits-new
p:last-of-type p:last-of-type
margin-bottom: 0 margin-bottom: 0
a
color: #be7a00
#outfit-forms #outfit-forms
+clearfix +clearfix
+module +module

View file

@ -1,7 +1,7 @@
module OutfitsHelper module OutfitsHelper
LAST_DAY_OF_NEOPASS_ANNOUNCEMENT = Date.parse("2024-05-05") LAST_DAY_OF_ANNOUNCEMENT = Date.parse("2024-09-13")
def show_neopass_announcement? def show_announcement?
Date.today <= LAST_DAY_OF_NEOPASS_ANNOUNCEMENT Date.today <= LAST_DAY_OF_ANNOUNCEMENT
end end
def destination_tag(value) def destination_tag(value)

View file

@ -4,26 +4,27 @@
%p#pet-not-found.alert= t 'pets.load.not_found' %p#pet-not-found.alert= t 'pets.load.not_found'
- if show_neopass_announcement? - if show_announcement?
%section.neopass-announcement %section.announcement
= image_tag "about/neopass-survey.png", width: 70, height: 70, = image_tag "about/announcement.png", width: 70, height: 70,
srcset: {"about/neopass-survey@2x.png": "2x"}, srcset: {"about/announcement@2x.png": "2x"},
class: "neopass-thumbnail" class: "neopass-thumbnail"
.neopass-content .content
%p %p
%strong %strong
💭 Thank you for sending us your NeoPass feedback! = link_to "We've updated the item page!",
item_path("37002-Floating-Negg-Faerie-Doll")
It should load faster, work better on phones, and be more reliable—no
more "failed to fetch"! Please try it out and let us know if it does
anything weird!!
%p %p{style: "font-style: italic; opacity: .85; font-size: 85%"}
We're working with TNT now to build new integrations, based on what you By the way, our integration work with TNT is on pause while they focus
told us! We're glad on the
= link_to "log in with NeoPass", about_neopass_path = link_to "~Void Within plot~!", "https://www.neopets.com/tvw/",
is working well, and we're excited to do the next part! More info soon! target: "_blank", style: "color: purple; font-weight: bold"
%p
Thanks again to everyone for helping us out! We're grateful, as always 💖
%br %br
%em —Matchu We'll start it back up closer to the new year.
#outfit-forms #outfit-forms
- localized_cache :action_suffix => 'outfit_forms_intro' do - localized_cache :action_suffix => 'outfit_forms_intro' do