O mně
Služby
Ceník
Galerie
Recenze
Kontakt
Galerie · Portfolio

Svatební focení

Od ranních příprav po poslední tanec. Každý záběr s citem pro váš příběh.

Rodinné focení

Přirozené momenty, radost a smích. Vaše rodina tak, jak ji znáte.

Těhotenské focení

Jemné, přirozené. Krása čekání zachycená navždy.

Portréty

Osobní portréty, které zachycují charakter každého člověka.

Zaujalo vás moje portfolio?

Ozvěte se mi a společně zachytíme vaše nejkrásnější momenty.

Nezávazná poptávka
const blobs = [ { x: 0.1, y: 0.2, r: 0.15, phase: 0, color: 'rgba(139,94,60,0.06)' }, { x: 0.85, y: 0.35, r: 0.2, phase: 2, color: 'rgba(139,94,60,0.04)' }, { x: 0.5, y: 0.75, r: 0.14, phase: 4, color: 'rgba(176,125,82,0.05)' }, { x: 0.15, y: 0.8, r: 0.18, phase: 1, color: 'rgba(139,94,60,0.05)' }, ]; function drawBlob(cx, cy, r, t, color) { ctx.beginPath(); const pts = 8; for (let i = 0; i <= pts * 2; i++) { const angle = (i / pts) * Math.PI; const wobble = r * (0.15 * Math.sin(t * 2 + i * 1.3) + 0.1 * Math.cos(t * 1.5 + i * 0.9)); const rad = r + wobble; const x = cx + Math.cos(angle) * rad; const y = cy + Math.sin(angle) * rad; i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); } ctx.closePath(); ctx.fillStyle = color; ctx.fill(); } let t = 0; function animateCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); t += 0.004; blobs.forEach(b => { const bx = b.x * canvas.width + Math.sin(t + b.phase) * 60; const by = b.y * canvas.height + Math.cos(t * 0.8 + b.phase) * 50; drawBlob(bx, by, b.r * Math.min(canvas.width, canvas.height), t + b.phase, b.color); }); requestAnimationFrame(animateCanvas); } animateCanvas(); // ── GENERATE GALLERY ITEMS const catConfig = [ { cat: 'svatba', count: 110, label: 'Svatební' }, { cat: 'rodina', count: 61, label: 'Rodinné' }, { cat: 'tehotenstvi', count: 93, label: 'Těhotenské' }, { cat: 'portret', count: 37, label: 'Portréty' }, ]; const catLabels = { svatba: 'Svatební', rodina: 'Rodinné', tehotenstvi: 'Těhotenské', portret: 'Portréty' }; let total = 0; catConfig.forEach(({ cat, count, label }) => { total += count; const el = document.getElementById(`cnt-${cat}`); if (el) el.textContent = count; const masonry = document.getElementById(`masonry-${cat}`); if (!masonry) return; for (let i = 1; i <= count; i++) { const num = String(i).padStart(2, '0'); const div = document.createElement('div'); div.className = 'm-item'; div.dataset.cat = cat; div.innerHTML = ` ${label}
Zobrazit
`; div.addEventListener('click', () => openLightbox(div)); masonry.appendChild(div); } }); document.getElementById('cnt-all').textContent = total; // ── MOBILE NAV const mobileNav = document.getElementById('mobileNav'); const ham = document.getElementById('ham'); const navClose = document.getElementById('navClose'); function openMobileNav() { mobileNav.classList.add('open'); document.body.style.overflow='hidden'; } function closeMobileNav() { mobileNav.classList.remove('open'); document.body.style.overflow=''; } ham.addEventListener('click', openMobileNav); navClose.addEventListener('click', closeMobileNav); mobileNav.querySelectorAll('a').forEach(a => a.addEventListener('click', closeMobileNav)); // ── FILTER const sections = ['svatba', 'rodina', 'tehotenstvi', 'portret']; document.querySelectorAll('.filter-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); const filter = btn.dataset.filter; sections.forEach(cat => { const sec = document.getElementById(`sec-${cat}`); const div = sec.nextElementSibling; const show = filter === 'all' || filter === cat; sec.dataset.hidden = show ? 'false' : 'true'; if (div && div.classList.contains('section-divider')) div.style.display = show ? '' : 'none'; }); const first = document.querySelector('.cat-section:not([data-hidden="true"])'); if (first) window.scrollTo({ top: first.getBoundingClientRect().top + scrollY - 130, behavior: 'smooth' }); }); }); // ── SCROLL REVEAL const io = new IntersectionObserver(entries => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('visible'); io.unobserve(e.target); } }); }, { threshold: 0.08 }); document.querySelectorAll('.reveal').forEach(el => io.observe(el)); // ── LIGHTBOX let currentIdx = 0, visibleItems = []; function getVisibleItems() { return Array.from(document.querySelectorAll('.cat-section:not([data-hidden="true"]) .m-item')); } function openLightbox(item) { visibleItems = getVisibleItems(); currentIdx = visibleItems.indexOf(item); renderLightbox(); document.getElementById('lightbox').classList.add('open'); document.body.style.overflow = 'hidden'; } function renderLightbox() { const item = visibleItems[currentIdx]; const cat = item.dataset.cat; const img = item.querySelector('img'); const content = document.getElementById('lbContent'); if (img) { content.innerHTML = `${img.alt || ''}`; } else { content.innerHTML = `

Vaše fotografie

`; } document.getElementById('lbCat').textContent = catLabels[cat] || ''; document.getElementById('lbCounter').textContent = `${currentIdx + 1} / ${visibleItems.length}`; } function closeLightbox() { document.getElementById('lightbox').classList.remove('open'); document.body.style.overflow = ''; } document.getElementById('lbClose').addEventListener('click', closeLightbox); document.getElementById('lightbox').addEventListener('click', e => { if (e.target === document.getElementById('lightbox')) closeLightbox(); }); document.getElementById('lbPrev').addEventListener('click', () => { currentIdx = (currentIdx - 1 + visibleItems.length) % visibleItems.length; renderLightbox(); }); document.getElementById('lbNext').addEventListener('click', () => { currentIdx = (currentIdx + 1) % visibleItems.length; renderLightbox(); }); document.addEventListener('keydown', e => { if (!document.getElementById('lightbox').classList.contains('open')) return; if (e.key === 'Escape') closeLightbox(); if (e.key === 'ArrowLeft') { currentIdx = (currentIdx - 1 + visibleItems.length) % visibleItems.length; renderLightbox(); } if (e.key === 'ArrowRight') { currentIdx = (currentIdx + 1) % visibleItems.length; renderLightbox(); } });