refactor(catalog): compact group card with visual toggles and bottom accordion
This commit is contained in:
@@ -308,6 +308,14 @@ function formatOptionLabel(field: ParamFieldKey, value: ParamValue) {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function selectedFieldValue(group: ProductGroup, field: ParamFieldKey) {
|
||||
const value = getGroupState(group)[field];
|
||||
if (value === null) {
|
||||
return '—';
|
||||
}
|
||||
return formatOptionLabel(field, value);
|
||||
}
|
||||
|
||||
function incrementProduct(product: ProductNode) {
|
||||
if (getQuantity(product.id) === 0) {
|
||||
addProduct({
|
||||
@@ -376,17 +384,48 @@ function decrementSelected(group: ProductGroup) {
|
||||
:key="group.key"
|
||||
class="surface-card rounded-3xl p-4 md:p-5"
|
||||
>
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<h2 class="text-xl font-bold text-[#133826]">{{ group.typeLabel }}</h2>
|
||||
<span class="badge badge-outline">{{ group.products.length }} вариантов</span>
|
||||
</div>
|
||||
<button class="btn btn-ghost btn-sm" @click="toggleExpanded(group)">
|
||||
{{ getGroupState(group).isExpanded ? 'Свернуть таблицу' : 'Показать все варианты' }}
|
||||
</button>
|
||||
|
||||
<div class="mt-4 grid gap-4 xl:grid-cols-[360px_1fr]">
|
||||
<aside class="rounded-2xl bg-base-100 p-3">
|
||||
<img
|
||||
:src="createProductCover(group.typeLabel, group.key)"
|
||||
:alt="`Превью группы ${group.typeLabel}`"
|
||||
class="h-56 w-full rounded-2xl object-cover"
|
||||
loading="lazy"
|
||||
>
|
||||
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
<span class="badge badge-neutral">SKU: {{ selectedProduct(group)?.sku ?? '—' }}</span>
|
||||
<span class="badge badge-outline">Совпадений: {{ matchingCount(group) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 grid gap-4 xl:grid-cols-[1fr_340px]">
|
||||
<div class="mt-3 flex items-center justify-between rounded-2xl border border-base-300 bg-base-100 px-2 py-1">
|
||||
<button
|
||||
class="btn btn-square btn-sm"
|
||||
:disabled="selectedQty(group) === 0"
|
||||
@click="decrementSelected(group)"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<span class="min-w-10 text-center font-semibold">{{ selectedQty(group) }}</span>
|
||||
<button class="btn btn-square btn-sm" @click="incrementSelected(group)">+</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="field in parameterFields"
|
||||
:key="`selected-${group.key}-${field.key}`"
|
||||
class="badge badge-outline"
|
||||
>
|
||||
{{ field.label }}: {{ selectedFieldValue(group, field.key) }}
|
||||
</span>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="grid gap-3 md:grid-cols-2 2xl:grid-cols-3">
|
||||
<div
|
||||
@@ -411,41 +450,6 @@ function decrementSelected(group: ProductGroup) {
|
||||
|
||||
<p class="text-sm text-base-content/70">Совпадающих вариантов: {{ matchingCount(group) }}</p>
|
||||
</div>
|
||||
|
||||
<aside class="rounded-2xl bg-base-100 p-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-base-content/60">Выбранная позиция</p>
|
||||
|
||||
<template v-if="selectedProduct(group)">
|
||||
<div class="mt-2 flex items-start gap-3">
|
||||
<img
|
||||
:src="createProductCover(selectedProduct(group)!.name, selectedProduct(group)!.sku)"
|
||||
:alt="`Превью ${selectedProduct(group)!.sku}`"
|
||||
class="h-16 w-16 rounded-xl object-cover"
|
||||
loading="lazy"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-semibold text-[#133826]">{{ selectedProduct(group)?.name }}</p>
|
||||
<p class="mt-1 text-xs text-base-content/65">SKU: {{ selectedProduct(group)?.sku }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between rounded-2xl border border-base-300 bg-base-100 px-2 py-1">
|
||||
<button
|
||||
class="btn btn-square btn-sm"
|
||||
:disabled="selectedQty(group) === 0"
|
||||
@click="decrementSelected(group)"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<span class="min-w-10 text-center font-semibold">{{ selectedQty(group) }}</span>
|
||||
<button class="btn btn-square btn-sm" @click="incrementSelected(group)">+</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<p v-else class="mt-2 text-sm text-base-content/70">
|
||||
Нет точного совпадения. Измените параметры или раскройте полный список вариантов.
|
||||
</p>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div v-if="getGroupState(group).isExpanded" class="mt-4 overflow-x-auto rounded-2xl bg-base-100 p-2">
|
||||
@@ -489,6 +493,22 @@ function decrementSelected(group: ProductGroup) {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-ghost mt-3 w-full justify-center gap-2"
|
||||
@click="toggleExpanded(group)"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4 transition-transform"
|
||||
:class="{ 'rotate-180': getGroupState(group).isExpanded }"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M5 7.5L10 12.5L15 7.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
<span>{{ getGroupState(group).isExpanded ? 'Свернуть все варианты' : 'Развернуть все варианты' }}</span>
|
||||
</button>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user