Spaces:
Sleeping
Sleeping
Create static/ui/index.html
Browse files- static/ui/index.html +113 -0
static/ui/index.html
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!-- static/ui/index.html -->
|
2 |
+
<!DOCTYPE html>
|
3 |
+
<html lang="en">
|
4 |
+
<head>
|
5 |
+
<meta charset="UTF-8">
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7 |
+
<title>Electronics Store</title>
|
8 |
+
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
9 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
|
10 |
+
<link href="https://cdn.jsdelivr.net/npm/@tailwindcss/typography/dist/typography.min.css" rel="stylesheet">
|
11 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
12 |
+
</head>
|
13 |
+
<body class="bg-gray-100">
|
14 |
+
<div id="app" class="container mx-auto px-4 py-8">
|
15 |
+
<h1 class="text-4xl font-bold mb-8 text-gray-800">Electronics Store</h1>
|
16 |
+
|
17 |
+
<!-- Filters -->
|
18 |
+
<div class="mb-6 flex gap-4">
|
19 |
+
<select v-model="selectedCategory" class="p-2 border rounded-lg">
|
20 |
+
<option value="">All Categories</option>
|
21 |
+
<option v-for="category in categories" :value="category">{{ category }}</option>
|
22 |
+
</select>
|
23 |
+
|
24 |
+
<select v-model="sortBy" class="p-2 border rounded-lg">
|
25 |
+
<option value="price-asc">Price: Low to High</option>
|
26 |
+
<option value="price-desc">Price: High to Low</option>
|
27 |
+
<option value="rating">Rating</option>
|
28 |
+
</select>
|
29 |
+
</div>
|
30 |
+
|
31 |
+
<!-- Products Grid -->
|
32 |
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
33 |
+
<div v-for="product in filteredProducts"
|
34 |
+
class="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow">
|
35 |
+
<h2 class="text-xl font-semibold mb-2">{{ product.name }}</h2>
|
36 |
+
<div class="text-sm text-gray-600 mb-4">Category: {{ product.category }}</div>
|
37 |
+
|
38 |
+
<div class="mb-4">
|
39 |
+
<h3 class="font-semibold mb-2">Specifications:</h3>
|
40 |
+
<ul class="text-sm">
|
41 |
+
<li v-for="(value, key) in product.specs" class="mb-1">
|
42 |
+
{{ key }}: {{ value }}
|
43 |
+
</li>
|
44 |
+
</ul>
|
45 |
+
</div>
|
46 |
+
|
47 |
+
<div class="flex justify-between items-center mt-4">
|
48 |
+
<div class="text-2xl font-bold text-green-600">${{ product.price }}</div>
|
49 |
+
<div class="text-sm">
|
50 |
+
<span class="text-yellow-500">★</span>
|
51 |
+
{{ product.rating }}
|
52 |
+
</div>
|
53 |
+
</div>
|
54 |
+
|
55 |
+
<div class="mt-4 text-sm" :class="{'text-red-500': product.stock < 10, 'text-green-500': product.stock >= 10}">
|
56 |
+
{{ product.stock }} in stock
|
57 |
+
</div>
|
58 |
+
</div>
|
59 |
+
</div>
|
60 |
+
</div>
|
61 |
+
|
62 |
+
<script>
|
63 |
+
const { createApp, ref, computed } = Vue
|
64 |
+
|
65 |
+
createApp({
|
66 |
+
setup() {
|
67 |
+
const products = ref([])
|
68 |
+
const selectedCategory = ref('')
|
69 |
+
const sortBy = ref('price-asc')
|
70 |
+
|
71 |
+
// Fetch products from API
|
72 |
+
fetch('/api/electronics/products')
|
73 |
+
.then(response => response.json())
|
74 |
+
.then(data => products.value = data)
|
75 |
+
|
76 |
+
const categories = computed(() => {
|
77 |
+
return [...new Set(products.value.map(p => p.category))]
|
78 |
+
})
|
79 |
+
|
80 |
+
const filteredProducts = computed(() => {
|
81 |
+
let filtered = [...products.value]
|
82 |
+
|
83 |
+
if (selectedCategory.value) {
|
84 |
+
filtered = filtered.filter(p => p.category === selectedCategory.value)
|
85 |
+
}
|
86 |
+
|
87 |
+
switch (sortBy.value) {
|
88 |
+
case 'price-asc':
|
89 |
+
filtered.sort((a, b) => a.price - b.price)
|
90 |
+
break
|
91 |
+
case 'price-desc':
|
92 |
+
filtered.sort((a, b) => b.price - a.price)
|
93 |
+
break
|
94 |
+
case 'rating':
|
95 |
+
filtered.sort((a, b) => b.rating - a.rating)
|
96 |
+
break
|
97 |
+
}
|
98 |
+
|
99 |
+
return filtered
|
100 |
+
})
|
101 |
+
|
102 |
+
return {
|
103 |
+
products,
|
104 |
+
categories,
|
105 |
+
selectedCategory,
|
106 |
+
sortBy,
|
107 |
+
filteredProducts
|
108 |
+
}
|
109 |
+
}
|
110 |
+
}).mount('#app')
|
111 |
+
</script>
|
112 |
+
</body>
|
113 |
+
</html>
|