product options layout and add to cart button in homepage

This commit is contained in:
elvira
2026-09-21 18:53:45 +03:00
parent af0245de43
commit a107184010
10 changed files with 225 additions and 537 deletions
@@ -16,13 +16,17 @@ export default class extends Controller {
}
connect() {
const params = new URLSearchParams(window.location.search)
const urlId = parseInt(params.get('variant'))
const defaultId = this.variantsValue[0]?.id
const params = new URLSearchParams(window.location.search)
const urlId = parseInt(params.get('variant'))
const urlVariant = this.variantsValue.find(v => v.id === urlId)
const initial = urlVariant ?? this.variantsValue[0]
this.selectedValue = urlId && this.variantsValue.find(v => v.id === urlId)
? urlId
: defaultId
// A product can have several independent options (e.g. size + style
// + person-count) — this tracks the currently-picked value id per
// option handle, and selectVariant() below resolves the full
// combination back to one exact variant on every change.
this.selections = { ...initial?.options }
this.selectedValue = initial?.id
// Capture phase, on this controller's own root element (an ancestor
// of the checkout module's add-to-cart <form>) — runs BEFORE that
@@ -108,11 +112,24 @@ export default class extends Controller {
}
selectVariant(event) {
const id = parseInt(event.currentTarget.dataset.variantId)
this.selectedValue = id
const option = event.currentTarget.dataset.option
const valueId = parseInt(event.currentTarget.dataset.valueId)
this.selections = { ...this.selections, [option]: valueId }
const match = this.variantsValue.find(variant =>
Object.keys(this.selections).every(key => variant.options?.[key] === this.selections[key])
)
// No variant exists for this combination (e.g. an option value that
// isn't offered together with another currently-selected value) —
// leave the previous selection in place rather than pointing the
// add-to-cart form at nothing.
if (!match) return
this.selectedValue = match.id
const url = new URL(window.location)
url.searchParams.set('variant', id)
url.searchParams.set('variant', match.id)
window.history.pushState({}, '', url)
}
@@ -140,12 +157,16 @@ export default class extends Controller {
if (purchasableInput) purchasableInput.value = id
this.swatchTargets.forEach(swatch => {
const isSelected = parseInt(swatch.dataset.variantId) === id
const isSelected = this.selections[swatch.dataset.option] === parseInt(swatch.dataset.valueId)
swatch.classList.toggle('is-selected', isSelected)
swatch.setAttribute('aria-pressed', String(isSelected))
if (isSelected && this.hasColorNameTarget) {
this.colorNameTarget.textContent = swatch.getAttribute('aria-label')
if (isSelected) {
// Each color-option group has its own colorName echo (see
// x-ui.color-swatch) — matched by option handle so a swatch
// in one group never overwrites another group's label.
const colorName = this.colorNameTargets.find(target => target.dataset.option === swatch.dataset.option)
if (colorName) colorName.textContent = swatch.getAttribute('aria-label')
}
})
}