Refine cabinet layout, profile blocks, and list filters

This commit is contained in:
Ruslan Bakiev
2026-04-02 17:17:16 +07:00
parent d99e9345f2
commit caa9b9fba5
7 changed files with 372 additions and 277 deletions

View File

@@ -3,6 +3,8 @@ import { useQuery } from '@vue/apollo-composable';
import { ClientProductsDocument } from '~/composables/graphql/generated';
const { result, loading, error } = useQuery(ClientProductsDocument);
const search = ref('');
const stockFilter = ref<'ALL' | 'CUSTOM' | 'STANDARD'>('ALL');
const coverPresets = [
['#e9fbe5', '#acfcd5', '#7be9aa'],
@@ -35,21 +37,58 @@ function createProductCover(name: string, sku: string) {
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
}
const filteredProducts = computed(() => {
const list = result.value?.clientProducts ?? [];
const normalizedSearch = search.value.trim().toLowerCase();
return list.filter((product) => {
const matchSearch = !normalizedSearch
|| product.name.toLowerCase().includes(normalizedSearch)
|| product.sku.toLowerCase().includes(normalizedSearch);
const matchType = stockFilter.value === 'ALL'
|| (stockFilter.value === 'CUSTOM' && product.isCustomizable)
|| (stockFilter.value === 'STANDARD' && !product.isCustomizable);
return matchSearch && matchType;
});
});
</script>
<template>
<section class="space-y-5">
<div>
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Каталог</h1>
<p class="mt-1 text-sm text-[#28543f]/80">Витрина в формате карточек: только визуал и название позиции.</p>
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Каталог</h1>
<div class="surface-card rounded-3xl p-4 md:p-5">
<div class="grid gap-3 md:grid-cols-[1fr_auto]">
<label class="form-control">
<span class="label-text">Поиск</span>
<input
v-model="search"
type="text"
class="input input-bordered w-full"
placeholder="Название или SKU"
>
</label>
<label class="form-control md:min-w-56">
<span class="label-text">Фильтр</span>
<select v-model="stockFilter" class="select select-bordered w-full">
<option value="ALL">Все товары</option>
<option value="CUSTOM">Только кастомные</option>
<option value="STANDARD">Только стандартные</option>
</select>
</label>
</div>
</div>
<div v-if="loading" class="alert surface-card border-0">Загрузка каталога...</div>
<div v-else-if="error" class="alert alert-error">{{ error.message }}</div>
<div v-else-if="(result?.clientProducts?.length ?? 0) > 0" class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
<div v-else-if="filteredProducts.length > 0" class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
<article
v-for="(product, index) in result?.clientProducts ?? []"
v-for="(product, index) in filteredProducts"
:key="product.id"
class="surface-card product-card-anim overflow-hidden rounded-3xl p-3"
:style="{ animationDelay: `${index * 55}ms` }"
@@ -69,7 +108,7 @@ function createProductCover(name: string, sku: string) {
</div>
<div v-else class="alert surface-card border-0">
В каталоге пока нет активных товаров.
Ничего не найдено по текущим параметрам.
</div>
</section>
</template>