envato-code / index.html
docto41's picture
Add 2 files
ee41924 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Envato Search - Recherche de produits</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.dropzone {
border: 2px dashed #3b82f6;
border-radius: 0.5rem;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.dropzone:hover {
border-color: #10b981;
background-color: rgba(16, 185, 129, 0.05);
}
.dropzone.active {
border-color: #8b5cf6;
background-color: rgba(139, 92, 246, 0.05);
}
.search-highlight {
background-color: rgba(16, 185, 129, 0.3);
font-weight: bold;
padding: 0.1rem 0.2rem;
border-radius: 0.2rem;
}
.envato-badge {
background-color: #82b440;
}
.codecanyon-badge {
background-color: #7e57c2;
}
.skeleton {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
background-color: #e5e7eb;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.image-search-preview {
transition: all 0.3s ease;
}
.image-search-preview:hover {
transform: scale(1.02);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<!-- Header -->
<header class="mb-8">
<div class="flex items-center justify-between">
<div class="flex items-center">
<img src="https://assets.envato.com/front/assets/envato-market-6d2a3fe6f4f1c4a16bea9eafb0e2b4b5d3c9188111f805d41a61d3d3b21e5ef1.svg" alt="Envato Market" class="h-10 mr-4">
<h1 class="text-3xl font-bold text-gray-800">Recherche de produits</h1>
</div>
<div class="flex items-center space-x-4">
<button class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition flex items-center">
<i class="fas fa-sign-in-alt mr-2"></i> Connexion
</button>
</div>
</div>
<p class="text-gray-600 mt-2">Recherchez parmi des milliers de produits Envato Market et CodeCanyon</p>
</header>
<!-- Search Section -->
<div class="bg-white rounded-lg shadow-md p-6 mb-8">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-semibold text-gray-800">Options de recherche</h2>
<div class="flex space-x-2">
<button id="textSearchTab" class="px-4 py-2 bg-green-600 text-white rounded-md transition">Recherche par texte</button>
<button id="imageSearchTab" class="px-4 py-2 bg-blue-600 text-white rounded-md transition">Recherche par image</button>
</div>
</div>
<!-- Text Search -->
<div id="textSearchSection" class="">
<div class="relative">
<input type="text" id="searchInput" placeholder="Rechercher par nom de produit, catégorie, auteur..."
class="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500">
<button id="searchBtn" class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">
<i class="fas fa-search mr-2"></i> Rechercher
</button>
</div>
<div class="flex flex-wrap gap-4 mt-4">
<div class="flex items-center">
<input type="checkbox" id="filterEnvato" checked class="mr-2">
<label for="filterEnvato" class="text-gray-700">Envato Market</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="filterCodeCanyon" checked class="mr-2">
<label for="filterCodeCanyon" class="text-gray-700">CodeCanyon</label>
</div>
<div class="flex items-center ml-auto">
<select id="sortBy" class="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="relevance">Pertinence</option>
<option value="popular">Plus populaires</option>
<option value="newest">Plus récents</option>
<option value="price_asc">Prix croissant</option>
<option value="price_desc">Prix décroissant</option>
</select>
</div>
</div>
</div>
<!-- Image Search -->
<div id="imageSearchSection" class="hidden">
<div class="mb-6">
<div id="dropzone" class="dropzone mb-4">
<i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-3"></i>
<p class="text-lg font-medium text-gray-700">Glissez-déposez une image de produit ici</p>
<p class="text-gray-500 mt-1">ou cliquez pour sélectionner un fichier</p>
<input type="file" id="fileInput" accept="image/*" class="hidden">
</div>
<div id="imagePreviewContainer" class="hidden">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-medium text-gray-800">Image sélectionnée</h3>
<button id="clearImageBtn" class="text-red-600 hover:text-red-800">
<i class="fas fa-times mr-1"></i> Supprimer
</button>
</div>
<div class="flex flex-col md:flex-row gap-6">
<div class="w-full md:w-1/3">
<div class="image-search-preview bg-white p-2 rounded-md border border-gray-200">
<img id="preview" src="#" alt="Aperçu de l'image" class="w-full h-auto rounded-md">
</div>
</div>
<div class="w-full md:w-2/3">
<div class="space-y-4">
<div>
<label for="imageSearchType" class="block text-sm font-medium text-gray-700 mb-1">Type de recherche</label>
<select id="imageSearchType" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="exact">Recherche exacte</option>
<option value="similar">Produits similaires</option>
<option value="color">Par palette de couleurs</option>
</select>
</div>
<div>
<label for="imageSearchConfidence" class="block text-sm font-medium text-gray-700 mb-1">Niveau de correspondance</label>
<input type="range" id="imageSearchConfidence" min="50" max="100" value="80" class="w-full">
<div class="flex justify-between text-xs text-gray-500 mt-1">
<span>Large</span>
<span>Précis</span>
</div>
</div>
<button id="searchImageBtn" class="w-full md:w-auto px-6 py-3 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition flex items-center justify-center">
<i class="fas fa-camera mr-2"></i> Lancer la recherche
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Results Section -->
<div id="resultsSection" class="hidden">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-semibold text-gray-800">
Résultats de recherche: <span id="resultsCount" class="text-blue-600">0</span>
</h2>
<div class="flex items-center space-x-2">
<span class="text-sm text-gray-600">Trier par:</span>
<select id="resultsSortBy" class="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="relevance">Pertinence</option>
<option value="popular">Popularité</option>
<option value="newest">Plus récents</option>
<option value="price_asc">Prix croissant</option>
<option value="price_desc">Prix décroissant</option>
</select>
</div>
</div>
<div id="loadingIndicator" class="hidden">
<div class="space-y-4">
<div class="skeleton h-32 rounded-md"></div>
<div class="skeleton h-32 rounded-md"></div>
<div class="skeleton h-32 rounded-md"></div>
</div>
</div>
<div id="resultsContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Results will be loaded here -->
</div>
<div id="pagination" class="mt-8 flex justify-center hidden">
<nav class="inline-flex rounded-md shadow">
<button class="px-3 py-1 rounded-l-md border border-gray-300 bg-white text-gray-500 hover:bg-gray-50">
Précédent
</button>
<button class="px-3 py-1 border-t border-b border-gray-300 bg-blue-50 text-blue-600 font-medium">
1
</button>
<button class="px-3 py-1 border border-gray-300 bg-white text-gray-500 hover:bg-gray-50">
2
</button>
<button class="px-3 py-1 border border-gray-300 bg-white text-gray-500 hover:bg-gray-50">
3
</button>
<button class="px-3 py-1 rounded-r-md border border-gray-300 bg-white text-gray-500 hover:bg-gray-50">
Suivant
</button>
</nav>
</div>
<div id="noResults" class="hidden text-center py-12">
<i class="fas fa-search fa-3x text-gray-300 mb-4"></i>
<h3 class="text-xl font-medium text-gray-700">Aucun résultat trouvé</h3>
<p class="text-gray-500 mt-2">Essayez de modifier vos critères de recherche</p>
</div>
</div>
<!-- Footer -->
<footer class="mt-12 pt-8 border-t border-gray-200">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<img src="https://assets.envato.com/front/assets/envato-market-6d2a3fe6f4f1c4a16bea9eafb0e2b4b5d3c9188111f805d41a61d3d3b21e5ef1.svg" alt="Envato Market" class="h-8">
<p class="text-gray-500 text-sm mt-2">© 2023 Envato Pty Ltd. Tous droits réservés.</p>
</div>
<div class="flex space-x-6">
<a href="#" class="text-gray-600 hover:text-gray-900">Conditions</a>
<a href="#" class="text-gray-600 hover:text-gray-900">Politique de confidentialité</a>
<a href="#" class="text-gray-600 hover:text-gray-900">API</a>
<a href="#" class="text-gray-600 hover:text-gray-900">Support</a>
</div>
</div>
</footer>
</div>
<script>
// Sample product database (in a real app, this would come from an API)
const products = [
{
id: "avada",
name: "Avada | Website Builder For WordPress & WooCommerce",
type: "envato",
category: "Thème WordPress",
author: "ThemeFusion",
price: 69,
sales: 842000,
rating: 4.82,
updated: "2023-10-15",
description: "Avada est le meilleur vendeur #1 de tous les temps sur ThemeForest avec 840 000 ventes. Il s'agit d'un thème WordPress ultra-personnalisable avec un constructeur de page avancé.",
image: "https://themeforest.img.customer.envatousercontent.com/files/459385881/avada-preview.jpg?auto=compress%2Cformat&fit=crop&crop=top&w=590&h=300&s=7b1b0c0b1b1b1b1b1b1b1b1b1b1b1b1",
tags: ["wordpress", "builder", "woocommerce", "responsive"]
},
{
id: "revolution",
name: "Slider Revolution - More Than Just a WordPress Slider",
type: "codecanyon",
category: "Plugin WordPress",
author: "ThemePunch",
price: 39,
sales: 320000,
rating: 4.78,
updated: "2023-09-28",
description: "Slider Revolution est un plugin de création de sliders et animations avancées pour WordPress. Créez des présentations époustouflantes avec des effets visuels impressionnants.",
image: "https://s3.envato.com/files/328384320/slider-revolution-preview.jpg",
tags: ["slider", "animation", "wordpress", "visual"]
},
{
id: "betheme",
name: "BeTheme - Responsive Multi-Purpose WordPress Theme",
type: "envato",
category: "Thème WordPress",
author: "Muffin group",
price: 59,
sales: 235000,
rating: 4.75,
updated: "2023-08-10",
description: "BeTheme est un thème WordPress multi-usage avec plus de 600 démos pré-construites. Idéal pour créer tout type de site web rapidement et facilement.",
image: "https://themeforest.img.customer.envatousercontent.com/files/459385881/betheme-preview.jpg?auto=compress%2Cformat&fit=crop&crop=top&w=590&h=300&s=7b1b0c0b1b1b1b1b1b1b1b1b1b1b1b1",
tags: ["wordpress", "multipurpose", "responsive", "demos"]
},
{
id: "wpbakery",
name: "WPBakery Page Builder (formerly Visual Composer)",
type: "codecanyon",
category: "Plugin WordPress",
author: "WPBakery",
price: 45,
sales: 410000,
rating: 4.72,
updated: "2023-07-22",
description: "WPBakery Page Builder est un constructeur de page visuel pour WordPress. Créez des mises en page complexes sans coder avec une interface glisser-déposer intuitive.",
image: "https://s3.envato.com/files/328384320/wpbakery-preview.jpg",
tags: ["page builder", "wordpress", "drag and drop", "visual"]
},
{
id: "the7",
name: "The7 — Website and eCommerce Builder for WordPress",
type: "envato",
category: "Thème WordPress",
author: "Dream-Theme",
price: 39,
sales: 125000,
rating: 4.81,
updated: "2023-10-05",
description: "The7 est un thème WordPress ultra-personnalisable avec options avancées. Compatible avec WooCommerce pour créer des boutiques en ligne performantes.",
image: "https://themeforest.img.customer.envatousercontent.com/files/459385881/the7-preview.jpg?auto=compress%2Cformat&fit=crop&crop=top&w=590&h=300&s=7b1b0c0b1b1b1b1b1b1b1b1b1b1b1b1",
tags: ["wordpress", "woocommerce", "responsive", "customizable"]
},
{
id: "elementor",
name: "Elementor Pro — Premium Drag & Drop Page Builder",
type: "codecanyon",
category: "Plugin WordPress",
author: "Elementor.com",
price: 49,
sales: 380000,
rating: 4.85,
updated: "2023-09-15",
description: "Elementor Pro est un constructeur de page avancé avec fonctionnalités pro. Créez des sites web professionnels avec une interface glisser-déposer intuitive et des widgets avancés.",
image: "https://s3.envato.com/files/328384320/elementor-preview.jpg",
tags: ["page builder", "wordpress", "drag and drop", "pro"]
},
{
id: "flatsome",
name: "Flatsome | Multi-Purpose Responsive WooCommerce Theme",
type: "envato",
category: "Thème WordPress",
author: "UX-Themes",
price: 59,
sales: 185000,
rating: 4.83,
updated: "2023-08-28",
description: "Flatsome est un thème WordPress spécialement conçu pour WooCommerce. Il offre des fonctionnalités avancées pour créer des boutiques en ligne performantes et esthétiques.",
image: "https://themeforest.img.customer.envatousercontent.com/files/459385881/flatsome-preview.jpg?auto=compress%2Cformat&fit=crop&crop=top&w=590&h=300&s=7b1b0c0b1b1b1b1b1b1b1b1b1b1b1b1",
tags: ["wordpress", "woocommerce", "ecommerce", "responsive"]
},
{
id: "ultimate",
name: "Ultimate Addons for Elementor - Power-up Your Elementor Page Builder",
type: "codecanyon",
category: "Plugin WordPress",
author: "Brainstorm Force",
price: 25,
sales: 95000,
rating: 4.79,
updated: "2023-07-30",
description: "Ultimate Addons étend les fonctionnalités d'Elementor avec des widgets et modules supplémentaires. Créez des mises en page encore plus impressionnantes avec ces outils avancés.",
image: "https://s3.envato.com/files/328384320/ultimate-addons-preview.jpg",
tags: ["elementor", "wordpress", "addons", "widgets"]
}
];
// DOM Elements
const textSearchTab = document.getElementById('textSearchTab');
const imageSearchTab = document.getElementById('imageSearchTab');
const textSearchSection = document.getElementById('textSearchSection');
const imageSearchSection = document.getElementById('imageSearchSection');
const searchInput = document.getElementById('searchInput');
const searchBtn = document.getElementById('searchBtn');
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const imagePreviewContainer = document.getElementById('imagePreviewContainer');
const preview = document.getElementById('preview');
const clearImageBtn = document.getElementById('clearImageBtn');
const searchImageBtn = document.getElementById('searchImageBtn');
const resultsSection = document.getElementById('resultsSection');
const resultsContainer = document.getElementById('resultsContainer');
const resultsCount = document.getElementById('resultsCount');
const loadingIndicator = document.getElementById('loadingIndicator');
const noResults = document.getElementById('noResults');
const pagination = document.getElementById('pagination');
const filterEnvato = document.getElementById('filterEnvato');
const filterCodeCanyon = document.getElementById('filterCodeCanyon');
const sortBy = document.getElementById('sortBy');
const resultsSortBy = document.getElementById('resultsSortBy');
// Tab switching
textSearchTab.addEventListener('click', () => {
textSearchTab.classList.add('bg-green-600');
imageSearchTab.classList.remove('bg-blue-600');
textSearchSection.classList.remove('hidden');
imageSearchSection.classList.add('hidden');
});
imageSearchTab.addEventListener('click', () => {
imageSearchTab.classList.add('bg-blue-600');
textSearchTab.classList.remove('bg-green-600');
imageSearchSection.classList.remove('hidden');
textSearchSection.classList.add('hidden');
});
// Image upload handling
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropzone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropzone.classList.add('border-blue-500', 'bg-blue-50');
}
function unhighlight() {
dropzone.classList.remove('border-blue-500', 'bg-blue-50');
}
dropzone.addEventListener('drop', handleDrop, false);
dropzone.addEventListener('click', () => fileInput.click(), false);
fileInput.addEventListener('change', function() {
handleFiles(this.files);
});
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
function handleFiles(files) {
if (files.length) {
const file = files[0];
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = function(e) {
preview.src = e.target.result;
imagePreviewContainer.classList.remove('hidden');
dropzone.classList.add('hidden');
};
reader.readAsDataURL(file);
}
}
}
clearImageBtn.addEventListener('click', function() {
preview.src = '#';
fileInput.value = '';
imagePreviewContainer.classList.add('hidden');
dropzone.classList.remove('hidden');
});
// Search functions
searchBtn.addEventListener('click', performTextSearch);
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
performTextSearch();
}
});
searchImageBtn.addEventListener('click', performImageSearch);
function performTextSearch() {
const searchTerm = searchInput.value.trim().toLowerCase();
if (searchTerm) {
showLoading();
// Simulate API delay
setTimeout(() => {
const filteredProducts = filterProducts(searchTerm);
displayResults(filteredProducts, searchTerm);
}, 800);
}
}
function performImageSearch() {
if (preview.src && !preview.src.endsWith('#')) {
showLoading();
// Simulate image search with random results
setTimeout(() => {
const randomProducts = [...products].sort(() => 0.5 - Math.random()).slice(0, 6);
displayResults(randomProducts, '', true);
}, 1200);
} else {
alert("Veuillez d'abord sélectionner une image.");
}
}
function filterProducts(searchTerm) {
const showEnvato = filterEnvato.checked;
const showCodeCanyon = filterCodeCanyon.checked;
const sortMethod = sortBy.value;
let filtered = products.filter(product => {
// Filter by type
if ((product.type === 'envato' && !showEnvato) ||
(product.type === 'codecanyon' && !showCodeCanyon)) {
return false;
}
// Filter by search term
return product.name.toLowerCase().includes(searchTerm) ||
product.description.toLowerCase().includes(searchTerm) ||
product.category.toLowerCase().includes(searchTerm) ||
product.author.toLowerCase().includes(searchTerm) ||
product.tags.some(tag => tag.toLowerCase().includes(searchTerm));
});
// Sort results
switch(sortMethod) {
case 'popular':
filtered.sort((a, b) => b.sales - a.sales);
break;
case 'newest':
filtered.sort((a, b) => new Date(b.updated) - new Date(a.updated));
break;
case 'price_asc':
filtered.sort((a, b) => a.price - b.price);
break;
case 'price_desc':
filtered.sort((a, b) => b.price - a.price);
break;
default: // relevance
// Simple relevance scoring - more matches = higher relevance
filtered.forEach(product => {
let score = 0;
if (product.name.toLowerCase().includes(searchTerm)) score += 3;
if (product.description.toLowerCase().includes(searchTerm)) score += 2;
if (product.category.toLowerCase().includes(searchTerm)) score += 1;
if (product.author.toLowerCase().includes(searchTerm)) score += 1;
product.tags.forEach(tag => {
if (tag.toLowerCase().includes(searchTerm)) score += 1;
});
product.relevance = score;
});
filtered.sort((a, b) => b.relevance - a.relevance);
}
return filtered;
}
function showLoading() {
resultsSection.classList.remove('hidden');
loadingIndicator.classList.remove('hidden');
resultsContainer.innerHTML = '';
noResults.classList.add('hidden');
pagination.classList.add('hidden');
}
function displayResults(results, searchTerm = '', isImageSearch = false) {
loadingIndicator.classList.add('hidden');
if (results.length === 0) {
noResults.classList.remove('hidden');
resultsCount.textContent = '0';
pagination.classList.add('hidden');
return;
}
resultsCount.textContent = results.length;
resultsContainer.innerHTML = '';
results.forEach(product => {
const productElement = document.createElement('div');
productElement.className = 'bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition';
// Highlight search term in results (for text search only)
let highlightedName = product.name;
let highlightedDesc = product.description;
if (searchTerm && !isImageSearch) {
const regex = new RegExp(searchTerm, 'gi');
highlightedName = product.name.replace(regex, match =>
`<span class="search-highlight">${match}</span>`
);
highlightedDesc = product.description.replace(regex, match =>
`<span class="search-highlight">${match}</span>`
);
}
// Format price
const formattedPrice = new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'USD'
}).format(product.price);
productElement.innerHTML = `
<div class="relative">
<img src="${product.image}" alt="${product.name}" class="w-full h-48 object-cover">
<span class="absolute top-2 left-2 px-2 py-1 rounded-md text-xs font-semibold text-white ${product.type === 'envato' ? 'envato-badge' : 'codecanyon-badge'}">
${product.type === 'envato' ? 'Envato' : 'CodeCanyon'}
</span>
${isImageSearch ? `
<div class="absolute top-2 right-2 bg-white bg-opacity-90 px-2 py-1 rounded-md text-xs font-semibold">
<i class="fas fa-percentage mr-1"></i> ${Math.floor(Math.random() * 20) + 80}% match
</div>
` : ''}
</div>
<div class="p-4">
<h3 class="font-bold text-lg text-gray-800 mb-1">${highlightedName}</h3>
<p class="text-sm text-gray-600 mb-2">Par ${product.author}</p>
<p class="text-gray-700 text-sm mb-3 line-clamp-2">${highlightedDesc}</p>
<div class="flex items-center justify-between">
<div>
<span class="font-bold text-gray-900">${formattedPrice}</span>
<span class="text-xs text-gray-500 ml-1">+ TVA si applicable</span>
</div>
<div class="flex items-center">
<i class="fas fa-star text-yellow-400 mr-1"></i>
<span class="text-sm font-medium">${product.rating}</span>
<span class="text-xs text-gray-500 ml-1">(${Math.floor(product.sales / 1000)}k)</span>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 border-t border-gray-100 flex justify-between">
<a href="#" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
<i class="far fa-eye mr-1"></i> Voir détails
</a>
<button class="text-green-600 hover:text-green-800 text-sm font-medium add-to-cart" data-id="${product.id}">
<i class="fas fa-cart-plus mr-1"></i> Ajouter
</button>
</div>
`;
resultsContainer.appendChild(productElement);
});
// Show pagination if enough results
if (results.length > 6) {
pagination.classList.remove('hidden');
} else {
pagination.classList.add('hidden');
}
}
// Add to cart functionality
document.addEventListener('click', function(e) {
if (e.target.classList.contains('add-to-cart') || e.target.closest('.add-to-cart')) {
const button = e.target.classList.contains('add-to-cart') ? e.target : e.target.closest('.add-to-cart');
const productId = button.getAttribute('data-id');
const product = products.find(p => p.id === productId);
// Show added notification
const notification = document.createElement('div');
notification.className = 'fixed top-4 right-4 bg-green-600 text-white px-4 py-2 rounded-md shadow-lg flex items-center animate-fade-in';
notification.innerHTML = `
<i class="fas fa-check-circle mr-2"></i>
"${product.name}" ajouté au panier
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.classList.add('animate-fade-out');
setTimeout(() => notification.remove(), 300);
}, 3000);
}
});
// Results sorting
resultsSortBy.addEventListener('change', function() {
const currentResults = Array.from(resultsContainer.children).map(el => {
const id = el.querySelector('.add-to-cart').getAttribute('data-id');
return products.find(p => p.id === id);
});
const sortMethod = this.value;
switch(sortMethod) {
case 'popular':
currentResults.sort((a, b) => b.sales - a.sales);
break;
case 'newest':
currentResults.sort((a, b) => new Date(b.updated) - new Date(a.updated));
break;
case 'price_asc':
currentResults.sort((a, b) => a.price - b.price);
break;
case 'price_desc':
currentResults.sort((a, b) => b.price - a.price);
break;
default: // relevance - keep original order
break;
}
displayResults(currentResults);
});
</script>
<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=docto41/envato-code" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>