interior-home / script.js
adowu's picture
✨ Premium refinement — new photos, polished microinteractions, editorial spacing
0ef8402 verified
/* ============================================
AW Interiors — Premium Script v3
Elite microinteractions & animations
============================================ */
// ─── PRELOADER ──────────────────────────────
document.body.style.overflow = 'hidden';
window.addEventListener('load', () => {
const fill = document.getElementById('preloaderFill');
const preloader = document.getElementById('preloader');
if (!fill || !preloader) return;
requestAnimationFrame(() => { fill.style.width = '100%'; });
setTimeout(() => {
preloader.classList.add('hidden');
document.body.style.overflow = 'auto';
initCounters();
initReveal();
}, 2100);
});
// ─── CUSTOM CURSOR ───────────────────────────
const cursor = document.getElementById('cursor');
const follower = document.getElementById('cursor-follower');
if (cursor && follower) {
let mX = window.innerWidth / 2;
let mY = window.innerHeight / 2;
let fX = mX, fY = mY;
let raf;
document.addEventListener('mousemove', (e) => {
mX = e.clientX;
mY = e.clientY;
cursor.style.left = mX + 'px';
cursor.style.top = mY + 'px';
});
document.addEventListener('mousedown', () => document.body.classList.add('cursor-click'));
document.addEventListener('mouseup', () => document.body.classList.remove('cursor-click'));
document.addEventListener('mouseleave', () => { cursor.style.opacity = '0'; follower.style.opacity = '0'; });
document.addEventListener('mouseenter', () => { cursor.style.opacity = ''; follower.style.opacity = ''; });
(function loopFollower() {
fX += (mX - fX) * 0.095;
fY += (mY - fY) * 0.095;
follower.style.left = fX + 'px';
follower.style.top = fY + 'px';
requestAnimationFrame(loopFollower);
})();
const hoverTargets = 'a, button, .portfolio-item, .tag, .filter-btn, .process-step, .testimonial-card, .award-item, .contact-detail';
document.querySelectorAll(hoverTargets).forEach(el => {
el.addEventListener('mouseenter', () => document.body.classList.add('cursor-hover'));
el.addEventListener('mouseleave', () => document.body.classList.remove('cursor-hover'));
});
}
// ─── NAV SCROLL ──────────────────────────────
const nav = document.getElementById('nav');
let lastScrollY = 0;
window.addEventListener('scroll', () => {
const y = window.scrollY;
if (nav) nav.classList.toggle('scrolled', y > 60);
lastScrollY = y;
}, { passive: true });
// ─── MOBILE NAV ───────────────────────────────
const navToggle = document.getElementById('navToggle');
const navMobile = document.getElementById('navMobile');
if (navToggle && navMobile) {
navToggle.addEventListener('click', () => {
const open = navMobile.classList.toggle('open');
navToggle.classList.toggle('open', open);
navToggle.setAttribute('aria-expanded', String(open));
document.body.style.overflow = open ? 'hidden' : '';
});
navMobile.querySelectorAll('a').forEach(a => {
a.addEventListener('click', () => {
navMobile.classList.remove('open');
navToggle.classList.remove('open');
document.body.style.overflow = '';
});
});
}
// ─── PARTICLES ────────────────────────────────
(function createParticles() {
const container = document.getElementById('heroParticles');
if (!container) return;
const style = document.createElement('style');
style.textContent = `
@keyframes pFloat {
0%,100%{transform:translateY(0) translateX(0) scale(1);opacity:var(--op)}
30%{transform:translateY(-24px) translateX(14px) scale(1.12);opacity:calc(var(--op)*1.6)}
65%{transform:translateY(16px) translateX(-10px) scale(0.88);opacity:calc(var(--op)*0.5)}
}
`;
document.head.appendChild(style);
for (let i = 0; i < 28; i++) {
const p = document.createElement('div');
const size = (Math.random() * 2.8 + 0.5).toFixed(1);
const op = (Math.random() * 0.22 + 0.04).toFixed(2);
p.style.cssText = [
'position:absolute',
`width:${size}px`, `height:${size}px`,
'background:rgba(200,169,106,1)',
'border-radius:50%',
`left:${(Math.random() * 92 + 4).toFixed(1)}%`,
`top:${(Math.random() * 92 + 4).toFixed(1)}%`,
`--op:${op}`,
`opacity:${op}`,
`animation:pFloat ${(Math.random() * 12 + 9).toFixed(1)}s ease-in-out infinite`,
`animation-delay:-${(Math.random() * 8).toFixed(1)}s`,
'pointer-events:none',
'will-change:transform'
].join(';');
container.appendChild(p);
}
})();
// ─── REVEAL ON SCROLL ─────────────────────────
let revealObserver;
function initReveal() {
revealObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;
const el = entry.target;
el.classList.add('visible');
revealObserver.unobserve(el);
});
}, { threshold: 0.07, rootMargin: '0px 0px -48px 0px' });
document.querySelectorAll('.reveal').forEach((el) => {
const siblings = Array.from(el.parentElement.querySelectorAll('.reveal'));
const idx = siblings.indexOf(el);
if (idx > 0 && idx < 6) {
const existing = parseFloat(el.style.transitionDelay) || 0;
el.style.transitionDelay = (existing + idx * 0.09) + 's';
}
revealObserver.observe(el);
});
}
// ─── COUNTER ANIMATION ────────────────────────
function initCounters() {
const easeOutExpo = t => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
document.querySelectorAll('.hero-stat-num').forEach(el => {
const target = parseInt(el.dataset.count, 10);
if (!target) return;
const dur = 2000;
const start = performance.now();
function tick(now) {
const p = Math.min((now - start) / dur, 1);
el.textContent = Math.round(easeOutExpo(p) * target);
if (p < 1) requestAnimationFrame(tick);
else el.textContent = target;
}
requestAnimationFrame(tick);
});
}
// ─── PORTFOLIO FILTER ─────────────────────────
const filterBtns = document.querySelectorAll('.filter-btn');
const portfolioItems = document.querySelectorAll('.portfolio-item');
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
if (btn.classList.contains('active')) return;
filterBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const filter = btn.dataset.filter;
let delay = 0;
portfolioItems.forEach(item => {
const match = filter === 'all' || item.dataset.category === filter;
if (match) {
item.classList.remove('filtered-out');
item.style.opacity = '0';
item.style.transform = 'translateY(12px) scale(0.98)';
item.style.transition = 'none';
requestAnimationFrame(() => {
setTimeout(() => {
item.style.transition = `opacity 0.55s ease ${delay}s, transform 0.55s cubic-bezier(0.16,1,0.3,1) ${delay}s`;
item.style.opacity = '1';
item.style.transform = 'translateY(0) scale(1)';
}, 16);
});
delay += 0.06;
} else {
item.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
item.style.opacity = '0';
item.style.transform = 'scale(0.97)';
setTimeout(() => {
item.classList.add('filtered-out');
item.style.opacity = '';
item.style.transform = '';
item.style.transition = '';
}, 310);
}
});
});
});
// ─── MAGNETIC BUTTONS ─────────────────────────
document.querySelectorAll('.btn-primary, .nav-cta').forEach(btn => {
btn.addEventListener('mousemove', (e) => {
const rect = btn.getBoundingClientRect();
const dx = (e.clientX - rect.left - rect.width / 2) * 0.22;
const dy = (e.clientY - rect.top - rect.height / 2) * 0.22;
btn.style.transform = `translate(${dx}px, ${dy}px)`;
});
btn.addEventListener('mouseleave', () => {
btn.style.transform = '';
});
});
// ─── CONTACT FORM ─────────────────────────────
const form = document.getElementById('contactForm');
const formSuccess = document.getElementById('formSuccess');
if (form) {
form.addEventListener('submit', (e) => {
e.preventDefault();
const btn = form.querySelector('button[type="submit"]');
if (btn.disabled) return;
const originalHTML = btn.innerHTML;
btn.innerHTML = `<span>Wysyłanie</span><svg width="18" height="18" viewBox="0 0 24 24" fill="none" style="animation:spinBtn 0.85s linear infinite"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="1.5" stroke-dasharray="40 22" stroke-linecap="round"/></svg>`;
btn.disabled = true;
if (!document.getElementById('spinBtnStyle')) {
const s = document.createElement('style');
s.id = 'spinBtnStyle';
s.textContent = '@keyframes spinBtn{to{rotate:360deg}}';
document.head.appendChild(s);
}
setTimeout(() => {
form.reset();
if (formSuccess) {
formSuccess.classList.add('visible');
setTimeout(() => formSuccess.classList.remove('visible'), 5500);
}
btn.innerHTML = originalHTML;
btn.disabled = false;
}, 1700);
});
// Live label animation for select
const select = form.querySelector('select');
if (select) {
select.style.color = 'rgba(244,239,232,0.3)';
select.addEventListener('change', () => {
select.style.color = select.value ? 'var(--white)' : 'rgba(244,239,232,0.3)';
});
}
}
// ─── SMOOTH ANCHOR SCROLL ─────────────────────
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener('click', (e) => {
const href = link.getAttribute('href');
if (href === '#') return;
const target = document.querySelector(href);
if (target) {
e.preventDefault();
const navH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--nav-h'), 10) || 78;
const offset = target.getBoundingClientRect().top + window.scrollY - navH;
window.scrollTo({ top: offset, behavior: 'smooth' });
}
});
});
// ─── PARALLAX ─────────────────────────────────
function onScroll() {
const y = window.scrollY;
const heroGrid = document.querySelector('.hero-grid');
if (heroGrid && y < window.innerHeight * 1.6) {
heroGrid.style.transform = `translateY(${y * 0.22}px)`;
}
const philoBg = document.querySelector('.philosophy-bg');
if (philoBg) {
const rect = philoBg.parentElement.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
const progress = (window.innerHeight - rect.top) / (window.innerHeight + rect.height);
philoBg.style.transform = `scale(1.06) translateY(${(progress - 0.5) * -28}px)`;
}
}
}
window.addEventListener('scroll', onScroll, { passive: true });
// ─── SECTION SEPARATOR LINES ──────────────────
const sepStyle = document.createElement('style');
sepStyle.textContent = `
.section-sep{height:1px;background:linear-gradient(to right,transparent,rgba(200,169,106,0.28),transparent);transform:scaleX(0);transform-origin:left;transition:transform 1.3s cubic-bezier(0.16,1,0.3,1)}
.section-sep.line-visible{transform:scaleX(1)}
`;
document.head.appendChild(sepStyle);
const lineObs = new IntersectionObserver((entries) => {
entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('line-visible'); });
}, { threshold: 0.3 });
document.querySelectorAll('.section-sep').forEach(el => lineObs.observe(el));
// ─── TILT ON HOVER — PORTFOLIO CARDS ──────────
document.querySelectorAll('.portfolio-item').forEach(card => {
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
card.style.transform = `translateY(-3px) rotateX(${-y * 4}deg) rotateY(${x * 4}deg)`;
});
card.addEventListener('mouseleave', () => {
card.style.transform = '';
});
});