schon/storefront/pages/search.vue
Alexandr SaVBaD Waltz 129ad1a6fa Features: 1) Build standalone pages for search, contact, catalog, category, brand, product, and home with localized metadata and scoped styles; 2) Add extensive TypeScript definitions for API and app-level structures, including products, orders, brands, and categories; 3) Implement i18n configuration with dynamic browser language detection and fallback system;
Fixes: None;

Extra: 1) Create Pinia stores for app, user, category, and company management; 2) Add utility functions for error handling and category slug lookups; 3) Include German locale file and robots.txt for improved SEO and accessibility; 4) Add SVG assets and improve general folder structure for better maintainability.
2025-06-27 00:10:35 +03:00

100 lines
No EOL
2.5 KiB
Vue

<template>
<div class="search">
<div class="container">
<div class="search__wrapper">
<div
v-for="(block, idx) in blocks"
:key="idx"
class="search__block"
>
<h6 class="search__block-title" v-if="hasData(block.key)">{{ t(block.title) }} {{ t('search.byRequest') }} "{{ q }}"</h6>
<div class="search__block-list" v-if="block.title.includes('products')">
<cards-product
v-for="product in data?.products.edges"
:key="product.node.uuid"
:product="product.node"
/>
</div>
<div class="search__block-list" v-if="block.title.includes('categories')">
<cards-category
v-for="category in data?.categories.edges"
:key="category.node.uuid"
:category="category.node"
/>
</div>
<div class="search__block-list" v-if="block.title.includes('brands')">
<cards-brand
v-for="brand in data?.brands.edges"
:key="brand.node.uuid"
:brand="brand.node"
/>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {useRouteQuery} from "@vueuse/router";
import {usePageTitle} from "~/composables/utils";
import {useSearchCombined} from "~/composables/search";
import type {ISearchCombinedResponse} from "~/types";
const {t} = useI18n();
const q = useRouteQuery('q', '');
const { setPageTitle } = usePageTitle();
setPageTitle(t('breadcrumbs.search'));
const { data } = await useSearchCombined(q.value);
type SearchResponseKey = keyof ISearchCombinedResponse;
const blocks = computed(() => {
if (!data.value) return [];
return (Object.keys(data.value) as SearchResponseKey[])
.map((key) => ({
key,
title: `search.${key}`
}));
});
const hasData = (blockKey: string): boolean => {
const validKey = blockKey as SearchResponseKey;
return (data.value?.[validKey]?.edges?.length ?? 0) > 0;
};
</script>
<style scoped lang="scss">
.search {
padding-top: 75px;
&__wrapper {
display: flex;
flex-direction: column;
gap: 50px;
}
&__block {
&-title {
padding-bottom: 10px;
border-bottom: 2px solid $accentDark;
color: $accentDark;
font-size: 28px;
}
&-list {
margin-top: 25px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(275px, 1fr));
justify-content: space-between;
grid-gap: 75px;
}
}
}
</style>