supportATP commited on
Commit
ff9089d
·
verified ·
1 Parent(s): 9b3e71c

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +465 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Catalog
3
- emoji: 😻
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: catalog
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,465 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Modern E-Commerce Dashboard</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .product-card:hover {
11
+ transform: translateY(-5px);
12
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
13
+ }
14
+ .pagination-btn.active {
15
+ background-color: #3b82f6;
16
+ color: white;
17
+ }
18
+ .admin-panel {
19
+ transition: all 0.3s ease;
20
+ }
21
+ .fade-in {
22
+ animation: fadeIn 0.3s ease-in;
23
+ }
24
+ @keyframes fadeIn {
25
+ from { opacity: 0; }
26
+ to { opacity: 1; }
27
+ }
28
+ </style>
29
+ </head>
30
+ <body class="bg-gray-50">
31
+ <div class="container mx-auto px-4 py-8">
32
+ <!-- Header -->
33
+ <header class="flex justify-between items-center mb-8">
34
+ <h1 class="text-3xl font-bold text-indigo-700">ShopSphere</h1>
35
+ <div class="flex items-center space-x-4">
36
+ <div class="relative">
37
+ <input type="text" id="searchInput" placeholder="Search products..."
38
+ class="pl-10 pr-4 py-2 rounded-full border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500">
39
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
40
+ </div>
41
+ <button id="adminButton" class="bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition">
42
+ <i class="fas fa-cog mr-2"></i>Admin Panel
43
+ </button>
44
+ </div>
45
+ </header>
46
+
47
+ <!-- Admin Panel (Hidden by default) -->
48
+ <div id="adminPanel" class="admin-panel hidden mb-8 bg-white rounded-lg shadow-lg p-6">
49
+ <h2 class="text-2xl font-bold mb-4 text-indigo-700">Product Management</h2>
50
+
51
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
52
+ <!-- Product Form -->
53
+ <div class="bg-gray-50 p-6 rounded-lg">
54
+ <h3 class="text-lg font-semibold mb-4">Add/Edit Product</h3>
55
+ <form id="productForm" class="space-y-4">
56
+ <input type="hidden" id="productId">
57
+ <div>
58
+ <label for="productName" class="block text-sm font-medium text-gray-700">Product Name</label>
59
+ <input type="text" id="productName" required
60
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
61
+ </div>
62
+ <div>
63
+ <label for="productDescription" class="block text-sm font-medium text-gray-700">Description</label>
64
+ <textarea id="productDescription" rows="3" required
65
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"></textarea>
66
+ </div>
67
+ <div>
68
+ <label for="productPrice" class="block text-sm font-medium text-gray-700">Price ($)</label>
69
+ <input type="number" id="productPrice" step="0.01" min="0" required
70
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
71
+ </div>
72
+ <div>
73
+ <label for="productImage" class="block text-sm font-medium text-gray-700">Image URL</label>
74
+ <input type="url" id="productImage" required
75
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
76
+ </div>
77
+ <div class="flex space-x-4">
78
+ <button type="submit" class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700">
79
+ Save Product
80
+ </button>
81
+ <button type="reset" class="bg-gray-200 text-gray-800 px-4 py-2 rounded-md hover:bg-gray-300">
82
+ Clear Form
83
+ </button>
84
+ </div>
85
+ </form>
86
+
87
+ <div class="mt-6">
88
+ <h3 class="text-lg font-semibold mb-2">Bulk Import</h3>
89
+ <button id="bulkImportButton" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700">
90
+ <i class="fas fa-file-import mr-2"></i>Import CSV
91
+ </button>
92
+ <input type="file" id="csvFile" accept=".csv" class="hidden">
93
+ <p class="text-xs text-gray-500 mt-2">CSV format: Name,Description,Price,Image,Category</p>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Product List for Admin -->
98
+ <div>
99
+ <h3 class="text-lg font-semibold mb-4">Current Products</h3>
100
+ <div id="adminProductList" class="space-y-4 max-h-96 overflow-y-auto p-2"></div>
101
+ </div>
102
+ </div>
103
+ </div>
104
+
105
+ <!-- Main Content -->
106
+ <main class="fade-in">
107
+ <!-- Product Grid -->
108
+ <div id="productList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 mb-8"></div>
109
+
110
+ <!-- Pagination -->
111
+ <div id="pagination" class="flex justify-center space-x-2 mt-8"></div>
112
+ </main>
113
+ </div>
114
+
115
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
116
+ <script>
117
+ document.addEventListener('DOMContentLoaded', () => {
118
+ // Sample products data (would normally come from products.json)
119
+ let products = [
120
+ {
121
+ id: 1,
122
+ name: "Wireless Headphones",
123
+ description: "Premium noise-cancelling wireless headphones with 30-hour battery life.",
124
+ price: 199.99,
125
+ image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
126
+ category: "Electronics"
127
+ },
128
+ {
129
+ id: 2,
130
+ name: "Smart Watch",
131
+ description: "Fitness tracker with heart rate monitor and smartphone notifications.",
132
+ price: 159.99,
133
+ image: "https://images.unsplash.com/photo-1523275335684-37898b6baf30?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
134
+ category: "Electronics"
135
+ },
136
+ {
137
+ id: 3,
138
+ name: "Leather Wallet",
139
+ description: "Genuine leather wallet with multiple card slots and RFID protection.",
140
+ price: 49.99,
141
+ image: "https://images.unsplash.com/photo-1611591437281-460914d15503?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
142
+ category: "Accessories"
143
+ },
144
+ {
145
+ id: 4,
146
+ name: "Bluetooth Speaker",
147
+ description: "Portable waterproof speaker with 20W output and 15-hour playtime.",
148
+ price: 89.99,
149
+ image: "https://images.unsplash.com/photo-1572569511254-d8f925fe2cbb?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
150
+ category: "Electronics"
151
+ },
152
+ {
153
+ id: 5,
154
+ name: "Running Shoes",
155
+ description: "Lightweight running shoes with responsive cushioning and breathable mesh.",
156
+ price: 129.99,
157
+ image: "https://images.unsplash.com/photo-1460353581641-37baddab0fa2?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
158
+ category: "Footwear"
159
+ },
160
+ {
161
+ id: 6,
162
+ name: "Coffee Maker",
163
+ description: "Programmable coffee maker with thermal carafe and built-in grinder.",
164
+ price: 149.99,
165
+ image: "https://images.unsplash.com/photo-1556911463-12d4dfcb1f68?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
166
+ category: "Home"
167
+ },
168
+ {
169
+ id: 7,
170
+ name: "Backpack",
171
+ description: "Durable backpack with laptop compartment and USB charging port.",
172
+ price: 79.99,
173
+ image: "https://images.unsplash.com/photo-1553062407-98eeb64c6a62?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
174
+ category: "Accessories"
175
+ },
176
+ {
177
+ id: 8,
178
+ name: "Wireless Charger",
179
+ description: "Fast wireless charging pad compatible with Qi-enabled devices.",
180
+ price: 29.99,
181
+ image: "https://images.unsplash.com/photo-1583394838336-acd977736f90?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
182
+ category: "Electronics"
183
+ }
184
+ ];
185
+
186
+ let currentPage = 1;
187
+ const productsPerPage = 8;
188
+
189
+ // Initialize the page
190
+ renderProductList();
191
+ renderPagination();
192
+
193
+ // Render product list
194
+ function renderProductList() {
195
+ const productList = document.getElementById('productList');
196
+ productList.innerHTML = '';
197
+
198
+ const startIndex = (currentPage - 1) * productsPerPage;
199
+ const endIndex = startIndex + productsPerPage;
200
+ const paginatedProducts = products.slice(startIndex, endIndex);
201
+
202
+ paginatedProducts.forEach(product => {
203
+ const productItem = document.createElement('div');
204
+ productItem.className = 'product-card bg-white rounded-lg shadow-md overflow-hidden transition duration-300';
205
+ productItem.innerHTML = `
206
+ <div class="h-48 overflow-hidden">
207
+ <img src="${product.image}" alt="${product.name}" class="w-full h-full object-cover">
208
+ </div>
209
+ <div class="p-4">
210
+ <div class="flex justify-between items-start mb-2">
211
+ <h3 class="text-lg font-semibold text-gray-800">${product.name}</h3>
212
+ <span class="bg-indigo-100 text-indigo-800 text-xs px-2 py-1 rounded-full">${product.category}</span>
213
+ </div>
214
+ <p class="text-gray-600 text-sm mb-3">${product.description}</p>
215
+ <div class="flex justify-between items-center">
216
+ <span class="text-lg font-bold text-indigo-700">$${product.price.toFixed(2)}</span>
217
+ <button class="bg-indigo-600 text-white px-3 py-1 rounded-md hover:bg-indigo-700 transition">
218
+ <i class="fas fa-shopping-cart mr-1"></i> Add to Cart
219
+ </button>
220
+ </div>
221
+ </div>
222
+ `;
223
+ productList.appendChild(productItem);
224
+ });
225
+ }
226
+
227
+ // Render pagination
228
+ function renderPagination() {
229
+ const pagination = document.getElementById('pagination');
230
+ pagination.innerHTML = '';
231
+
232
+ const totalPages = Math.ceil(products.length / productsPerPage);
233
+
234
+ // Previous button
235
+ if (currentPage > 1) {
236
+ const prevButton = document.createElement('button');
237
+ prevButton.innerHTML = '<i class="fas fa-chevron-left"></i>';
238
+ prevButton.className = 'px-3 py-1 rounded-md border border-gray-300 hover:bg-gray-100';
239
+ prevButton.addEventListener('click', () => {
240
+ currentPage--;
241
+ renderProductList();
242
+ renderPagination();
243
+ });
244
+ pagination.appendChild(prevButton);
245
+ }
246
+
247
+ // Page buttons
248
+ for (let i = 1; i <= totalPages; i++) {
249
+ const pageButton = document.createElement('button');
250
+ pageButton.textContent = i;
251
+ pageButton.className = `px-3 py-1 rounded-md border border-gray-300 hover:bg-gray-100 pagination-btn ${i === currentPage ? 'active' : ''}`;
252
+ pageButton.addEventListener('click', () => {
253
+ currentPage = i;
254
+ renderProductList();
255
+ renderPagination();
256
+ });
257
+ pagination.appendChild(pageButton);
258
+ }
259
+
260
+ // Next button
261
+ if (currentPage < totalPages) {
262
+ const nextButton = document.createElement('button');
263
+ nextButton.innerHTML = '<i class="fas fa-chevron-right"></i>';
264
+ nextButton.className = 'px-3 py-1 rounded-md border border-gray-300 hover:bg-gray-100';
265
+ nextButton.addEventListener('click', () => {
266
+ currentPage++;
267
+ renderProductList();
268
+ renderPagination();
269
+ });
270
+ pagination.appendChild(nextButton);
271
+ }
272
+ }
273
+
274
+ // Search functionality
275
+ document.getElementById('searchInput').addEventListener('input', (event) => {
276
+ const query = event.target.value.toLowerCase();
277
+ const filteredProducts = products.filter(product =>
278
+ product.name.toLowerCase().includes(query) ||
279
+ product.category.toLowerCase().includes(query) ||
280
+ product.description.toLowerCase().includes(query)
281
+ );
282
+ products = filteredProducts;
283
+ currentPage = 1;
284
+ renderProductList();
285
+ renderPagination();
286
+
287
+ // Reset to all products if search is empty
288
+ if (query === '') {
289
+ // In a real app, we would reload from the original JSON
290
+ // For this demo, we'll just use our sample data
291
+ products = [
292
+ {
293
+ id: 1,
294
+ name: "Wireless Headphones",
295
+ description: "Premium noise-cancelling wireless headphones with 30-hour battery life.",
296
+ price: 199.99,
297
+ image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
298
+ category: "Electronics"
299
+ },
300
+ // ... (rest of the sample products)
301
+ ];
302
+ renderProductList();
303
+ renderPagination();
304
+ }
305
+ });
306
+
307
+ // Admin panel toggle
308
+ document.getElementById('adminButton').addEventListener('click', () => {
309
+ const adminPanel = document.getElementById('adminPanel');
310
+ adminPanel.style.display = adminPanel.style.display === 'none' ? 'block' : 'none';
311
+ renderAdminProductList();
312
+ });
313
+
314
+ // Save product form
315
+ document.getElementById('productForm').addEventListener('submit', (event) => {
316
+ event.preventDefault();
317
+ const productId = document.getElementById('productId').value;
318
+ const productName = document.getElementById('productName').value;
319
+ const productDescription = document.getElementById('productDescription').value;
320
+ const productPrice = parseFloat(document.getElementById('productPrice').value);
321
+ const productImage = document.getElementById('productImage').value;
322
+
323
+ if (!productName || !productDescription || isNaN(productPrice) || !productImage) {
324
+ alert('Please fill in all fields correctly.');
325
+ return;
326
+ }
327
+
328
+ if (productId) {
329
+ // Edit existing product
330
+ const productIndex = products.findIndex(p => p.id === parseInt(productId));
331
+ if (productIndex !== -1) {
332
+ products[productIndex] = {
333
+ id: parseInt(productId),
334
+ name: productName,
335
+ description: productDescription,
336
+ price: productPrice,
337
+ image: productImage,
338
+ category: "General"
339
+ };
340
+ }
341
+ } else {
342
+ // Add new product
343
+ const newProduct = {
344
+ id: products.length ? products[products.length - 1].id + 1 : 1,
345
+ name: productName,
346
+ description: productDescription,
347
+ price: productPrice,
348
+ image: productImage,
349
+ category: "General"
350
+ };
351
+ products.push(newProduct);
352
+ }
353
+
354
+ saveProductsToFile();
355
+ renderProductList();
356
+ renderPagination();
357
+ renderAdminProductList();
358
+ document.getElementById('productForm').reset();
359
+ document.getElementById('productId').value = '';
360
+ });
361
+
362
+ // Render admin product list
363
+ function renderAdminProductList() {
364
+ const adminProductList = document.getElementById('adminProductList');
365
+ adminProductList.innerHTML = '';
366
+
367
+ products.forEach(product => {
368
+ const productItem = document.createElement('div');
369
+ productItem.className = 'bg-gray-50 p-4 rounded-lg flex items-start space-x-4';
370
+ productItem.innerHTML = `
371
+ <img src="${product.image}" alt="${product.name}" class="w-16 h-16 object-cover rounded">
372
+ <div class="flex-1">
373
+ <h3 class="font-semibold">${product.name}</h3>
374
+ <p class="text-sm text-gray-600 mb-1">${product.description.substring(0, 50)}...</p>
375
+ <div class="flex justify-between items-center">
376
+ <span class="font-bold text-indigo-700">$${product.price.toFixed(2)}</span>
377
+ <div class="space-x-2">
378
+ <button onclick="editProduct(${product.id})" class="text-blue-600 hover:text-blue-800">
379
+ <i class="fas fa-edit"></i> Edit
380
+ </button>
381
+ <button onclick="deleteProduct(${product.id})" class="text-red-600 hover:text-red-800">
382
+ <i class="fas fa-trash-alt"></i> Delete
383
+ </button>
384
+ </div>
385
+ </div>
386
+ </div>
387
+ `;
388
+ adminProductList.appendChild(productItem);
389
+ });
390
+ }
391
+
392
+ // Edit product
393
+ window.editProduct = function(id) {
394
+ const product = products.find(p => p.id === id);
395
+ if (product) {
396
+ document.getElementById('productId').value = product.id;
397
+ document.getElementById('productName').value = product.name;
398
+ document.getElementById('productDescription').value = product.description;
399
+ document.getElementById('productPrice').value = product.price;
400
+ document.getElementById('productImage').value = product.image;
401
+
402
+ // Scroll to form
403
+ document.getElementById('productForm').scrollIntoView({ behavior: 'smooth' });
404
+ }
405
+ };
406
+
407
+ // Delete product
408
+ window.deleteProduct = function(id) {
409
+ if (confirm('Are you sure you want to delete this product?')) {
410
+ products = products.filter(p => p.id !== id);
411
+ saveProductsToFile();
412
+ renderProductList();
413
+ renderPagination();
414
+ renderAdminProductList();
415
+ }
416
+ };
417
+
418
+ // Bulk import CSV
419
+ document.getElementById('bulkImportButton').addEventListener('click', () => {
420
+ document.getElementById('csvFile').click();
421
+ });
422
+
423
+ document.getElementById('csvFile').addEventListener('change', (event) => {
424
+ const file = event.target.files[0];
425
+ if (file) {
426
+ const reader = new FileReader();
427
+ reader.onload = function(e) {
428
+ const text = e.target.result;
429
+ const csvData = Papa.parse(text, { header: true }).data;
430
+
431
+ csvData.forEach(row => {
432
+ if (row.Name && row.Description && row.Price && row.Image) {
433
+ const newProduct = {
434
+ id: products.length ? products[products.length - 1].id + 1 : 1,
435
+ name: row.Name,
436
+ description: row.Description,
437
+ price: parseFloat(row.Price),
438
+ image: row.Image,
439
+ category: row.Category || 'General'
440
+ };
441
+ products.push(newProduct);
442
+ }
443
+ });
444
+
445
+ saveProductsToFile();
446
+ renderProductList();
447
+ renderPagination();
448
+ renderAdminProductList();
449
+
450
+ // Show success message
451
+ alert(`Successfully imported ${csvData.length} products!`);
452
+ };
453
+ reader.readAsText(file);
454
+ }
455
+ });
456
+
457
+ // Save products to JSON file (simulated for this demo)
458
+ function saveProductsToFile() {
459
+ // In a real application, this would save to a server or local file
460
+ console.log('Products saved:', products);
461
+ }
462
+ });
463
+ </script>
464
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=supportATP/catalog" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
465
+ </html>