na-kakuyu-temu-mozhno-sozdat/app.js

167 lines
5.0 KiB
JavaScript

// ===================================
// APPLE-STYLE APP - FRONTEND
// ===================================
const API = {
products: '/api/products',
announcements: '/api/announcements',
settings: '/api/settings'
};
// Load settings and content
async function init() {
await loadSettings();
await loadAnnouncements();
await loadProducts();
setupScrollEffects();
setupRevealAnimations();
}
// Load site settings
async function loadSettings() {
try {
const res = await fetch(API.settings);
const json = await res.json();
if (json.ok && json.data) {
document.getElementById('heroTitle').textContent = json.data.heroTitle || 'Добро пожаловать';
document.getElementById('heroSubtitle').textContent = json.data.heroSubtitle || 'Инновации здесь';
}
} catch (e) {
console.error('Failed to load settings:', e);
}
}
// Load announcements
async function loadAnnouncements() {
try {
const res = await fetch(API.announcements);
const json = await res.json();
const bar = document.getElementById('announcementBar');
if (json.ok && json.data.length > 0) {
const ann = json.data[0];
bar.innerHTML = `${ann.title} — ${ann.content} <a href="#">Подробнее →</a>`;
} else {
bar.classList.add('hidden');
}
} catch (e) {
console.error('Failed to load announcements:', e);
document.getElementById('announcementBar').classList.add('hidden');
}
}
// Load products
async function loadProducts() {
try {
const res = await fetch(API.products);
const json = await res.json();
const container = document.getElementById('productsContainer');
if (!json.ok || !json.data) {
container.innerHTML = '<p style="text-align:center;color:var(--text-secondary)">Нет продуктов</p>';
return;
}
container.innerHTML = json.data.map((p, i) => `
<div class="product-card" style="transition-delay: ${i * 100}ms">
<img src="${p.image}" alt="${p.name}" class="product-image">
<div class="product-content">
<h3 class="product-name">${p.name}</h3>
<p class="product-tagline">${p.tagline}</p>
<p class="product-price">от ${p.price} $</p>
<div class="product-features">
${p.features.map(f => `<span class="feature-tag">${f}</span>`).join('')}
</div>
</div>
</div>
`).join('');
// Trigger visibility check after load
setTimeout(checkProductVisibility, 100);
} catch (e) {
console.error('Failed to load products:', e);
document.getElementById('productsContainer').innerHTML = '<p style="text-align:center;color:var(--text-secondary)">Ошибка загрузки</p>';
}
}
// Scroll effects for navigation
function setupScrollEffects() {
const nav = document.getElementById('nav');
const heroBg = document.getElementById('heroBg');
const featuresBg = document.getElementById('featuresBg');
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
// Nav background
if (scrolled > 100) {
nav.classList.add('scrolled');
} else {
nav.classList.remove('scrolled');
}
// Hero parallax
if (scrolled < window.innerHeight) {
heroBg.style.transform = `translateY(${scrolled * 0.5}px) scale(${1 + scrolled * 0.0008})`;
}
// Features parallax
const featuresSection = document.getElementById('features');
if (featuresSection) {
const rect = featuresSection.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
const offset = (window.innerHeight - rect.top) * 0.2;
featuresBg.style.transform = `translateY(${offset}px)`;
}
}
});
}
// Reveal animations on scroll
function setupRevealAnimations() {
const reveals = document.querySelectorAll('.reveal');
const checkReveal = () => {
reveals.forEach(el => {
const top = el.getBoundingClientRect().top;
const trigger = window.innerHeight * 0.85;
if (top < trigger) {
el.classList.add('active');
}
});
};
window.addEventListener('scroll', checkReveal);
checkReveal();
}
// Check product cards visibility
function checkProductVisibility() {
const cards = document.querySelectorAll('.product-card');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, { threshold: 0.1 });
cards.forEach(card => observer.observe(card));
}
// Smooth scroll for anchor links
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
const href = this.getAttribute('href');
if (href !== '#') {
e.preventDefault();
const target = document.querySelector(href);
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
});
});
init();
});