[WV2] Extract species-color-picker component
This commit is contained in:
parent
2dc5505147
commit
14298fafa9
5 changed files with 86 additions and 23 deletions
|
|
@ -24,24 +24,6 @@ document.addEventListener("turbo:frame-missing", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
class SpeciesColorPicker extends HTMLElement {
|
|
||||||
#internals;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.#internals = this.attachInternals();
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
// Listen for changes to auto-submit the form, then tell CSS about it!
|
|
||||||
this.addEventListener("change", this.#handleChange);
|
|
||||||
this.#internals.states.add("auto-loading");
|
|
||||||
}
|
|
||||||
|
|
||||||
#handleChange(e) {
|
|
||||||
this.querySelector("form").requestSubmit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SpeciesFacePicker extends HTMLElement {
|
class SpeciesFacePicker extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
|
@ -109,7 +91,6 @@ class MeasuredContainer extends HTMLElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("species-color-picker", SpeciesColorPicker);
|
|
||||||
customElements.define("species-face-picker", SpeciesFacePicker);
|
customElements.define("species-face-picker", SpeciesFacePicker);
|
||||||
customElements.define("species-face-picker-options", SpeciesFacePickerOptions);
|
customElements.define("species-face-picker-options", SpeciesFacePickerOptions);
|
||||||
customElements.define("measured-container", MeasuredContainer);
|
customElements.define("measured-container", MeasuredContainer);
|
||||||
|
|
|
||||||
28
app/assets/javascripts/species-color-picker.js
Normal file
28
app/assets/javascripts/species-color-picker.js
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* SpeciesColorPicker web component
|
||||||
|
*
|
||||||
|
* Progressive enhancement for species/color picker forms:
|
||||||
|
* - Auto-submits the form when species or color changes (if JS is enabled)
|
||||||
|
* - Shows a submit button as fallback (if JS is disabled or slow to load)
|
||||||
|
* - Uses Custom Element internals API to communicate state to CSS
|
||||||
|
*/
|
||||||
|
class SpeciesColorPicker extends HTMLElement {
|
||||||
|
#internals;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.#internals = this.attachInternals();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
// Listen for changes to auto-submit the form, then tell CSS about it!
|
||||||
|
this.addEventListener("change", this.#handleChange);
|
||||||
|
this.#internals.states.add("auto-loading");
|
||||||
|
}
|
||||||
|
|
||||||
|
#handleChange(e) {
|
||||||
|
this.querySelector("form").requestSubmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("species-color-picker", SpeciesColorPicker);
|
||||||
|
|
@ -59,8 +59,6 @@ body.wardrobe-v2 {
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
form {
|
form {
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
/* Re-enable clicks on the form itself */
|
/* Re-enable clicks on the form itself */
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +95,51 @@ body.wardrobe-v2 {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Submit button: progressive enhancement pattern */
|
||||||
|
/* If JS is disabled, the button is always visible */
|
||||||
|
/* If JS is enabled but slow to load, fade in after 0.75s */
|
||||||
|
/* Once the web component loads, hide the button completely */
|
||||||
|
input[type="submit"] {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
border-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: rgba(255, 255, 255, 0.8);
|
||||||
|
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If JS is enabled, hide the submit button initially with a delay */
|
||||||
|
@media (scripting: enabled) {
|
||||||
|
input[type="submit"] {
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
opacity: 0;
|
||||||
|
animation: fade-in 0.25s forwards;
|
||||||
|
animation-delay: 0.75s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Once auto-loading is ready, hide the submit button completely */
|
||||||
|
&:state(auto-loading) {
|
||||||
|
input[type="submit"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show picker on hover (real hover only, not simulated touch hover) */
|
/* Show picker on hover (real hover only, not simulated touch hover) */
|
||||||
|
|
@ -170,3 +213,13 @@ body.wardrobe-v2 {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -131,4 +131,5 @@
|
||||||
- content_for :javascripts do
|
- content_for :javascripts do
|
||||||
= javascript_include_tag "idiomorph", async: true
|
= javascript_include_tag "idiomorph", async: true
|
||||||
= javascript_include_tag "outfit-viewer", async: true
|
= javascript_include_tag "outfit-viewer", async: true
|
||||||
|
= javascript_include_tag "species-color-picker", async: true
|
||||||
= javascript_include_tag "items/show", async: true
|
= javascript_include_tag "items/show", async: true
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
= javascript_include_tag "application", async: true
|
= javascript_include_tag "application", async: true
|
||||||
= javascript_include_tag "idiomorph", async: true
|
= javascript_include_tag "idiomorph", async: true
|
||||||
= javascript_include_tag "outfit-viewer", async: true
|
= javascript_include_tag "outfit-viewer", async: true
|
||||||
|
= javascript_include_tag "species-color-picker", async: true
|
||||||
= javascript_include_tag "outfits/new_v2", async: true
|
= javascript_include_tag "outfits/new_v2", async: true
|
||||||
%body.wardrobe-v2
|
%body.wardrobe-v2
|
||||||
= turbo_frame_tag "outfit-editor" do
|
= turbo_frame_tag "outfit-editor" do
|
||||||
|
|
@ -32,13 +33,12 @@
|
||||||
= select_tag :color,
|
= select_tag :color,
|
||||||
options_from_collection_for_select(@colors, "id", "human_name",
|
options_from_collection_for_select(@colors, "id", "human_name",
|
||||||
@selected_color&.id),
|
@selected_color&.id),
|
||||||
onchange: "this.form.requestSubmit()",
|
|
||||||
"aria-label": "Pet color"
|
"aria-label": "Pet color"
|
||||||
= select_tag :species,
|
= select_tag :species,
|
||||||
options_from_collection_for_select(@species, "id", "human_name",
|
options_from_collection_for_select(@species, "id", "human_name",
|
||||||
@selected_species&.id),
|
@selected_species&.id),
|
||||||
onchange: "this.form.requestSubmit()",
|
|
||||||
"aria-label": "Pet species"
|
"aria-label": "Pet species"
|
||||||
|
= submit_tag "Go", name: nil
|
||||||
|
|
||||||
-# Preserve item IDs in the URL
|
-# Preserve item IDs in the URL
|
||||||
- if params[:objects].present?
|
- if params[:objects].present?
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue