stock check, variants in cart, variant buttons in product page

This commit is contained in:
elvira
2026-09-17 21:52:39 +03:00
parent fe55cb5f33
commit afa1993c53
27 changed files with 564 additions and 155 deletions
+12 -1
View File
@@ -3,6 +3,7 @@
'href' => null,
'type' => 'button',
'size' => 'lg',
'variant' => 'primary',
'position' => 'relative',
])
@@ -15,6 +16,16 @@
default => 'py-5 px-[46px] text-[19px]',
};
// 'primary' is the CTA look (offset-shadow via .btn-primary's ::before/
// ::after, italic, uppercase). 'secondary' is a plain bordered toggle —
// no shadow layers, fills solid on hover/aria-pressed=true instead, used
// for option pickers (see x-ui.option-buttons) and anywhere else a
// secondary/toggle action shouldn't compete visually with the CTA.
$variantClasses = match($variant) {
'secondary' => 'font-semibold hover:bg-black hover:text-neutral-200 aria-pressed:bg-black aria-pressed:text-neutral-200 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-black',
default => 'btn-primary font-bold italic uppercase',
};
// $position defaults to 'relative' (needed so the ::before/::after layers
// in .btn-primary position against the button itself), but callers that
// need to place the button absolutely (e.g. a hover-reveal CTA over a
@@ -22,7 +33,7 @@
// "absolute" via the class prop — Tailwind's generated stylesheet always
// orders the "relative" utility after "absolute", so on a class clash
// "relative" silently wins and the button never actually gets positioned.
$class = 'btn-primary '.$position.' isolate inline-flex items-center justify-center border border-black font-display font-bold italic text-black cursor-pointer no-underline uppercase ' . $sizeClasses;
$class = trim($position.' isolate inline-flex items-center justify-center border border-black text-black cursor-pointer no-underline '.$variantClasses.' '.$sizeClasses);
$attrs = $href
? $attributes->merge(['href' => $href, 'class' => $class])
@@ -0,0 +1,36 @@
{{-- $variants: array of Modules\Core\Catalog\Services\ProductIndexer's mapVariant()
shape (id, options: [{option, value, meta}], ...) — plain arrays, not Eloquent
models, since this is fed from Modules\Core\Catalog\Services\ProductService.
Use this instead of <x-ui.color-swatch> for options that aren't a color
(no meta.hex), where a swatch dot has nothing meaningful to show. --}}
@props(['variants', 'option' => null])
<div {{ $attributes }}>
@if($option)
<p class="font-bold mb-3 text-sm uppercase tracking-wide">
{{ $option }}
</p>
@endif
<div
class="flex flex-wrap gap-2"
role="group"
aria-label="{{ $option ?? 'Option' }}"
>
@foreach($variants as $variant)
@php
$value = $variant['options'][0] ?? null;
$label = $value['value'] ?? '';
@endphp
<x-ui.button
variant="secondary"
size="sm"
data-product-form-target="swatch"
data-action="click->product-form#selectVariant"
data-variant-id="{{ $variant['id'] }}"
aria-label="{{ $label }}"
aria-pressed="false"
>{{ $label }}</x-ui.button>
@endforeach
</div>
</div>
@@ -1,8 +1,9 @@
@props([
'name' => '',
'price' => null,
'image' => null,
'href' => '#',
'name' => '',
'price' => null,
'image' => null,
'href' => '#',
'variantId' => null,
])
{{-- data-turbo-frame="_top" on the links: this card renders inside the
@@ -27,9 +28,20 @@ class="w-full h-auto block"
@endif
</a>
<x-ui.button size="md" position="absolute" class="opacity-0 group-hover:opacity-100 transition-opacity duration-100">
{{ __('storefront.product.add_to_cart') }}
</x-ui.button>
@if ($variantId)
{{-- has-[...] forces the button visible while an add-to-cart error
is showing, so it isn't only readable on hover — a shopper who
already moved off the card (mouse or the click itself) must
still see why nothing happened. --}}
<x-checkout::add-to-cart
:purchasable="$variantId"
class="absolute opacity-0 group-hover:opacity-100 has-[.bbk-add-to-cart-error:not([hidden])]:opacity-100 transition-opacity duration-100"
>
<x-ui.button type="submit" size="md">
{{ __('storefront.product.add_to_cart') }}
</x-ui.button>
</x-checkout::add-to-cart>
@endif
</div>
<div class="flex items-baseline justify-between gap-4">