update v1.1
This commit is contained in:
@@ -127,27 +127,6 @@ function initProductDetails() {
|
||||
});
|
||||
}
|
||||
|
||||
// Show product details modal
|
||||
function showProductDetails(pageNum) {
|
||||
const details = productDetails[pageNum];
|
||||
if (details) {
|
||||
document.getElementById('modalTitle').textContent = details.title;
|
||||
document.getElementById('modalDescription').textContent = details.description;
|
||||
document.getElementById('productModal').classList.add('show');
|
||||
}
|
||||
}
|
||||
|
||||
function hideProductDetails() {
|
||||
document.getElementById('productModal').classList.remove('show');
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('productModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
hideProductDetails();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize
|
||||
initProductDetails();
|
||||
// Product details functionality moved to products.html
|
||||
// This file only handles flipbook navigation
|
||||
updatePages();
|
||||
575
js/products.js
Normal file
575
js/products.js
Normal file
@@ -0,0 +1,575 @@
|
||||
async function showCryptoModal(eurAmount) {
|
||||
document.getElementById('cryptoModal').classList.remove('hidden');
|
||||
|
||||
// Update payment amount with loading state
|
||||
const paymentAmountEl = document.getElementById('paymentAmount');
|
||||
paymentAmountEl.textContent = 'Расчет суммы...';
|
||||
|
||||
try {
|
||||
const ltcAmount = await convertEurToLtc(eurAmount);
|
||||
paymentAmountEl.textContent = `Сумма к оплате: ${ltcAmount} LTC`;
|
||||
} catch (error) {
|
||||
console.error('Ошибка расчета суммы:', error);
|
||||
paymentAmountEl.textContent = 'Ошибка расчета суммы';
|
||||
}
|
||||
}
|
||||
|
||||
function hideCryptoModal() {
|
||||
document.getElementById('cryptoModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Product details data
|
||||
|
||||
function showBlackBoxProductDetails(productName) {
|
||||
console.log('showBlackBoxProductDetails called with:', productName);
|
||||
|
||||
// Verify productsData exists and has the product
|
||||
if (!productsData) {
|
||||
console.error('productsData is not defined!');
|
||||
return;
|
||||
}
|
||||
if (!productsData[productName]) {
|
||||
console.error('Product not found in productsData:', productName);
|
||||
return;
|
||||
}
|
||||
|
||||
const modal = document.getElementById('productModal');
|
||||
if (!modal) {
|
||||
console.error('Modal element not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Force remove any inline display:none styles
|
||||
modal.style.display = 'flex';
|
||||
|
||||
const titleEl = document.getElementById('modalTitle');
|
||||
const descEl = document.getElementById('modalDescription');
|
||||
|
||||
if (titleEl) titleEl.textContent = productName;
|
||||
if (descEl) descEl.textContent = productsData[productName].description;
|
||||
|
||||
// Ensure modal is visible
|
||||
modal.classList.remove('hidden');
|
||||
|
||||
// Debug modal state after changes
|
||||
setTimeout(() => {
|
||||
console.log('Modal state after show:', {
|
||||
classList: Array.from(modal.classList),
|
||||
computedDisplay: window.getComputedStyle(modal).display,
|
||||
computedOpacity: window.getComputedStyle(modal).opacity,
|
||||
computedVisibility: window.getComputedStyle(modal).visibility,
|
||||
computedZIndex: window.getComputedStyle(modal).zIndex,
|
||||
computedPointerEvents: window.getComputedStyle(modal).pointerEvents
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function hideBlackBoxProductDetails() {
|
||||
const modal = document.getElementById('productModal');
|
||||
modal.classList.add('hidden');
|
||||
console.log('Product modal hidden');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOMContentLoaded - Adding event listeners');
|
||||
|
||||
// Debug: Log all elements with onclick handlers
|
||||
const detailButtons = document.querySelectorAll('[onclick^="showProductDetails"]');
|
||||
console.log('Found', detailButtons.length, 'detail buttons');
|
||||
detailButtons.forEach(btn => {
|
||||
const originalOnClick = btn.onclick;
|
||||
btn.onclick = function(e) {
|
||||
console.log('Detail button clicked:', {
|
||||
element: e.target,
|
||||
product: e.target.getAttribute('onclick').match(/'([^']+)'/)[1],
|
||||
stack: new Error().stack
|
||||
});
|
||||
return originalOnClick.call(this, e);
|
||||
};
|
||||
});
|
||||
|
||||
// Connect all buy buttons to show crypto modal
|
||||
const buyButtons = document.querySelectorAll('.buy-btn');
|
||||
console.log('Found', buyButtons.length, 'buy buttons');
|
||||
buyButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function(e) {
|
||||
console.log('Buy button clicked', e.target);
|
||||
// Find the parent glass-card to get the product name and price
|
||||
const productCard = e.target.closest('.glass-card');
|
||||
if (productCard) {
|
||||
const productNameElement = productCard.querySelector('h3');
|
||||
if (productNameElement) {
|
||||
const productName = productNameElement.textContent.trim();
|
||||
const product = productsData[productName];
|
||||
if (product && product.price) {
|
||||
showCryptoModal(product.price);
|
||||
} else {
|
||||
console.error('Product price not found for:', productName);
|
||||
// Optionally show the modal without price calculation or show an error message
|
||||
showCryptoModal(0); // Pass 0 or handle error in showCryptoModal
|
||||
}
|
||||
} else {
|
||||
console.error('Product name element not found in card');
|
||||
showCryptoModal(0);
|
||||
}
|
||||
} else {
|
||||
console.error('Product card not found for buy button');
|
||||
showCryptoModal(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Debug modal close button
|
||||
const modalClose = document.querySelector('.modal-close');
|
||||
if (modalClose) {
|
||||
console.log('Found modal close button');
|
||||
modalClose.addEventListener('click', function(e) {
|
||||
console.log('Modal close clicked');
|
||||
hideBlackBoxProductDetails();
|
||||
});
|
||||
}
|
||||
|
||||
const dropdownItems = document.querySelectorAll('.dropdown-item');
|
||||
const menuButtons = document.querySelectorAll('.dropdown-item button');
|
||||
const contentAreas = document.querySelectorAll('.content-area');
|
||||
|
||||
function activateCategory(index) {
|
||||
// Remove active class from all menu items and content areas
|
||||
dropdownItems.forEach(item => item.classList.remove('active'));
|
||||
contentAreas.forEach(area => area.classList.remove('active'));
|
||||
|
||||
// Add active class to the selected menu item and content area
|
||||
dropdownItems[index].classList.add('active');
|
||||
const targetId = menuButtons[index].getAttribute('data-target');
|
||||
const targetContentArea = document.getElementById(targetId);
|
||||
if (targetContentArea) {
|
||||
targetContentArea.classList.add('active');
|
||||
}
|
||||
|
||||
// Rotate icon for active item
|
||||
menuButtons.forEach((button, btnIndex) => {
|
||||
const icon = button.querySelector('i'); // Get icon reference here
|
||||
if (index === btnIndex) {
|
||||
icon.style.transform = 'rotate(90deg)';
|
||||
icon.classList.add('active-arrow');
|
||||
} else {
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
icon.classList.remove('active-arrow');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize the first category as active
|
||||
activateCategory(0);
|
||||
|
||||
menuButtons.forEach((button, index) => {
|
||||
const icon = button.querySelector('i'); // Get icon reference here
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
activateCategory(index);
|
||||
});
|
||||
|
||||
// Handle hover for icon rotation on desktop
|
||||
// Handle arrow rotation and glow effect
|
||||
button.addEventListener('click', () => {
|
||||
const isActive = button.parentElement.classList.contains('active');
|
||||
icon.style.transform = isActive ? 'rotate(90deg)' : 'rotate(0deg)';
|
||||
|
||||
if (isActive) {
|
||||
icon.classList.add('active-arrow');
|
||||
} else {
|
||||
icon.classList.remove('active-arrow');
|
||||
}
|
||||
});
|
||||
|
||||
// Desktop hover effects
|
||||
if (window.innerWidth >= 768) {
|
||||
button.addEventListener('mouseenter', () => {
|
||||
if (!button.parentElement.classList.contains('active')) {
|
||||
icon.style.transform = 'rotate(90deg)';
|
||||
}
|
||||
button.style.transform = 'translateX(5px)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', () => {
|
||||
if (!button.parentElement.classList.contains('active')) {
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
}
|
||||
button.style.transform = '';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Add click handlers for product cards (if needed, currently handled by onclick)
|
||||
// document.querySelectorAll('.product-card').forEach(card => {
|
||||
// card.addEventListener('click', () => {
|
||||
// const productName = card.querySelector('h3').textContent;
|
||||
// showProductDetails(productName);
|
||||
// });
|
||||
// });
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('productModal').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('productModal')) {
|
||||
hideBlackBoxProductDetails();
|
||||
}
|
||||
});
|
||||
|
||||
// Close crypto modal when clicking outside
|
||||
document.getElementById('cryptoModal').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('cryptoModal')) {
|
||||
hideCryptoModal();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Функция для получения курса LTC/EUR с Kraken
|
||||
async function getKrakenRate() {
|
||||
try {
|
||||
const response = await fetch('https://api.kraken.com/0/public/Ticker?pair=LTCEUR');
|
||||
const data = await response.json();
|
||||
const price = parseFloat(data.result.XLTCZEUR.c[0]);
|
||||
return price;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении курса с Kraken:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для получения курса LTC/EUR с CoinGecko
|
||||
async function getCoinGeckoRate() {
|
||||
try {
|
||||
const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=litecoin&vs_currencies=eur');
|
||||
const data = await response.json();
|
||||
const price = parseFloat(data.litecoin.eur);
|
||||
return price;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении курса с CoinGecko:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для получения курса LTC/EUR с Bybit
|
||||
async function getBybitRate() {
|
||||
try {
|
||||
const response = await fetch('https://api.bybit.com/v2/public/tickers?symbol=LTCUSDT');
|
||||
const data = await response.json();
|
||||
const ltcUsdtPrice = parseFloat(data.result[0].last_price);
|
||||
const eurResponse = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=tether&vs_currencies=eur');
|
||||
const eurData = await eurResponse.json();
|
||||
const usdtEurRate = parseFloat(eurData.tether.eur);
|
||||
const ltcEurPrice = ltcUsdtPrice * usdtEurRate;
|
||||
return ltcEurPrice;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении курса с Bybit:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для получения среднего курса LTC/EUR
|
||||
async function getAverageRate() {
|
||||
const rates = await Promise.all([getKrakenRate(), getCoinGeckoRate(), getBybitRate()]);
|
||||
const validRates = rates.filter(rate => rate !== null);
|
||||
if (validRates.length === 0) {
|
||||
throw new Error('Не удалось получить курсы с бирж.');
|
||||
}
|
||||
const sum = validRates.reduce((acc, rate) => acc + rate, 0);
|
||||
return sum / validRates.length;
|
||||
}
|
||||
|
||||
// Функция для конвертации суммы в евро в LTC
|
||||
async function convertEurToLtc(eurAmount) {
|
||||
try {
|
||||
const averageRate = await getAverageRate();
|
||||
const ltcAmount = eurAmount / averageRate;
|
||||
console.log(`Средний курс LTC/EUR: €${averageRate.toFixed(2)}`);
|
||||
console.log(`${eurAmount} EUR ≈ ${ltcAmount.toFixed(8)} LTC`);
|
||||
return ltcAmount.toFixed(8);
|
||||
} catch (error) {
|
||||
console.error('Ошибка при конвертации:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update the payment amount in the crypto modal
|
||||
async function updatePaymentAmount(eurAmount) {
|
||||
const paymentAmountElement = document.getElementById('paymentAmount');
|
||||
if (paymentAmountElement) {
|
||||
paymentAmountElement.textContent = 'Расчет суммы...'; // Show loading state
|
||||
const ltcAmount = await convertEurToLtc(eurAmount);
|
||||
if (ltcAmount !== null) {
|
||||
paymentAmountElement.textContent = `Сумма к оплате: ${ltcAmount} LTC`;
|
||||
} else {
|
||||
paymentAmountElement.textContent = 'Не удалось рассчитать сумму';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showCryptoModal(productPrice) {
|
||||
document.getElementById('cryptoModal').classList.remove('hidden');
|
||||
// Call the function to update the payment amount when the modal is shown
|
||||
updatePaymentAmount(productPrice);
|
||||
}
|
||||
|
||||
function hideCryptoModal() {
|
||||
document.getElementById('cryptoModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Product details data
|
||||
// Product details data with prices
|
||||
const productsData = {
|
||||
"BlackBox VPN": {
|
||||
description: "Базовый бокс с VPN функционалом. 512MB RAM. Создаёт Wi-Fi точку с защищённым VPN. Включает: безопасный браузинг, VPN сервер, анонимный e-mail, доставку обновлений.",
|
||||
price: 99
|
||||
},
|
||||
"BlackBox Privacy Messenger/Cloud": {
|
||||
description: "Встроенный Matrix Messenger или Nextcloud. 1 GB RAM. Полный контроль над вашими данными. Защищённые чаты и файловое хранилище.",
|
||||
price: 199
|
||||
},
|
||||
"BlackBox 4GB": {
|
||||
description: "Мощный бокс с увеличенной памятью. 4GB RAM. Все функции базовой модели + удалённый рабочий стол (Workspace). Полный контроль над вашими данными.",
|
||||
price: 299
|
||||
},
|
||||
"BlackBox Workstation": {
|
||||
description: "Полноценная рабочая станция. Все функции предыдущих моделей. Поддержка виртуальных машин и контейнеров.",
|
||||
price: 499
|
||||
},
|
||||
"BlackBox AI": {
|
||||
description: "Включает все технологии BlackBox. Приватный искусственный интеллект. Максимальная автономность и защита. Локальная обработка данных.",
|
||||
price: 2999
|
||||
},
|
||||
"BlackBox Shop": {
|
||||
description: "Создание магазина в Telegram через бота. Загрузка товаров, описание, цена. Оплата за товары через криптовалюту. Полная анонимность продавца и покупателя.",
|
||||
price: 499 // Assuming a base price for the shop
|
||||
},
|
||||
"Защита данных": {
|
||||
description: "Полная защита ваших персональных данных. Включает: мониторинг утечек, защиту от фишинга, безопасное хранение паролей, регулярные обновления безопасности.",
|
||||
price: 49 // per month
|
||||
},
|
||||
"Облачное хранилище": {
|
||||
description: "Защищенное хранилище файлов с end-to-end шифрованием. Доступ с любого устройства. Автоматическое резервное копирование. Совместимость со всеми популярными форматами.",
|
||||
price: 29 // per month
|
||||
},
|
||||
"Приватный чат": {
|
||||
description: "Полностью анонимные переписки с end-to-end шифрованием. Нет логов сообщений. Поддержка групповых чатов. Совместимость с другими мессенджерами.",
|
||||
price: 19 // per month
|
||||
},
|
||||
"Анонимный email": {
|
||||
description: "Полностью анонимная почта без привязки к личности. Временные адреса. Шифрование всех входящих/исходящих сообщений. Защита от спама.",
|
||||
price: 39 // per month
|
||||
},
|
||||
"Крипто-кошелек": {
|
||||
description: "Изолированный cold-wallet для хранения и операций криптовалютой с максимальной изоляцией от internet-угроз. Поддержка основных блокчейнов.",
|
||||
price: 59 // per month
|
||||
},
|
||||
"Децентрализованный хостинг": {
|
||||
description: "Размещение сайтов и приложений без центрального сервера. Полная анонимность владельца. Защита от DDoS. Автоматическое масштабирование.",
|
||||
price: 79 // per month
|
||||
}
|
||||
};
|
||||
|
||||
function showBlackBoxProductDetails(productName) {
|
||||
console.log('showBlackBoxProductDetails called with:', productName);
|
||||
|
||||
// Verify productsData exists and has the product
|
||||
if (!productsData) {
|
||||
console.error('productsData is not defined!');
|
||||
return;
|
||||
}
|
||||
if (!productsData[productName]) {
|
||||
console.error('Product not found in productsData:', productName);
|
||||
return;
|
||||
}
|
||||
|
||||
const modal = document.getElementById('productModal');
|
||||
if (!modal) {
|
||||
console.error('Modal element not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Force remove any inline display:none styles
|
||||
modal.style.display = 'flex';
|
||||
|
||||
const titleEl = document.getElementById('modalTitle');
|
||||
const descEl = document.getElementById('modalDescription');
|
||||
|
||||
if (titleEl) titleEl.textContent = productName;
|
||||
if (descEl) descEl.textContent = productsData[productName].description;
|
||||
|
||||
// Ensure modal is visible
|
||||
modal.classList.remove('hidden');
|
||||
|
||||
// Debug modal state after changes
|
||||
setTimeout(() => {
|
||||
console.log('Modal state after show:', {
|
||||
classList: Array.from(modal.classList),
|
||||
computedDisplay: window.getComputedStyle(modal).display,
|
||||
computedOpacity: window.getComputedStyle(modal).opacity,
|
||||
computedVisibility: window.getComputedStyle(modal).visibility,
|
||||
computedZIndex: window.getComputedStyle(modal).zIndex,
|
||||
computedPointerEvents: window.getComputedStyle(modal).pointerEvents
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function hideBlackBoxProductDetails() {
|
||||
const modal = document.getElementById('productModal');
|
||||
modal.classList.add('hidden');
|
||||
console.log('Product modal hidden');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOMContentLoaded - Adding event listeners');
|
||||
|
||||
// Debug: Log all elements with onclick handlers
|
||||
const detailButtons = document.querySelectorAll('[onclick^="showProductDetails"]');
|
||||
console.log('Found', detailButtons.length, 'detail buttons');
|
||||
detailButtons.forEach(btn => {
|
||||
const originalOnClick = btn.onclick;
|
||||
btn.onclick = function(e) {
|
||||
console.log('Detail button clicked:', {
|
||||
element: e.target,
|
||||
product: e.target.getAttribute('onclick').match(/'([^']+)'/)[1],
|
||||
stack: new Error().stack
|
||||
});
|
||||
return originalOnClick.call(this, e);
|
||||
};
|
||||
});
|
||||
|
||||
// Connect all buy buttons to show crypto modal and pass product price
|
||||
const buyButtons = document.querySelectorAll('.buy-btn');
|
||||
console.log('Found', buyButtons.length, 'buy buttons');
|
||||
buyButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function(e) {
|
||||
console.log('Buy button clicked', e.target);
|
||||
// Find the parent glass-card to get the product name and price
|
||||
const productCard = e.target.closest('.glass-card');
|
||||
if (productCard) {
|
||||
const productNameElement = productCard.querySelector('h3');
|
||||
if (productNameElement) {
|
||||
const productName = productNameElement.textContent.trim();
|
||||
const product = productsData[productName];
|
||||
if (product && product.price) {
|
||||
showCryptoModal(product.price);
|
||||
} else {
|
||||
console.error('Product price not found for:', productName);
|
||||
// Optionally show the modal without price calculation or show an error message
|
||||
showCryptoModal(0); // Pass 0 or handle error in showCryptoModal
|
||||
}
|
||||
} else {
|
||||
console.error('Product name element not found in card');
|
||||
showCryptoModal(0);
|
||||
}
|
||||
} else {
|
||||
console.error('Product card not found for buy button');
|
||||
showCryptoModal(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Debug modal close button
|
||||
const modalClose = document.querySelector('.modal-close');
|
||||
if (modalClose) {
|
||||
console.log('Found modal close button');
|
||||
modalClose.addEventListener('click', function(e) {
|
||||
console.log('Modal close clicked');
|
||||
hideBlackBoxProductDetails();
|
||||
});
|
||||
}
|
||||
|
||||
const dropdownItems = document.querySelectorAll('.dropdown-item');
|
||||
const menuButtons = document.querySelectorAll('.dropdown-item button');
|
||||
const contentAreas = document.querySelectorAll('.content-area');
|
||||
|
||||
function activateCategory(index) {
|
||||
// Remove active class from all menu items and content areas
|
||||
dropdownItems.forEach(item => item.classList.remove('active'));
|
||||
contentAreas.forEach(area => area.classList.remove('active'));
|
||||
|
||||
// Add active class to the selected menu item and content area
|
||||
dropdownItems[index].classList.add('active');
|
||||
const targetId = menuButtons[index].getAttribute('data-target');
|
||||
const targetContentArea = document.getElementById(targetId);
|
||||
if (targetContentArea) {
|
||||
targetContentArea.classList.add('active');
|
||||
}
|
||||
|
||||
// Rotate icon for active item
|
||||
menuButtons.forEach((button, btnIndex) => {
|
||||
const icon = button.querySelector('i'); // Get icon reference here
|
||||
if (index === btnIndex) {
|
||||
icon.style.transform = 'rotate(90deg)';
|
||||
icon.classList.add('active-arrow');
|
||||
} else {
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
icon.classList.remove('active-arrow');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize the first category as active
|
||||
activateCategory(0);
|
||||
|
||||
menuButtons.forEach((button, index) => {
|
||||
const icon = button.querySelector('i'); // Get icon reference here
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
activateCategory(index);
|
||||
});
|
||||
|
||||
// Handle hover for icon rotation on desktop
|
||||
// Handle arrow rotation and glow effect
|
||||
button.addEventListener('click', () => {
|
||||
const isActive = button.parentElement.classList.contains('active');
|
||||
icon.style.transform = isActive ? 'rotate(90deg)' : 'rotate(0deg)';
|
||||
|
||||
if (isActive) {
|
||||
icon.classList.add('active-arrow');
|
||||
} else {
|
||||
icon.classList.remove('active-arrow');
|
||||
}
|
||||
});
|
||||
|
||||
// Desktop hover effects
|
||||
if (window.innerWidth >= 768) {
|
||||
button.addEventListener('mouseenter', () => {
|
||||
if (!button.parentElement.classList.contains('active')) {
|
||||
icon.style.transform = 'rotate(90deg)';
|
||||
}
|
||||
button.style.transform = 'translateX(5px)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', () => {
|
||||
if (!button.parentElement.classList.contains('active')) {
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
}
|
||||
button.style.transform = '';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Add click handlers for product cards (if needed, currently handled by onclick)
|
||||
// document.querySelectorAll('.product-card').forEach(card => {
|
||||
// card.addEventListener('click', () => {
|
||||
// const productName = card.querySelector('h3').textContent;
|
||||
// showProductDetails(productName);
|
||||
// });
|
||||
// });
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('productModal').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('productModal')) {
|
||||
hideBlackBoxProductDetails();
|
||||
}
|
||||
});
|
||||
|
||||
// Close crypto modal when clicking outside
|
||||
document.getElementById('cryptoModal').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('cryptoModal')) {
|
||||
hideCryptoModal();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user