|
1 | 1 | <template> |
2 | | - <div class="flex"> |
3 | | - <div class="mx-auto box-content w-[calc(100%+40px)] max-w-[935px] grow p-1"> |
4 | | - <div role="tablist" class="my-4 flex max-w-full flex-col items-stretch"> |
5 | | - <div class="flex flex-row flex-nowrap items-center gap-4"> |
6 | | - <div class="flex items-center justify-center"> |
7 | | - <NuxtLink to="/"> |
8 | | - <img class="mx-auto my-0 h-10 rounded-xl" src="/logo.png" alt="logo" /> |
9 | | - </NuxtLink> |
10 | | - </div> |
11 | | - <div class="flex flex-shrink flex-grow flex-col text-sm font-semibold text-neutral-600 dark:text-neutral-200"> |
12 | | - <form |
13 | | - class="group flex h-10 flex-grow rounded-xl border border-transparent bg-neutral-800/5 dark:bg-white/10 pl-4 pr-3 transition-all focus-within:border-neutral-400 focus-within:dark:border-neutral-600 focus-within:bg-white/30 focus-within:dark:bg-neutral-800/30 hover:border-neutral-300 hover:focus-within:border-neutral-400 hover:dark:border-neutral-600"> |
14 | | - <div class="flex w-full items-center gap-4"> |
15 | | - <div class="flex text-neutral-500 dark:text-neutral-400"> |
16 | | - <Icon name="majesticons:search-line" size="20"></Icon> |
17 | | - </div> |
18 | | - <div class="flex w-full"> |
19 | | - <input |
20 | | - class="w-full bg-transparent py-2 outline-none placeholder:text-neutral-400 placeholder:dark:text-neutral-500" |
21 | | - v-model="searchTerm" |
22 | | - :placeholder="selectedCategory ? `Search in ${selectedCategory}` : 'Search'" /> |
23 | | - </div> |
24 | | - <div @click="searchTerm = ''" class="opacity-0 flex cursor-pointer text-neutral-300 dark:text-neutral-500 transition-all group-focus-within:opacity-100"> |
25 | | - <Icon v-if="!loading" name="solar:close-square-bold" size="24" /> |
26 | | - <Icon v-else-if="loading" name="Loading" size="20" /> |
27 | | - </div> |
28 | | - </div> |
29 | | - </form> |
30 | | - </div> |
31 | | - <div |
32 | | - @click.stop=" |
33 | | - isDropdownCategory = !isDropdownCategory; |
34 | | - isDropdownSortBy = false; |
35 | | - " |
36 | | - class="relative cursor-pointer select-none items-center justify-center text-sm font-semibold"> |
37 | | - <div |
38 | | - class="box-border flex h-10 items-center rounded-xl py-1.5 pl-4 pr-3 transition-all bg-neutral-800/5 hover:bg-neutral-800/10 dark:bg-white/10 hover:dark:bg-white/20 active:scale-95"> |
39 | | - <span class="mr-3">{{ selectedCategory || 'All Categories' }}</span> |
40 | | - <Icon name="ion:chevron-down-outline" size="14" /> |
41 | | - </div> |
42 | | - <Transition> |
43 | | - <div |
44 | | - v-if="isDropdownCategory" |
45 | | - class="absolute left-0 top-full z-10 mt-3 rounded-xl border border-neutral-800/10 dark:border-white/10 text-[13px] font-medium backdrop-blur-xl bg-white/90 dark:bg-neutral-800/80 shadow-lg"> |
46 | | - <div class="m-2 w-44"> |
47 | | - <div @click="selectedCategory = ''" class="rounded-lg px-3 py-2 transition-all duration-300 hover:bg-neutral-800/5 hover:dark:bg-white/5"> |
48 | | - <div class="flex items-center justify-between"> |
49 | | - <div class="mr-4 w-full">All Categories</div> |
50 | | - <Icon v-if="selectedCategory === ''" name="mingcute:check-line" size="16" /> |
51 | | - </div> |
52 | | - </div> |
53 | | - <div |
54 | | - v-for="category in categories" |
55 | | - :key="category.id" |
56 | | - @click="selectedCategory = category.name" |
57 | | - class="rounded-lg px-3 py-2 transition-all duration-300 hover:bg-neutral-800/5 hover:dark:bg-white/5"> |
58 | | - <div class="flex items-center justify-between"> |
59 | | - <div class="mr-4 w-full">{{ category.name }}</div> |
60 | | - <Icon v-if="selectedCategory === category.name" name="mingcute:check-line" size="16" /> |
61 | | - </div> |
62 | | - </div> |
63 | | - </div> |
64 | | - </div> |
65 | | - </Transition> |
66 | | - </div> |
67 | | - <div |
68 | | - @click.stop=" |
69 | | - isDropdownSortBy = !isDropdownSortBy; |
70 | | - isDropdownCategory = false; |
71 | | - " |
72 | | - class="relative cursor-pointer select-none items-center justify-center text-sm font-semibold"> |
73 | | - <div |
74 | | - class="box-border flex h-10 items-center rounded-xl py-1.5 pl-4 pr-3 transition-all bg-neutral-800/5 hover:bg-neutral-800/10 dark:bg-white/10 hover:dark:bg-white/20 active:scale-95"> |
75 | | - <span class="mr-3">{{ selectedOption }}</span> |
76 | | - <Icon name="ion:chevron-down-outline" size="14" /> |
77 | | - </div> |
78 | | - <Transition> |
79 | | - <div |
80 | | - v-if="isDropdownSortBy" |
81 | | - class="absolute right-0 top-full z-10 mt-3 rounded-xl border border-neutral-800/10 dark:border-white/10 text-[13px] font-medium backdrop-blur-xl bg-white/90 dark:bg-neutral-800/80 shadow-lg"> |
82 | | - <div class="m-2 w-44"> |
83 | | - <div |
84 | | - v-for="(option, index) in options" |
85 | | - :key="index" |
86 | | - @click="selectedOption = option.value" |
87 | | - class="rounded-lg px-3 py-2 transition-all duration-300 hover:bg-neutral-800/5 hover:dark:bg-white/5"> |
88 | | - <div class="flex items-center justify-between"> |
89 | | - <div class="mr-4 w-full">{{ option.value }}</div> |
90 | | - <Icon v-if="selectedOption === option.value" name="mingcute:check-line" size="16" /> |
91 | | - </div> |
92 | | - </div> |
93 | | - </div> |
94 | | - </div> |
95 | | - </Transition> |
96 | | - </div> |
97 | | - </div> |
| 2 | + <div class="mx-auto box-content w-full max-w-[935px] grow p-1"> |
| 3 | + <div role="tablist" class="my-4 flex max-w-full flex-col items-stretch"> |
| 4 | + <div class="flex flex-row flex-nowrap items-center gap-4"> |
| 5 | + <Logo /> |
| 6 | + <ProductSearchBox :searchTerm="searchTerm" :selectedCategory="selectedCategory" :loading="loading" v-model:searchTerm="searchTerm" /> |
| 7 | + <ButtonSelectCategory @click.stop="toggleDropdown('category')" :show="isDropdownCategory" :categories="categories" v-model:selectedCategory="selectedCategory" /> |
| 8 | + <ButtonSortBy @click.stop="toggleDropdown('sortBy')" :show="isDropdownSortBy" :options="options" v-model:selectedOption="selectedOption" /> |
98 | 9 | </div> |
99 | | - <div class="grid grid-cols-3 gap-4"> |
100 | | - <ProductCard v-for="product in products" :key="product.id" :product="product" /> |
101 | | - <ProductSkeleton v-if="loading" /> |
102 | | - </div> |
103 | | - <ProductEmpty v-if="!empty && !loading" :cat="selectedCategory" :term="searchTerm" /> |
104 | | - <Footer /> |
105 | 10 | </div> |
| 11 | + <div class="grid grid-cols-3 gap-4"> |
| 12 | + <ProductCard v-for="product in products" :key="product.id" :product="product" /> |
| 13 | + <ProductSkeleton v-if="loading" /> |
| 14 | + </div> |
| 15 | + <ProductEmpty v-if="!empty" :selectedCategory="selectedCategory" :searchTerm="searchTerm" /> |
| 16 | + <AppFooter /> |
106 | 17 | </div> |
107 | 18 | </template> |
108 | 19 |
|
109 | 20 | <script setup> |
110 | 21 | const { products, empty, loading, categories, options, searchTerm, selectedCategory, selectedOption, isDropdownCategory, isDropdownSortBy } = useSearch(); |
| 22 | +
|
| 23 | +const toggleDropdown = (type) => { |
| 24 | + if (type === 'category') { |
| 25 | + isDropdownCategory.value = !isDropdownCategory.value; |
| 26 | + isDropdownSortBy.value = false; |
| 27 | + } else if (type === 'sortBy') { |
| 28 | + isDropdownSortBy.value = !isDropdownSortBy.value; |
| 29 | + isDropdownCategory.value = false; |
| 30 | + } |
| 31 | +}; |
111 | 32 | </script> |
112 | 33 |
|
113 | 34 | <style lang="postcss"> |
|
0 commit comments