Skip to content

Commit a37ff4a

Browse files
committed
fix: components some files
renamed footer.vue to appFooter.vue add buttonselectcategory.vue components add buttonsortby.vue components add logo.vue components add productsearchbox.vue components fix: productcard.vue fix productempty.vue
1 parent 1bc92a9 commit a37ff4a

File tree

8 files changed

+168
-111
lines changed

8 files changed

+168
-111
lines changed

app.vue

Lines changed: 23 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,34 @@
11
<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" />
989
</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 />
10510
</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 />
10617
</div>
10718
</template>
10819

10920
<script setup>
11021
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+
};
11132
</script>
11233

11334
<style lang="postcss">
File renamed without changes.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<template>
2+
<div class="relative cursor-pointer select-none items-center justify-center text-sm font-semibold">
3+
<div
4+
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">
5+
<span class="mr-3">{{ selectedCategory || 'All Categories' }}</span>
6+
<Icon name="ion:chevron-down-outline" size="14" />
7+
</div>
8+
<Transition>
9+
<div
10+
v-show="show"
11+
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">
12+
<div class="m-2 w-44">
13+
<div @click="selectCategory('')" class="rounded-lg px-3 py-2 transition-all duration-300 hover:bg-neutral-800/5 hover:dark:bg-white/5">
14+
<div class="flex items-center justify-between">
15+
<div class="mr-4 w-full">All Categories</div>
16+
<Icon v-if="selectedCategory === ''" name="mingcute:check-line" size="16" />
17+
</div>
18+
</div>
19+
<div
20+
v-for="category in categories"
21+
:key="category.id"
22+
@click="selectCategory(category.name)"
23+
class="rounded-lg px-3 py-2 transition-all duration-300 hover:bg-neutral-800/5 hover:dark:bg-white/5">
24+
<div class="flex items-center justify-between">
25+
<div class="mr-4 w-full">{{ category.name }}</div>
26+
<Icon v-if="selectedCategory === category.name" name="mingcute:check-line" size="16" />
27+
</div>
28+
</div>
29+
</div>
30+
</div>
31+
</Transition>
32+
</div>
33+
</template>
34+
35+
<script setup>
36+
defineProps({
37+
show: Boolean,
38+
categories: Array,
39+
selectedCategory: String,
40+
});
41+
42+
const emit = defineEmits(['update:selectedCategory']);
43+
44+
const selectCategory = (category) => {
45+
emit('update:selectedCategory', category);
46+
};
47+
</script>

components/ButtonSortBy.vue

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<template>
2+
<div class="relative cursor-pointer select-none items-center justify-center text-sm font-semibold">
3+
<div
4+
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">
5+
<span class="mr-3">{{ selectedOption }}</span>
6+
<Icon name="ion:chevron-down-outline" size="14" />
7+
</div>
8+
<Transition>
9+
<div
10+
v-show="show"
11+
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">
12+
<div class="m-2 w-44">
13+
<div
14+
v-for="(option, index) in options"
15+
:key="index"
16+
@click="selectOption(option.value)"
17+
class="rounded-lg px-3 py-2 transition-all duration-300 hover:bg-neutral-800/5 hover:dark:bg-white/5">
18+
<div class="flex items-center justify-between">
19+
<div class="mr-4 w-full">{{ option.value }}</div>
20+
<Icon v-if="selectedOption === option.value" name="mingcute:check-line" size="16" />
21+
</div>
22+
</div>
23+
</div>
24+
</div>
25+
</Transition>
26+
</div>
27+
</template>
28+
29+
<script setup>
30+
defineProps({
31+
show: Boolean,
32+
options: Array,
33+
selectedOption: String,
34+
});
35+
36+
const emit = defineEmits(['update:selectedOption']);
37+
38+
const selectOption = (option) => {
39+
emit('update:selectedOption', option);
40+
};
41+
</script>

components/ProductCard.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
</div>
3333
</template>
3434

35-
<script setup lang="ts">
35+
<script setup>
3636
defineProps({
37-
product: { type: Object, default: null },
37+
product: Object,
3838
});
3939
</script>

components/ProductEmpty.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
<div class="p-6 text-center text-lg">
33
<Icon name="majesticons:search-line" size="99"></Icon>
44
<div class="py-4">
5-
<span v-if="cat">
6-
In the <strong>{{ cat }}</strong> category,
5+
<span v-if="selectedCategory">
6+
In the <strong>{{ selectedCategory }}</strong> category,
77
</span>
8-
<span v-if="term">
9-
there are no items matching for: <strong>{{ term }}</strong>
8+
<span v-if="searchTerm">
9+
there are no items matching for: <strong>{{ searchTerm }}</strong>
1010
</span>
1111
</div>
1212
<div class="text-sm">Try improving your results by double checking your spelling or trying a more general keyword.</div>
1313
</div>
1414
</template>
1515

16-
<script setup lang="ts">
16+
<script setup>
1717
defineProps({
18-
cat: { type: String, default: null },
19-
term: { type: String, default: null },
18+
selectedCategory: String,
19+
searchTerm: String,
2020
});
2121
</script>

components/ProductSearchBox.vue

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<template>
2+
<div class="flex flex-shrink flex-grow flex-col text-sm font-semibold text-neutral-600 dark:text-neutral-200">
3+
<form
4+
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">
5+
<div class="flex w-full items-center gap-4">
6+
<div class="flex text-neutral-500 dark:text-neutral-400">
7+
<Icon name="majesticons:search-line" size="20"></Icon>
8+
</div>
9+
<div class="flex w-full">
10+
<input
11+
class="w-full bg-transparent py-2 outline-none placeholder:text-neutral-400 placeholder:dark:text-neutral-500"
12+
:value="searchTerm"
13+
@input="updateSearchTerm"
14+
:placeholder="selectedCategory ? `Search in ${selectedCategory}` : 'Search'" />
15+
</div>
16+
<div @click="clearSearchTerm" class="opacity-0 flex cursor-pointer text-neutral-300 dark:text-neutral-500 transition-all group-focus-within:opacity-100">
17+
<Icon v-if="!loading" name="solar:close-square-bold" size="24" />
18+
<Icon v-else-if="loading" name="Loading" size="20" />
19+
</div>
20+
</div>
21+
</form>
22+
</div>
23+
</template>
24+
25+
<script setup>
26+
defineProps({
27+
searchTerm: String,
28+
selectedCategory: String,
29+
loading: Boolean,
30+
});
31+
32+
const emits = defineEmits(['update:searchTerm']);
33+
34+
const updateSearchTerm = (event) => {
35+
emits('update:searchTerm', event.target.value);
36+
};
37+
38+
const clearSearchTerm = () => {
39+
emits('update:searchTerm', '');
40+
};
41+
</script>

components/global/Logo.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<template>
2+
<div class="flex items-center justify-center">
3+
<NuxtLink to="/">
4+
<img class="mx-auto my-0 h-10 rounded-xl" src="/logo.png" alt="logo" />
5+
</NuxtLink>
6+
</div>
7+
</template>

0 commit comments

Comments
 (0)