Here, we add loading skeletons to lots of individual elements, instead of doing a whole item placeholder skeleton. That helps when coming from pages where we have some data, like name and thumbnail, but things is isNc are still missing.
It looks nice, but also particularly means we can handle the loading for the preview separately, get that started faster and iterate better on it in dev!
Initially the spinner was only used in OutfitPreview, where the background was always pretty dark. Now that we use it in more general contexts, we need a light/dark distinction!
Also went and standardized out the `size` props
Here, we extract a lean WardrobePageLayout component, so that we can bundle it into the main app as a loading state for WardrobePage.
This means that clicking Start from the homepage will, instead of flashing the screen to white while WardrobePage loads, show the correctly-sized black/white page layout instead.
I think the Chakra upgrades made these overrides stop working? added !important so that they happen again!
The regression meant the homepage looked worse, always having the selects fade in :/
This is a new field I just added manually:
```
ALTER TABLE items ADD COLUMN modeling_status_hint ENUM('done', 'glitchy');
```
Done means it's actually done being modeled, despite the heuristics telling us otherwise. And glitchy means there's DTI issues that prevent us from making progress on it.
I'm using my first ever MySQL Store Procedure for clever cleverness in caching the modeling query!
I realized that checking for the latest contribution timestamp is a pretty reliable way of deciding when modeling data was last updated at all. If that timestamp hasn't changed, we can reuse the results!
I figured that, because query roundtrips are a bottleneck in this environment, I didn't want to make that query separately. So, I built a MySQL procedure to do the check on the database side!
I think I got all up in my head about direct queries for this one, because of a previous implementation I had in mind, and I forgot that I could just query species and color from the cache by reference without breaking out of the API provided to the cache function!
I also learned in here that I _can_ look up things from the root by doing `readField("allSpecies", {__ref: "ROOT_QUERY"})`, which I struggled to figure out my previous time. I couldn't figure out how to read an uncached field with arguments (I couldn't quite figure out how to build a proper FieldNode, and passing the string form seemed to provide `null` to the `species` cache field reader), but it's probably doable!