Implement a complete overhaul of the theme templates to match the Kolli UI design, including enhanced WooCommerce support, dark mode functionality, and improved responsive layouts. - Redesign core templates: front-page, archive, single, and product pages - Implement dynamic WooCommerce templates for shop, single product, and checkout - Add comprehensive asset structure including fonts, images, and custom CSS/JS - Integrate Tailwind CSS via CDN with custom configuration for brand colors - Add dark mode support with local storage persistence - Refactor functions.php for better theme setup and script enqueuing - Implement custom product meta fields for ingredients and health benefits - Add responsive design improvements and custom animations
481 lines
20 KiB
JavaScript
481 lines
20 KiB
JavaScript
// ============================================
|
||
// دادههای محصولات (برای جستجو و سبد خرید)
|
||
// ============================================
|
||
let productsData = [];
|
||
let cart = [];
|
||
let selectedWeightPrice = 295000;
|
||
|
||
// ============================================
|
||
// توابع سبد خرید
|
||
// ============================================
|
||
function quickAddToCart(id) {
|
||
// اگر محصول در دیتا نبود، از طریق Ajax واکشی کن
|
||
fetch(motayeb_ajax.ajax_url + '?action=get_product_data&id=' + id + '&nonce=' + motayeb_ajax.nonce)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
const p = data.data;
|
||
const existing = cart.find(x => x.id === p.id);
|
||
if (existing) { existing.qty++; }
|
||
else { cart.push({ ...p, qty: 1 }); }
|
||
updateCartUI();
|
||
showToast(p.name + ' به سبد خرید اضافه شد', 'success');
|
||
}
|
||
})
|
||
.catch(() => {
|
||
// اگر Ajax کار نکرد، از دادههای mock استفاده کن
|
||
const mockProduct = {
|
||
id: id,
|
||
name: 'محصول شماره ' + id,
|
||
price: 100000,
|
||
img: 'default-product'
|
||
};
|
||
const existing = cart.find(x => x.id === mockProduct.id);
|
||
if (existing) { existing.qty++; }
|
||
else { cart.push({ ...mockProduct, qty: 1 }); }
|
||
updateCartUI();
|
||
showToast(mockProduct.name + ' به سبد خرید اضافه شد', 'success');
|
||
});
|
||
}
|
||
|
||
function addToCartDetail(productId) {
|
||
const qty = parseInt(document.getElementById('product-qty')?.textContent || 1);
|
||
// از طریق Ajax محصول رو واکشی کن
|
||
fetch(motayeb_ajax.ajax_url + '?action=get_product_data&id=' + productId + '&nonce=' + motayeb_ajax.nonce)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
const p = data.data;
|
||
const existing = cart.find(x => x.id === p.id);
|
||
if (existing) { existing.qty += qty; }
|
||
else { cart.push({ ...p, qty: qty }); }
|
||
updateCartUI();
|
||
showToast(p.name + ' به سبد خرید اضافه شد', 'success');
|
||
}
|
||
})
|
||
.catch(() => {
|
||
// Mock
|
||
const mockProduct = {
|
||
id: productId,
|
||
name: 'محصول شماره ' + productId,
|
||
price: 100000,
|
||
img: 'default-product'
|
||
};
|
||
const existing = cart.find(x => x.id === mockProduct.id);
|
||
if (existing) { existing.qty += qty; }
|
||
else { cart.push({ ...mockProduct, qty: qty }); }
|
||
updateCartUI();
|
||
showToast(mockProduct.name + ' به سبد خرید اضافه شد', 'success');
|
||
});
|
||
}
|
||
|
||
function removeFromCart(id) {
|
||
cart = cart.filter(x => x.id !== id);
|
||
updateCartUI();
|
||
}
|
||
|
||
function updateCartQty(id, delta) {
|
||
const item = cart.find(x => x.id === id);
|
||
if (!item) return;
|
||
item.qty += delta;
|
||
if (item.qty <= 0) { removeFromCart(id); return; }
|
||
updateCartUI();
|
||
}
|
||
|
||
function updateCartUI() {
|
||
const count = cart.reduce((s, i) => s + i.qty, 0);
|
||
const total = cart.reduce((s, i) => s + i.price * i.qty, 0);
|
||
|
||
// Badge
|
||
['cart-count', 'mobile-cart-count', 'cart-drawer-count'].forEach(id => {
|
||
const el = document.getElementById(id);
|
||
if (el) {
|
||
if (id === 'cart-drawer-count') {
|
||
el.textContent = count;
|
||
} else {
|
||
if (count > 0) { el.textContent = count; el.classList.remove('hidden'); }
|
||
else { el.classList.add('hidden'); }
|
||
}
|
||
}
|
||
});
|
||
|
||
// Drawer items
|
||
const listEl = document.getElementById('cart-items-list');
|
||
const emptyEl = document.getElementById('cart-empty');
|
||
const footerEl = document.getElementById('cart-drawer-footer');
|
||
|
||
if (!listEl) return;
|
||
|
||
if (cart.length === 0) {
|
||
listEl.classList.add('hidden');
|
||
if (emptyEl) emptyEl.classList.remove('hidden');
|
||
if (footerEl) footerEl.classList.add('hidden');
|
||
} else {
|
||
listEl.classList.remove('hidden');
|
||
if (emptyEl) emptyEl.classList.add('hidden');
|
||
if (footerEl) footerEl.classList.remove('hidden');
|
||
|
||
const totalEl = document.getElementById('cart-drawer-total');
|
||
if (totalEl) totalEl.textContent = formatPrice(total) + ' تومان';
|
||
|
||
listEl.innerHTML = cart.map(i => `
|
||
<div class="flex gap-3 bg-cream-50 dark:bg-dark-bg rounded-xl p-3">
|
||
<img src="https://picsum.photos/seed/${i.img || 'default'}/100/100.jpg" class="w-16 h-16 rounded-lg object-cover flex-shrink-0">
|
||
<div class="flex-1 min-w-0">
|
||
<h4 class="font-bold text-sm line-clamp-1">${i.name}</h4>
|
||
<div class="text-xs text-cream-500 dark:text-dark-muted mt-0.5">${formatPrice(i.price)} تومان</div>
|
||
<div class="flex items-center justify-between mt-2">
|
||
<div class="flex items-center border border-cream-200 dark:border-dark-border rounded-lg overflow-hidden">
|
||
<button onclick="updateCartQty(${i.id},-1)" class="w-7 h-7 flex items-center justify-center hover:bg-cream-200 dark:hover:bg-dark-card transition text-xs"><iconify-icon icon="lucide:minus" width="12"></iconify-icon></button>
|
||
<span class="w-8 h-7 flex items-center justify-center text-xs font-bold border-x border-cream-200 dark:border-dark-border">${i.qty}</span>
|
||
<button onclick="updateCartQty(${i.id},1)" class="w-7 h-7 flex items-center justify-center hover:bg-cream-200 dark:hover:bg-dark-card transition text-xs"><iconify-icon icon="lucide:plus" width="12"></iconify-icon></button>
|
||
</div>
|
||
<button onclick="removeFromCart(${i.id})" class="text-red-400 hover:text-red-500 transition"><iconify-icon icon="lucide:trash-2" width="16"></iconify-icon></button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// Checkout
|
||
const checkoutItems = document.getElementById('checkout-items');
|
||
if (checkoutItems) {
|
||
if (cart.length === 0) {
|
||
checkoutItems.innerHTML = '<p class="text-sm text-cream-500 dark:text-dark-muted text-center py-4">سبد خرید خالی است</p>';
|
||
} else {
|
||
checkoutItems.innerHTML = cart.map(i => `
|
||
<div class="flex items-center gap-3">
|
||
<img src="https://picsum.photos/seed/${i.img || 'default'}/60/60.jpg" class="w-12 h-12 rounded-lg object-cover">
|
||
<div class="flex-1 min-w-0">
|
||
<div class="text-sm font-medium line-clamp-1">${i.name}</div>
|
||
<div class="text-xs text-cream-500 dark:text-dark-muted">${i.qty} عدد</div>
|
||
</div>
|
||
<div class="text-sm font-bold whitespace-nowrap">${formatPrice(i.price * i.qty)}</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
const subtotalEl = document.getElementById('checkout-subtotal');
|
||
const totalEl = document.getElementById('checkout-total');
|
||
if (subtotalEl) subtotalEl.textContent = formatPrice(total) + ' تومان';
|
||
if (totalEl) totalEl.textContent = formatPrice(total) + ' تومان';
|
||
}
|
||
}
|
||
|
||
function formatPrice(n) {
|
||
return n.toLocaleString('fa-IR');
|
||
}
|
||
|
||
// ============================================
|
||
// توابع UI
|
||
// ============================================
|
||
function openSearch() {
|
||
const overlay = document.getElementById('search-overlay');
|
||
if (overlay) {
|
||
overlay.classList.remove('hidden');
|
||
setTimeout(() => {
|
||
const input = document.getElementById('search-input');
|
||
if (input) input.focus();
|
||
}, 100);
|
||
}
|
||
}
|
||
|
||
function closeSearch() {
|
||
const overlay = document.getElementById('search-overlay');
|
||
if (overlay) overlay.classList.add('hidden');
|
||
const input = document.getElementById('search-input');
|
||
if (input) input.value = '';
|
||
const results = document.getElementById('search-results');
|
||
if (results) results.innerHTML = '';
|
||
const suggestions = document.getElementById('search-suggestions');
|
||
if (suggestions) suggestions.classList.remove('hidden');
|
||
}
|
||
|
||
function openCart() {
|
||
const drawer = document.getElementById('cart-drawer');
|
||
if (drawer) drawer.classList.remove('hidden');
|
||
}
|
||
|
||
function closeCart() {
|
||
const drawer = document.getElementById('cart-drawer');
|
||
if (drawer) drawer.classList.add('hidden');
|
||
}
|
||
|
||
function openMobileMenu() {
|
||
const menu = document.getElementById('mobile-menu');
|
||
if (menu) menu.classList.remove('hidden');
|
||
}
|
||
|
||
function closeMobileMenu() {
|
||
const menu = document.getElementById('mobile-menu');
|
||
if (menu) menu.classList.add('hidden');
|
||
}
|
||
|
||
function toggleDark() {
|
||
document.documentElement.classList.toggle('dark');
|
||
}
|
||
|
||
function toggleLang() {
|
||
showToast('نسخه انگلیسی به زودی اضافه میشود', 'info');
|
||
}
|
||
|
||
function goToCheckout() {
|
||
closeCart();
|
||
// هدایت به صفحه تسویه حساب ووکامرس
|
||
if (typeof motayeb_ajax !== 'undefined' && motayeb_ajax.checkout_url) {
|
||
window.location.href = motayeb_ajax.checkout_url;
|
||
} else {
|
||
// Fallback: اگر متغیر وجود نداشت، به صفحه سبد خرید برود
|
||
window.location.href = '/cart/';
|
||
}
|
||
}
|
||
|
||
// ============================================
|
||
// جستجو
|
||
// ============================================
|
||
function handleSearch(val) {
|
||
const results = document.getElementById('search-results');
|
||
const suggestions = document.getElementById('search-suggestions');
|
||
if (!results) return;
|
||
|
||
if (val.length < 2) {
|
||
results.innerHTML = '';
|
||
if (suggestions) suggestions.classList.remove('hidden');
|
||
return;
|
||
}
|
||
if (suggestions) suggestions.classList.add('hidden');
|
||
|
||
// ارسال درخواست Ajax برای جستجو
|
||
fetch(motayeb_ajax.ajax_url + '?action=search_products&term=' + encodeURIComponent(val) + '&nonce=' + motayeb_ajax.nonce)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success && data.data.length > 0) {
|
||
results.innerHTML = data.data.map(p => `
|
||
<button onclick="closeSearch()" class="flex items-center gap-3 w-full p-3 rounded-xl hover:bg-cream-50 dark:hover:bg-dark-bg transition text-right">
|
||
<img src="${p.image || 'https://picsum.photos/seed/' + p.id + '/60/60.jpg'}" class="w-12 h-12 rounded-lg object-cover">
|
||
<div class="flex-1">
|
||
<div class="font-bold text-sm">${p.name}</div>
|
||
<div class="text-xs text-cream-500 dark:text-dark-muted">${p.category || 'محصول'}</div>
|
||
</div>
|
||
<div class="text-sm font-bold text-forest-500 dark:text-forest-300">${formatPrice(p.price)}</div>
|
||
</button>
|
||
`).join('');
|
||
} else {
|
||
results.innerHTML = '<p class="text-sm text-cream-500 dark:text-dark-muted text-center py-6">محصولی یافت نشد</p>';
|
||
}
|
||
})
|
||
.catch(() => {
|
||
// Mock results
|
||
results.innerHTML = '<p class="text-sm text-cream-500 dark:text-dark-muted text-center py-6">خطا در جستجو. لطفاً دوباره تلاش کنید.</p>';
|
||
});
|
||
}
|
||
|
||
//زوم تصویر
|
||
function changeImage(src, btn) {
|
||
const mainImg = document.getElementById('main-product-img');
|
||
if (!mainImg) return;
|
||
|
||
// 1. تغییر تصویر اصلی
|
||
mainImg.src = src;
|
||
|
||
// 2. آپدیت ویژگیهای ضروری برای زوم و پاپآپ ووکامرس
|
||
mainImg.setAttribute('data-large_image', src);
|
||
mainImg.setAttribute('data-src', src);
|
||
|
||
// 3. مهمترین بخش برای پاپآپ: آپدیت لینک والد (<a> اطراف عکس)
|
||
// ووکامرس برای باز کردن پاپآپ از روی href این لینک استفاده میکند
|
||
const parentLink = mainImg.closest('a');
|
||
if (parentLink) {
|
||
parentLink.href = src;
|
||
}
|
||
|
||
// 4. بروزرسانی کلاس فعال روی thumbnails
|
||
document.querySelectorAll('.gallery-thumb').forEach(t => t.classList.remove('active'));
|
||
if (btn) btn.classList.add('active');
|
||
|
||
// 5. بازسازی مجدد Zoom (با متد مقاومتر)
|
||
if (typeof jQuery !== 'undefined' && typeof jQuery.fn.zoom !== 'undefined') {
|
||
const $mainImg = jQuery(mainImg);
|
||
// والد بلافصل عکس را هدف قرار میدهیم (معمولاً یک <div> یا <a> است)
|
||
const $wrapper = $mainImg.parent();
|
||
|
||
// اگر والد قبلاً زوم داشته باشد، آن را نابود کن
|
||
$wrapper.trigger('zoom.destroy');
|
||
|
||
// زوم جدید را روی والد اعمال کن
|
||
$wrapper.zoom({
|
||
url: src,
|
||
touch: false
|
||
});
|
||
}
|
||
}
|
||
|
||
function selectWeight(btn, price) {
|
||
document.querySelectorAll('.weight-btn').forEach(b => {
|
||
b.classList.remove('active', 'border-forest-500', 'dark:border-forest-300', 'bg-forest-50', 'dark:bg-forest-900/30', 'text-forest-500', 'dark:text-forest-300');
|
||
b.classList.add('border-cream-200', 'dark:border-dark-border');
|
||
});
|
||
btn.classList.add('active', 'border-forest-500', 'dark:border-forest-300', 'bg-forest-50', 'dark:bg-forest-900/30', 'text-forest-500', 'dark:text-forest-300');
|
||
btn.classList.remove('border-cream-200', 'dark:border-dark-border');
|
||
selectedWeightPrice = price;
|
||
const priceEl = document.getElementById('product-price');
|
||
if (priceEl) priceEl.textContent = formatPrice(price);
|
||
}
|
||
|
||
function changeQty(delta) {
|
||
const el = document.getElementById('product-qty');
|
||
if (!el) return;
|
||
let val = parseInt(el.textContent) + delta;
|
||
if (val < 1) val = 1;
|
||
if (val > 10) val = 10;
|
||
el.textContent = val;
|
||
}
|
||
|
||
function switchTab(tabId, btn) {
|
||
document.querySelectorAll('.tab-content').forEach(t => t.classList.add('hidden'));
|
||
document.querySelectorAll('.tab-btn').forEach(b => {
|
||
b.classList.remove('tab-active');
|
||
b.classList.add('text-cream-500', 'dark:text-dark-muted');
|
||
});
|
||
const target = document.getElementById('tab-' + tabId);
|
||
if (target) target.classList.remove('hidden');
|
||
if (btn) {
|
||
btn.classList.add('tab-active');
|
||
btn.classList.remove('text-cream-500', 'dark:text-dark-muted');
|
||
}
|
||
}
|
||
|
||
// ============================================
|
||
// علاقهمندیها
|
||
// ============================================
|
||
function toggleWishlist(btn) {
|
||
const icon = btn.querySelector('iconify-icon');
|
||
if (!icon) return;
|
||
const currentIcon = icon.getAttribute('icon');
|
||
if (currentIcon === 'lucide:heart') {
|
||
icon.setAttribute('icon', 'lucide:heart');
|
||
icon.style.color = '#ef4444';
|
||
icon.style.fill = '#ef4444';
|
||
showToast('به علاقهمندیها اضافه شد', 'info');
|
||
} else {
|
||
icon.style.color = '';
|
||
icon.style.fill = '';
|
||
showToast('از علاقهمندیها حذف شد', 'info');
|
||
}
|
||
}
|
||
|
||
// ============================================
|
||
// Toast
|
||
// ============================================
|
||
function showToast(msg, type = 'info') {
|
||
const container = document.getElementById('toast-container');
|
||
if (!container) return;
|
||
const colors = { success: 'bg-forest-500', info: 'bg-earth-400', error: 'bg-red-500' };
|
||
const icons = { success: 'lucide:check-circle', info: 'lucide:info', error: 'lucide:alert-circle' };
|
||
const toast = document.createElement('div');
|
||
toast.className = `toast flex items-center gap-3 px-5 py-3 ${colors[type] || 'bg-earth-400'} text-white rounded-2xl shadow-xl text-sm font-medium`;
|
||
toast.innerHTML = `<iconify-icon icon="${icons[type] || 'lucide:info'}" width="20"></iconify-icon><span>${msg}</span>`;
|
||
container.appendChild(toast);
|
||
setTimeout(() => {
|
||
toast.style.opacity = '0';
|
||
toast.style.transition = 'opacity 0.3s';
|
||
setTimeout(() => toast.remove(), 300);
|
||
}, 3000);
|
||
}
|
||
|
||
// ============================================
|
||
// فرمها
|
||
// ============================================
|
||
function handleNewsletter(e) {
|
||
e.preventDefault();
|
||
const email = document.getElementById('newsletter-email');
|
||
if (email) {
|
||
showToast(email.value + ' با موفقیت ثبت شد!', 'success');
|
||
email.value = '';
|
||
}
|
||
}
|
||
|
||
function handleContact(e) {
|
||
e.preventDefault();
|
||
showToast('پیام شما با موفقیت ارسال شد. به زودی پاسخ میدهیم.', 'success');
|
||
e.target.reset();
|
||
}
|
||
|
||
// ============================================
|
||
// رویدادهای صفحه کلید
|
||
// ============================================
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
closeSearch();
|
||
closeCart();
|
||
closeMobileMenu();
|
||
}
|
||
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||
e.preventDefault();
|
||
openSearch();
|
||
}
|
||
});
|
||
|
||
// ============================================
|
||
// تغییر هدر هنگام اسکرول
|
||
// ============================================
|
||
let lastScroll = 0;
|
||
window.addEventListener('scroll', function() {
|
||
const header = document.getElementById('header');
|
||
if (!header) return;
|
||
const scroll = window.scrollY;
|
||
if (scroll > 100) {
|
||
header.classList.add('shadow-lg');
|
||
} else {
|
||
header.classList.remove('shadow-lg');
|
||
}
|
||
lastScroll = scroll;
|
||
});
|
||
|
||
// ============================================
|
||
// مقداردهی اولیه
|
||
// ============================================
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// تنظیم شمارنده سبد خرید از کوکی (اختیاری)
|
||
updateCartUI();
|
||
|
||
// اگر در صفحه محصول هستیم، کلاسهای گالری رو تنظیم کن
|
||
const mainImg = document.getElementById('main-product-img');
|
||
if (mainImg) {
|
||
// اولین تصویر گالری رو بهعنوان active تنظیم کن
|
||
const firstThumb = document.querySelector('.gallery-thumb');
|
||
if (firstThumb) firstThumb.classList.add('active');
|
||
}
|
||
});
|
||
|
||
// نمونه کد جایگزین برای تولید ستاره
|
||
function renderStars(rating) {
|
||
// ⚠️ اینجا را تغییر دهید: به جای 'ستاره_کانتینر_آیدی'، شناسه واقعی تگ div در HTML خود را بگذارید
|
||
const container = document.getElementById('star-rating'); // یا هر شناسهای که در HTML دارید
|
||
if (!container) return; // اگر ظرف پیدا نشد، کد متوقف شود تا خطا ندهد
|
||
|
||
container.innerHTML = ''; // پاک کردن ظرف
|
||
|
||
for (let i = 1; i <= 5; i++) {
|
||
let star = document.createElement('i'); // ساختن تگ آیکون
|
||
if (i <= rating) {
|
||
star.className = 'fa-solid fa-star text-warning'; // ستاره پر طلایی
|
||
} else {
|
||
star.className = 'fa-regular fa-star text-secondary'; // ستاره خالی خاکستری
|
||
}
|
||
// اضافه کردن کلیک برای ثبت نظر
|
||
star.onclick = function() { setRating(i); };
|
||
|
||
container.appendChild(star);
|
||
}
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// فرض کنید امتیاز فعلی محصول 0 است یا از دیتابیس میخوانید
|
||
let initialRating = 0; // یا عددی که از سمت سرور به جاوا اسکریپت پاس داده میشود
|
||
|
||
// اگر در صفحه جزئیات نظر هستیم، تابع ستارهها را صدا بزنیم
|
||
const starContainer = document.getElementById('star-rating'); // همان شناسه بالا
|
||
if (starContainer) {
|
||
renderStars(initialRating);
|
||
}
|
||
}); |