tucalikus's picture
Create a Shopify theme for an electronics shop
55a575d verified
// Product Data
const products = [
{
id: 1,
name: "iPhone 15 Pro Max",
category: "phones",
price: 1199,
originalPrice: 1299,
image: "https://images.unsplash.com/photo-1696446701796-da61225697cc?w=500&auto=format&fit=crop&q=80",
rating: 4.9,
reviews: 2341,
badge: "Best Seller",
description: "Titanium design. A17 Pro chip. Action button. 48MP Main camera. 5x Telephoto.",
specs: ["256GB Storage", "A17 Pro Chip", "48MP Camera", "5x Zoom"]
},
{
id: 2,
name: "MacBook Pro 16",
category: "laptops",
price: 2499,
originalPrice: 2699,
image: "https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=500&auto=format&fit=crop&q=80",
rating: 4.8,
reviews: 1856,
badge: "New",
description: "M3 Max chip. 16-inch Liquid Retina XDR display. Up to 22 hours battery life.",
specs: ["M3 Max", "36GB RAM", "1TB SSD", "16-inch Display"]
},
{
id: 3,
name: "Sony WH-1000XM5",
category: "audio",
price: 399,
originalPrice: 449,
image: "https://images.unsplash.com/photo-1618366712010-f4ae9c647dcb?w=500&auto=format&fit=crop&q=80",
rating: 4.7,
reviews: 3422,
badge: "Popular",
description: "Industry-leading noise cancellation. 30-hour battery life. Crystal clear hands-free calling.",
specs: ["Noise Cancelling", "30h Battery", "Multipoint", "LDAC"]
},
{
id: 4,
name: "PlayStation 5",
category: "gaming",
price: 499,
originalPrice: 549,
image: "https://images.unsplash.com/photo-1606813907291-d86efa9b94db?w=500&auto=format&fit=crop&q=80",
rating: 4.9,
reviews: 5621,
badge: "Hot",
description: "Experience lightning-fast loading with an ultra-high-speed SSD and haptic feedback.",
specs: ["4K Gaming", "Ray Tracing", "SSD", "DualSense"]
},
{
id: 5,
name: "Apple Watch Ultra 2",
category: "accessories",
price: 799,
originalPrice: 799,
image: "https://images.unsplash.com/photo-1434493789847-2f02dc6ca35d?w=500&auto=format&fit=crop&q=80",
rating: 4.8,
reviews: 1234,
badge: null,
description: "The most rugged and capable Apple Watch. 49mm titanium case. Precision GPS.",
specs: ["49mm", "Titanium", "100m Water", "72h Battery"]
},
{
id: 6,
name: "Samsung Galaxy S24 Ultra",
category: "phones",
price: 1299,
originalPrice: 1399,
image: "https://images.unsplash.com/photo-1610945265078-3858a0828671?w=500&auto=format&fit=crop&q=80",
rating: 4.7,
reviews: 1890,
badge: "New",
description: "Galaxy AI is here. 200MP camera. S Pen built-in. Titanium frame.",
specs: ["200MP Camera", "S Pen", "Galaxy AI", "Titanium"]
},
{
id: 7,
name: "Dell XPS 15",
category: "laptops",
price: 1899,
originalPrice: 2099,
image: "https://images.unsplash.com/photo-1593642632823-8f78536788c6?w=500&auto=format&fit=crop&q=80",
rating: 4.6,
reviews: 876,
badge: null,
description: "Stunning OLED display. 13th Gen Intel Core. NVIDIA 40-series graphics.",
specs: ["OLED Touch", "i9-13900H", "RTX 4070", "32GB RAM"]
},
{
id: 8,
name: "AirPods Pro 2",
category: "audio",
price: 249,
originalPrice: 299,
image: "https://images.unsplash.com/photo-1603351154351-5cfb3d04ef32?w=500&auto=format&fit=crop&q=80",
rating: 4.8,
reviews: 8934,
badge: "Best Seller",
description: "Active Noise Cancellation with Adaptive Audio. Personalized Spatial Audio.",
specs: ["ANC", "Spatial Audio", "6h Battery", "MagSafe"]
}
];
// State
let cart = [];
let currentCategory = 'all';
let searchQuery = '';
// DOM Elements
const productsGrid = document.getElementById('products-grid');
const cartSidebar = document.getElementById('cart-sidebar');
const cartOverlay = document.getElementById('cart-overlay');
const cartItems = document.getElementById('cart-items');
const cartBadge = document.getElementById('cart-badge');
const cartSubtotal = document.getElementById('cart-subtotal');
const cartTotal = document.getElementById('cart-total');
const mobileMenu = document.getElementById('mobile-menu');
const searchOverlay = document.getElementById('search-overlay');
const searchInput = document.getElementById('search-input');
// Initialize
document.addEventListener('DOMContentLoaded', () => {
renderProducts();
lucide.createIcons();
});
// Render Products
function renderProducts() {
let filtered = products;
// Filter by category
if (currentCategory !== 'all') {
filtered = filtered.filter(p => p.category === currentCategory);
}
// Filter by search
if (searchQuery) {
filtered = filtered.filter(p =>
p.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
p.description.toLowerCase().includes(searchQuery.toLowerCase())
);
}
productsGrid.innerHTML = filtered.map((product, index) => `
<div class="product-card stagger-item bg-slate-800 rounded-2xl border border-slate-700 overflow-hidden group" style="animation-delay: ${index * 0.1}s">
<div class="relative img-zoom aspect-square bg-slate-900">
<img src="${product.image}" alt="${product.name}" class="w-full h-full object-cover">
${product.badge ? `
<div class="absolute top-4 left-4 px-3 py-1 bg-blue-600 text-white text-xs font-bold rounded-full">
${product.badge}
</div>
` : ''}
<button onclick="openProductModal(${product.id})" class="quick-view absolute bottom-4 right-4 p-3 bg-white/90 hover:bg-white text-slate-900 rounded-full shadow-lg backdrop-blur-sm">
<i data-lucide="eye" class="w-5 h-5"></i>
</button>
</div>
<div class="p-5">
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-medium text-blue-400 uppercase tracking-wider">${product.category}</span>
<div class="flex items-center gap-1 text-sm">
<i data-lucide="star" class="w-4 h-4 text-yellow-500 fill-yellow-500"></i>
<span class="text-slate-300">${product.rating}</span>
<span class="text-slate-500">(${product.reviews})</span>
</div>
</div>
<h3 class="font-semibold text-white mb-2 line-clamp-1">${product.name}</h3>
<p class="text-sm text-slate-400 mb-4 line-clamp-2">${product.description}</p>
<div class="flex items-center justify-between">
<div>
<span class="text-xl font-bold text-white">$${product.price}</span>
${product.originalPrice > product.price ? `
<span class="text-sm text-slate-500 line-through ml-2">$${product.originalPrice}</span>
` : ''}
</div>
<button onclick="addToCart(${product.id})" class="p-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl transition-all transform hover:scale-105 active:scale-95">
<i data-lucide="plus" class="w-5 h-5"></i>
</button>
</div>
</div>
</div>
`).join('');
lucide.createIcons();
}
// Filter by Category
function filterByCategory(category) {
currentCategory = category;
// Update active button
document.querySelectorAll('.category-btn').forEach(btn => {
btn.classList.remove('active');
});
event.currentTarget.classList.add('active');
renderProducts();
}
// Sort Products
function sortProducts() {
const sortValue = document.getElementById('sort-select').value;
switch(sortValue) {
case 'price-low':
products.sort((a, b) => a.price - b.price);
break;
case 'price-high':
products.sort((a, b) => b.price - a.price);
break;
case 'newest':
products.sort((a, b) => b.id - a.id);
break;
default:
products.sort((a, b) => a.id - b.id);
}
renderProducts();
}
// Search Toggle
function toggleSearch() {
searchOverlay.classList.toggle('hidden');
if (!searchOverlay.classList.contains('hidden')) {
searchInput.focus();
}
}
// Search Input Handler
searchInput.addEventListener('input', (e) => {
searchQuery = e.target.value;
renderProducts();
});
// Mobile Menu Toggle
function toggleMobileMenu() {
mobileMenu.classList.toggle('hidden');
}
// Cart Toggle
function toggleCart() {
cartSidebar.classList.toggle('translate-x-full');
cartOverlay.classList.toggle('hidden');
document.body.classList.toggle('overflow-hidden');
}
// Add to Cart
function addToCart(productId) {
const product = products.find(p => p.id === productId);
const existingItem = cart.find(item => item.id === productId);
if (existingItem) {
existingItem.quantity++;
} else {
cart.push({ ...product, quantity: 1 });
}
updateCart();
showToast(`${product.name} added to cart!`);
}
// Remove from Cart
function removeFromCart(productId) {
cart = cart.filter(item => item.id !== productId);
updateCart();
}
// Update Quantity
function updateQuantity(productId, change) {
const item = cart.find(item => item.id === productId);
if (item) {
item.quantity += change;
if (item.quantity <= 0) {
removeFromCart(productId);
} else {
updateCart();
}
}
}
// Update Cart UI
function updateCart() {
// Update badge
const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0);
cartBadge.textContent = totalItems;
cartBadge.classList.toggle('hidden', totalItems === 0);
// Update items
if (cart.length === 0) {
cartItems.innerHTML = `
<div class="text-center text-slate-500 py-12">
<i data-lucide="shopping-bag" class="w-12 h-12 mx-auto mb-4 opacity-50"></i>
<p>Your cart is empty</p>
</div>
`;
} else {
cartItems.innerHTML = cart.map(item => `
<div class="cart-item flex gap-4 p-4 bg-slate-800 rounded-xl border border-slate-700">
<img src="${item.image}" alt="${item.name}" class="w-20 h-20 object-cover rounded-lg bg-slate-900">
<div class="flex-1 min-w-0">
<h4 class="font-medium text-white text-sm truncate">${item.name}</h4>
<p class="text-blue-400 font-semibold mt-1">$${item.price}</p>
<div class="flex items-center gap-3 mt-2">
<button onclick="updateQuantity(${item.id}, -1)" class="w-6 h-6 flex items-center justify-center bg-slate-700 hover:bg-slate-600 rounded text-white text-xs transition-colors">-</button>
<span class="text-sm text-white w-4 text-center">${item.quantity}</span>
<button onclick="updateQuantity(${item.id}, 1)" class="w-6 h-6 flex items-center justify-center bg-slate-700 hover:bg-slate-600 rounded text-white text-xs transition-colors">+</button>
</div>
</div>
<button onclick="removeFromCart(${item.id})" class="p-2 hover:bg-slate-700 rounded-lg transition-colors self-start">
<i data-lucide="trash-2" class="w-4 h-4 text-slate-400"></i>
</button>
</div>
`).join('');
}
// Update totals
const subtotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
cartSubtotal.textContent = `$${subtotal.toFixed(2)}`;
cartTotal.textContent = `$${subtotal.toFixed(2)}`;
lucide.createIcons();
}
// Product Modal
function openProductModal(productId) {
const product = products.find(p => p.id === productId);
const modal = document.getElementById('product-modal');
const content = document.getElementById('modal-content');
content.innerHTML = `
<div class="img-zoom h-64 md:h-full bg-slate-950 rounded-t-3xl md:rounded-l-3xl md:rounded-tr-none overflow-hidden">
<img src="${product.image}" alt="${product.name}" class="w-full h-full object-cover">
</div>
<div class="p-8 md:p-12 flex flex-col">
<div class="flex items-center gap-2 mb-4">
<span class="px-3 py-1 bg-blue-500/20 text-blue-400 text-xs font-bold rounded-full uppercase">${product.category}</span>
${product.badge ? `<span class="px-3 py-1 bg-purple-500/20 text-purple-400 text-xs font-bold rounded-full">${product.badge}</span>` : ''}
</div>
<h2 class="text-3xl font-bold text-white mb-4">${product.name}</h2>
<div class="flex items-center gap-4 mb-6">
<div class="flex items-center gap-1">
<i data-lucide="star" class="w-5 h-5 text-yellow-500 fill-yellow-500"></i>
<span class="text-white font-semibold">${product.rating}</span>
</div>
<span class="text-slate-500">${product.reviews} reviews</span>
</div>
<p class="text-slate-400 mb-6 leading-relaxed">${product.description}</p>
<div class="grid grid-cols-2 gap-3 mb-8">
${product.specs.map(spec => `
<div class="flex items-center gap-2 text-sm text-slate-300">
<i data-lucide="check-circle" class="w-4 h-4 text-blue-500"></i>
${spec}
</div>
`).join('')}
</div>
<div class="flex items-center justify-between pt-6 border-t border-slate-800 mt-auto">
<div>
<span class="text-3xl font-bold text-white">$${product.price}</span>
${product.originalPrice > product.price ? `
<span class="text-lg text-slate-500 line-through ml-3">$${product.originalPrice}</span>
` : ''}
</div>
<button onclick="addToCart(${product.id}); closeProductModal();" class="px-8 py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-xl transition-all transform hover:scale-105 flex items-center gap-2">
<i data-lucide="shopping-cart" class="w-5 h-5"></i>
Add to Cart
</button>
</div>
</div>
`;
modal.classList.remove('hidden');
lucide.createIcons();
}
function closeProductModal() {
document.getElementById('product-modal').classList.add('hidden');
}
// Toast Notification
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toast-message');
toastMessage.textContent = message;
toast.classList.remove('translate-y-24');
setTimeout(() => {
toast.classList.add('translate-y-24');
}, 3000);
}
// Checkout
function checkout() {
if (cart.length === 0) {
showToast('Your cart is empty!');
return;
}
// Simulate checkout
const total = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
showToast(`Proceeding to checkout... Total: $${total.toFixed(2)}`);
// In a real app, this would redirect to checkout page
setTimeout(() => {
cart = [];
updateCart();
toggleCart();
showToast('Order placed successfully! 🎉');
}, 1500);
}
// Newsletter Subscribe
function handleSubscribe(e) {
e.preventDefault();
const email = e.target.querySelector('input').value;
showToast(`Thanks for subscribing with ${email}!`);
e.target.reset();
}
// Scroll to Products
function scrollToProducts() {
document.getElementById('products').scrollIntoView({ behavior: 'smooth' });
}
// Close modal on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeProductModal();
if (!cartSidebar.classList.contains('translate-x-full')) {
toggleCart();
}
if (!searchOverlay.classList.contains('hidden')) {
toggleSearch();
}
}
});
// Close mobile menu when clicking outside
document.addEventListener('click', (e) => {
if (!e.target.closest('nav') && !mobileMenu.classList.contains('hidden')) {
mobileMenu.classList.add('hidden');
}
});