Skip to content

Commit 08dfac0

Browse files
feat(frontend): added filtering,searching and sorting (#232)
- added new FilterPanel to handle filters - used two way bindings for reactivity Closes #231
1 parent a5174a7 commit 08dfac0

4 files changed

Lines changed: 377 additions & 163 deletions

File tree

backend/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,4 @@ db.sqlite3
104104
venv
105105
.env
106106
.vscode
107+
.python-version
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<template>
2+
<div class="p-4 border rounded-xl shadow-lg bg-white w-full mt-6">
3+
<h2 class="text-xl font-bold mb-4">Filters</h2>
4+
<div
5+
class="grid p-2 w-full justify-between gap-4 grid-flow-col grid-rows-2 place-items-center"
6+
>
7+
<!-- Type -->
8+
<div>
9+
<label class="block mb-2 text-center">Type:</label>
10+
<input type="text" v-model="typeProxy" class="input-field" />
11+
</div>
12+
13+
<!-- Category -->
14+
<div>
15+
<label class="block mb-2 text-center">Category:</label>
16+
<select v-model="categoryProxy" class="input-field custom-select">
17+
<option value="">All</option>
18+
<option value="clothing">Clothing</option>
19+
<option value="rsvp">RSVP</option>
20+
</select>
21+
</div>
22+
23+
<!-- Min Price -->
24+
<div class="flex flex-col items-center">
25+
<label class="block mb-2 text-center">Min Price:</label>
26+
<input type="number" v-model.number="minProxy" class="input-field" />
27+
</div>
28+
29+
<!-- Max Price -->
30+
<div class="flex flex-col items-center">
31+
<label class="block mb-2 text-center">Max Price:</label>
32+
<input type="number" v-model.number="maxProxy" class="input-field" />
33+
</div>
34+
35+
<!-- Color -->
36+
<div class="flex flex-col items-center">
37+
<label class="block mb-2 text-center">Color:</label>
38+
<input type="text" v-model="colorProxy" class="input-field" />
39+
</div>
40+
41+
<!-- Size -->
42+
<div class="flex flex-col items-center">
43+
<label class="block mb-2 text-center">Size:</label>
44+
<input type="text" v-model="sizeProxy" class="input-field" />
45+
</div>
46+
47+
<!-- Sort By -->
48+
<div>
49+
<label class="block mb-2 text-center">Sort By:</label>
50+
<select v-model="sortProxy" class="input-field custom-select">
51+
<option value="">None</option>
52+
<option value="name">Name (A-Z)</option>
53+
<option value="-name">Name (Z-A)</option>
54+
<option value="price">Price (Low to High)</option>
55+
<option value="-price">Price (High to Low)</option>
56+
<option value="created_at">Newest</option>
57+
<option value="-created_at">Oldest</option>
58+
</select>
59+
</div>
60+
</div>
61+
</div>
62+
</template>
63+
64+
<script setup>
65+
import { computed } from "vue";
66+
67+
const props = defineProps({
68+
selectedType: String,
69+
selectedCategory: String,
70+
minPrice: Number,
71+
maxPrice: Number,
72+
selectedColor: String,
73+
selectedSize: String,
74+
selectedSort: String,
75+
});
76+
77+
const emit = defineEmits([
78+
"update:selectedType",
79+
"update:selectedCategory",
80+
"update:minPrice",
81+
"update:maxPrice",
82+
"update:selectedColor",
83+
"update:selectedSize",
84+
"update:selectedSort",
85+
]);
86+
87+
const typeProxy = computed({
88+
get: () => props.selectedType,
89+
set: (val) => emit("update:selectedType", val),
90+
});
91+
92+
const categoryProxy = computed({
93+
get: () => props.selectedCategory,
94+
set: (val) => emit("update:selectedCategory", val),
95+
});
96+
97+
const minProxy = computed({
98+
get: () => props.minPrice,
99+
set: (val) => emit("update:minPrice", val),
100+
});
101+
102+
const maxProxy = computed({
103+
get: () => props.maxPrice,
104+
set: (val) => emit("update:maxPrice", val),
105+
});
106+
107+
const colorProxy = computed({
108+
get: () => props.selectedColor,
109+
set: (val) => emit("update:selectedColor", val),
110+
});
111+
112+
const sizeProxy = computed({
113+
get: () => props.selectedSize,
114+
set: (val) => emit("update:selectedSize", val),
115+
});
116+
117+
const sortProxy = computed({
118+
get: () => props.selectedSort,
119+
set: (val) => emit("update:selectedSort", val),
120+
});
121+
</script>
122+
123+
<style scoped>
124+
.input-field {
125+
@apply border-2 rounded-md px-3 py-2 w-40 focus:border-[#E43232] focus:outline-none shadow-lg;
126+
height: 42px;
127+
background-color: white;
128+
}
129+
130+
/* Custom dropdown arrow and appearance */
131+
.custom-select {
132+
-webkit-appearance: none;
133+
-moz-appearance: none;
134+
appearance: none;
135+
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20fill%3D%22%23E43232%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M10%2012a.75.75%200%2001-.53-.22l-3-3a.75.75%200%20111.06-1.06L10%2010.19l2.47-2.47a.75.75%200%20011.06%201.06l-3%203a.75.75%200%2001-.53.22z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C/svg%3E");
136+
background-repeat: no-repeat;
137+
background-position: right 0.75rem center;
138+
background-size: 1rem;
139+
padding-right: 2.5rem;
140+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
141+
}
142+
143+
/* Default options */
144+
.custom-select option {
145+
background-color: white;
146+
color: black;
147+
}
148+
149+
/* Attempt to style hovered options — not guaranteed across all browsers */
150+
.custom-select option:hover {
151+
background-color: #e43232;
152+
color: white;
153+
}
154+
</style>

0 commit comments

Comments
 (0)