diff --git a/assets/hero-background.png b/assets/hero-background.png new file mode 100644 index 0000000..bd1fd95 Binary files /dev/null and b/assets/hero-background.png differ diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..328c356 --- /dev/null +++ b/css/style.css @@ -0,0 +1,336 @@ +/* ========================================================================== + STYLE.CSS - Spletna stran za Brezplačno snemanje porok + ========================================================================== */ + +/* -------------------------------------------------------------------------- */ +/* 0. UVOZ PISAV, SPREMENLJIVKE IN GLOBALNI RESET +/* -------------------------------------------------------------------------- */ + +/* Uvoz pisav iz Google Fonts */ +@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Lato:wght@400;700&display=swap'); + +:root { + /* -- Barvna paleta -- */ + --color-background: #FDFCFB; /* Topla, skoraj bela barva za ozadje */ + --color-text: #333333; /* Temno siva za glavno besedilo */ + --color-headings: #2c2c2c; /* Še temnejša za naslove */ + --color-accent: #c5a47e; /* Elegantna zlato-peščena barva za poudarke */ + --color-accent-hover: #b3916b; /* Temnejša različica za hover efekte */ + --color-border: #e0e0e0; /* Svetlo siva za subtilne robove */ + --color-success: #2ecc71; /* Zelena za sporočila o uspehu */ + --color-error: #e74c3c; /* Rdeča za sporočila o napakah */ + + /* -- Tipografija -- */ + --font-primary: 'Lato', sans-serif; + --font-headings: 'Playfair Display', serif; + + /* -- Razmiki in dimenzije -- */ + --spacing-xs: 0.5rem; /* 8px */ + --spacing-sm: 1rem; /* 16px */ + --spacing-md: 2rem; /* 32px */ + --spacing-lg: 4rem; /* 64px */ + --spacing-xl: 6rem; /* 96px */ + + --border-radius: 5px; + --max-width: 1140px; + --transition-speed: 0.3s; +} + +/* Osnovni reset za dosleden izgled v vseh brskalnikih */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + scroll-behavior: smooth; + font-size: 16px; +} + +body { + font-family: var(--font-primary); + line-height: 1.7; + color: var(--color-text); + background-color: var(--color-background); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +/* -------------------------------------------------------------------------- */ +/* 1. OSNOVNI ELEMENTI IN TIPOGRAFIJA +/* -------------------------------------------------------------------------- */ + +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-headings); + color: var(--color-headings); + line-height: 1.2; + font-weight: 700; + margin-bottom: var(--spacing-sm); +} + +/* Uporaba clamp() za fluidno velikost pisave med različnimi širinami zaslona */ +h1 { font-size: clamp(2.5rem, 5vw, 4rem); } +h2 { font-size: clamp(2rem, 4vw, 3rem); } +h3 { font-size: clamp(1.5rem, 3vw, 2rem); } + +p { + margin-bottom: var(--spacing-sm); +} + +a { + color: var(--color-accent); + text-decoration: none; + transition: color var(--transition-speed) ease; +} + +a:hover, a:focus { + color: var(--color-accent-hover); +} + + +/* -------------------------------------------------------------------------- */ +/* 2. POSTAVITEV IN POMOŽNI RAZREDI +/* -------------------------------------------------------------------------- */ + +.container { + width: 90%; + max-width: var(--max-width); + margin-left: auto; + margin-right: auto; +} + +.section { + padding: var(--spacing-lg) 0; +} + +.text-center { + text-align: center; +} + +/* Stil za gumbe */ +.btn { + display: inline-block; + padding: 0.9rem 2rem; + font-family: var(--font-primary); + font-weight: 700; + font-size: 1rem; + text-transform: uppercase; + letter-spacing: 1px; + color: #fff; + background-color: var(--color-accent); + border: none; + border-radius: var(--border-radius); + cursor: pointer; + transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease; +} + +.btn:hover, .btn:focus { + background-color: var(--color-accent-hover); + transform: translateY(-3px); + box-shadow: 0 4px 10px rgba(0,0,0,0.1); +} + + +/* -------------------------------------------------------------------------- */ +/* 3. STILI POSAMEZNIH SEKCIJ +/* -------------------------------------------------------------------------- */ + +/* -- Hero sekcija -- */ +#hero-section { + position: relative; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + color: #fff; + overflow: hidden; /* Skrije dele ozadja, ki se premaknejo ven */ +} + +/* Ozadje za parallax efekt */ +.hero-background { + position: absolute; + top: -30px; left: -30px; right: -30px; bottom: -30px; /* Večje od vidnega polja */ + background: url('https://images.unsplash.com/photo-1523438885262-e6252c869911?auto=format&fit=crop&w=1920&q=80') no-repeat center center/cover; + z-index: -2; + transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); /* Gladki prehodi za JS animacijo */ +} + +/* Temen overlay za boljšo berljivost besedila */ +#hero-section::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: -1; +} + +.hero-content { + max-width: 800px; +} + +.hero-content .subtitle { + font-size: clamp(1rem, 2.5vw, 1.25rem); + margin-bottom: var(--spacing-md); + font-weight: 400; + line-height: 1.6; +} + +/* -- Sekcija O nas / Opis storitve -- */ +#about-section { + background-color: #fff; +} + +/* -- Sekcija s koraki / procesom -- */ +.process-grid { + display: grid; + gap: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.process-step { + border: 1px solid var(--color-border); + padding: var(--spacing-md); + border-radius: var(--border-radius); + background-color: #fff; +} + +.process-step .step-number { + font-size: 2.5rem; + font-family: var(--font-headings); + color: var(--color-accent); + margin-bottom: var(--spacing-xs); +} + +/* -- Kontaktni obrazec -- */ +#form-section { + background-color: var(--color-background); +} + +#contact-form { + max-width: 700px; + margin: 0 auto; + display: grid; + gap: var(--spacing-sm); +} + +.form-group { + display: flex; + flex-direction: column; +} + +input[type="text"], +input[type="email"], +input[type="date"], +textarea { + width: 100%; + padding: 0.9rem; + font-family: var(--font-primary); + font-size: 1rem; + border: 1px solid var(--color-border); + border-radius: var(--border-radius); + background-color: #fff; + transition: border-color var(--transition-speed) ease, box-shadow var(--transition-speed) ease; +} + +input[type="text"]:focus, +input[type="email"]:focus, +input[type="date"]:focus, +textarea:focus { + outline: none; + border-color: var(--color-accent); + box-shadow: 0 0 0 3px rgba(197, 164, 126, 0.2); +} + +textarea { + min-height: 150px; + resize: vertical; +} + +label { + margin-bottom: var(--spacing-xs); + font-weight: 700; +} + +/* -- Footer -- */ +.site-footer { + padding: var(--spacing-md) 0; + border-top: 1px solid var(--color-border); + background-color: #fff; +} + +/* -------------------------------------------------------------------------- */ +/* 4. ANIMACIJE IN STANJA OBRAZCA +/* -------------------------------------------------------------------------- */ + +/* Začetno stanje za elemente, ki se animirajo ob drsanju */ +.animate-on-scroll { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.8s cubic-bezier(0.645, 0.045, 0.355, 1), + transform 0.8s cubic-bezier(0.645, 0.045, 0.355, 1); +} + +/* Končno (vidno) stanje */ +.animate-on-scroll.is-visible { + opacity: 1; + transform: translateY(0); +} + +/* Stili za validacijo obrazca */ +.is-invalid { + border-color: var(--color-error); +} + +.error-message { + color: var(--color-error); + font-size: 0.875em; + display: block; + margin-top: 5px; +} + +#form-response { + display: none; /* Skrito po privzetem */ + padding: var(--spacing-sm); + border-radius: var(--border-radius); + margin-top: var(--spacing-sm); +} + +#form-response.success { + background-color: #eaf7ed; + color: #2b753c; + border: 1px solid var(--color-success); +} + +#form-response.error { + background-color: #fbe9e7; + color: var(--color-error); + border: 1px solid var(--color-error); +} + +/* -------------------------------------------------------------------------- */ +/* 5. MEDIA QUERIES (ODZIVNOST) +/* -------------------------------------------------------------------------- */ + +/* -- Tablice in večje naprave (768px in več) -- */ +@media (min-width: 768px) { + .section { + padding: var(--spacing-xl) 0; + } + + .process-grid { + grid-template-columns: repeat(3, 1fr); + } + + #contact-form { + grid-template-columns: 1fr 1fr; + /* Specifična polja raztegnemo čez obe koloni */ + .form-group.full-width { + grid-column: 1 / -1; + } + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..b915ccb --- /dev/null +++ b/index.html @@ -0,0 +1,255 @@ + + + + + + + Brezplačno Snemanje Poroke | Profesionalni Poročni Video Slovenija + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+

Brezplačno Snemanje Poroke: Ujemita Vajin Dan v Profesionalni Poročni Video

+

Iščeva zaročene pare po vsej Sloveniji, ki si želijo čustven in kinematografski poročni video – popolnoma brezplačno v zameno za uporabo posnetkov za najin portfelj. Število terminov je omejeno!

+ Prijavi se zdaj +
+
+ +
+ + +
+
+

Zakaj Ponujava Brezplačno Poročno Videografijo?

+

Sva strastna videografa na začetku svoje skupne poti v svetu poročne videografije. Verjameva, da ima vsaka ljubezenska zgodba moč, da navdihne. Zato iščeva pare, kot sta vidva, da nama pomagata zgraditi portfelj osupljivih poročnih zgodb. V zameno za vajino zaupanje prejmeta profesionalni poročni video, ustvarjen z najnovejšo opremo in polno mero kreativne energije, brez kakršnihkoli stroškov.

+
+
+ + +
+
+

Kaj Vključuje Brezplačni Poročni Video Paket?

+

Najina ponudba je transparentna. Prejmeta vse, kar potrebujeta za večen spomin.

+
    +
  • Profesionalni poročni video: 3-5 minutni, čustveno zmontiran film vajinega dne.
  • +
  • Snemanje z več kamerami: Za dinamične in raznolike posnetke.
  • +
  • Uporaba drona: Za dih jemajoče posnetke lokacije iz zraka (kjer je to mogoče in dovoljeno).
  • +
  • Kakovosten zvok: Snemanje govora in zaobljub z diskretnimi mikrofoni.
  • +
  • Digitalna dostava: Končni video v visoki ločljivosti (4K) preko spletne galerije.
  • +
+
+
+ + +
+
+

Najin Proces Snemanja Poroke v 3 Korakih

+
+
+
01
+

Prijava

+

Izpolnita obrazec na dnu strani z osnovnimi informacijami o vajini poroki. Bolj kot sta podrobna, lažje si vaju predstavljava.

+
+
+
02
+

Spoznavni klic

+

Če se vajina vizija ujema z najino, se dogovorimo za kratek spletni klic, kjer se spoznamo in pogovorimo o podrobnostih vajinega dne.

+
+
+
03
+

Snemanje

+

Na poročni dan sva z vama, diskretna in osredotočena na lovljenje pristnih trenutkov. Po poroki se lotiva montaže in vama dostaviva končni video.

+
+
+
+
+ + +
+
+

Zagotovita si Svoj Termin za Brezplačno Snemanje Poroke!

+

Mesta se hitro polnijo. Ne odlašajta in izpolnita prijavo še danes. Veseliva se vajine zgodbe!

+ +
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+ + +
+
+

Pogosta Vprašanja

+
+

Ali so res kakšni skriti stroški?

+

Ne. Ponudba je 100% brezplačna in ne vključuje nobenih skritih stroškov. Edini pogoj je podpis pogodbe, ki nama dovoljuje uporabo posnetkov za promocijske namene. Potni stroški znotraj Slovenije so vključeni.

+
+
+

Katere lokacije v Sloveniji pokrivata?

+

Pokrivava celotno Slovenijo! Iščeva pare iz vseh regij, od Gorenjske in Primorske do Štajerske in Prekmurja. Ne glede na to, ali je vaša lokacija Ljubljana, Maribor ali skriti kotiček narave, naju zanima.

+
+
+

Kako poteka izbor parov?

+

Ker je število terminov omejeno, bomo izbrali pare, katerih poročni dan in vizija se najbolj ujemata z najinim stilom snemanja. Iščemo unikatne zgodbe, zanimive lokacije in predvsem pristno energijo.

+
+
+
+ +
+ + + + + + + + + + + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..ad45940 --- /dev/null +++ b/js/main.js @@ -0,0 +1,218 @@ +/** + * main.js + * Glavna JavaScript datoteka za spletno stran "Brezplačno snemanje poroke". + * + * Funkcionalnosti: + * 1. Inicializacija vseh skript po nalaganju DOM-a. + * 2. Upravljanje animacij elementov ob drsanju strani (Intersection Observer). + * 3. Implementacija gladkega drsanja za interne povezave. + * 4. Interaktivni parallax efekt v "hero" sekciji, ki se odziva na premik miške. + * 5. Napredna validacija in pošiljanje kontaktnega obrazca preko Fetch API. + */ + +// Počakamo, da se celoten HTML dokument naloži, preden zaženemo skripte. +document.addEventListener('DOMContentLoaded', () => { + + // Inicializacija vseh glavnih funkcij + initScrollAnimations(); + initSmoothScrolling(); + initHeroParallaxEffect(); + initContactFormHandler(); + + console.log("Stran je pripravljena in vsi interaktivni elementi so aktivirani."); + +}); + + +/** + * Funkcija za inicializacijo animacij ob drsanju (Fade-in efekt). + * Uporablja Intersection Observer API za optimalno delovanje. + * Elementi z razredom .animate-on-scroll bodo postali vidni, ko vstopijo v vidno polje. + */ +function initScrollAnimations() { + const animatedElements = document.querySelectorAll('.animate-on-scroll'); + + if (!animatedElements.length) return; + + const observerOptions = { + root: null, // opazujemo glede na vidno polje brskalnika + rootMargin: '0px', + threshold: 0.1 // sproži se, ko je vsaj 10% elementa vidnega + }; + + const observer = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('is-visible'); + observer.unobserve(entry.target); // prenehamo opazovati, da se animacija zgodi samo enkrat + } + }); + }, observerOptions); + + animatedElements.forEach(element => { + observer.observe(element); + }); +} + + +/** + * Funkcija za implementacijo gladkega drsanja do sidrnih točk. + * Vsi linki, ki se začnejo z '#', bodo sprožili gladko drsenje namesto skoka. + */ +function initSmoothScrolling() { + const internalLinks = document.querySelectorAll('a[href^="#"]'); + + internalLinks.forEach(link => { + link.addEventListener('click', function(e) { + e.preventDefault(); + const targetId = this.getAttribute('href'); + const targetElement = document.querySelector(targetId); + + if (targetElement) { + targetElement.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + }); + }); +} + + +/** + * Funkcija za parallax efekt v "hero" sekciji, ki se odziva na premik miške. + * Predpostavlja obstoj elementa z ID-jem #hero-section in elementa v njem z razredom .hero-background. + */ +function initHeroParallaxEffect() { + const heroSection = document.querySelector('#hero-section'); + const heroBackground = document.querySelector('.hero-background'); + + if (!heroSection || !heroBackground) return; + + const parallaxStrength = 15; // Manjša vrednost = bolj subtilen efekt + + heroSection.addEventListener('mousemove', (e) => { + const { clientWidth, clientHeight } = heroSection; + const x = (e.clientX / clientWidth) - 0.5; + const y = (e.clientY / clientHeight) - 0.5; + + // Uporabimo transform za premik, kar je bolj učinkovito za animacije + heroBackground.style.transform = ` + translateX(${-x * parallaxStrength}px) + translateY(${-y * parallaxStrength}px) + scale(1.05)`; // Rahlo povečamo ozadje, da robovi niso vidni + }); + + heroSection.addEventListener('mouseleave', () => { + // Obnovimo pozicijo, ko miška zapusti območje + heroBackground.style.transform = 'translate(0, 0) scale(1.05)'; + }); +} + + +/** + * Funkcija za upravljanje kontaktnega obrazca. + * Vključuje validacijo na strani odjemalca in pošiljanje podatkov preko Fetch API. + * Predpostavlja, da ima obrazec ID #contact-form in da ga upravlja Netlify. + */ +function initContactFormHandler() { + const form = document.querySelector('#contact-form'); + if (!form) return; + + const submitButton = form.querySelector('button[type="submit"]'); + const formResponseEl = document.querySelector('#form-response'); // Element za prikaz sporočil + + form.addEventListener('submit', function(e) { + e.preventDefault(); + + // 1. Validacija polj + if (!validateForm(form)) { + return; // Ustavi pošiljanje, če validacija ne uspe + } + + // 2. Priprava podatkov za pošiljanje + const formData = new FormData(form); + const originalButtonText = submitButton.textContent; + submitButton.disabled = true; + submitButton.textContent = 'Pošiljanje...'; + + // 3. Pošiljanje preko Fetch API (prilagojeno za Netlify Forms) + fetch('/', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams(formData).toString() + }) + .then(response => { + if (response.ok) { + // Uspešno poslano + form.style.display = 'none'; // Skrij obrazec + formResponseEl.innerHTML = `

Hvala za prijavo!

Oglasili se vam bova v najkrajšem možnem času. Preverite svoj e-poštni nabiralnik.

`; + formResponseEl.classList.add('success'); + formResponseEl.style.display = 'block'; + } else { + // Napaka pri pošiljanju + throw new Error('Prišlo je do napake pri pošiljanju. Poskusite znova.'); + } + }) + .catch(error => { + formResponseEl.innerHTML = `

Napaka: ${error.message}

`; + formResponseEl.classList.add('error'); + formResponseEl.style.display = 'block'; + }) + .finally(() => { + // Ponastavi gumb samo v primeru napake, saj ob uspehu formo skrijemo + if (form.style.display !== 'none') { + submitButton.disabled = false; + submitButton.textContent = originalButtonText; + } + }); + }); +} + +/** + * Pomožna funkcija za validacijo polj v obrazcu. + * @param {HTMLFormElement} form - Obrazec, ki ga validiramo. + * @returns {boolean} - Vrne `true`, če so vsa polja veljavna, sicer `false`. + */ +function validateForm(form) { + let isValid = true; + const requiredFields = form.querySelectorAll('[required]'); + + // Najprej počistimo vse prejšnje napake + form.querySelectorAll('.error-message').forEach(el => el.remove()); + form.querySelectorAll('.is-invalid').forEach(el => el.classList.remove('is-invalid')); + + requiredFields.forEach(field => { + let error = null; + + if (field.value.trim() === '') { + error = 'To polje je obvezno.'; + } else if (field.type === 'email' && !isValidEmail(field.value)) { + error = 'Prosimo, vnesite veljaven e-poštni naslov.'; + } else if (field.type === 'date' && new Date(field.value) < new Date()) { + error = 'Datum poroke ne more biti v preteklosti.'; + } + + if (error) { + isValid = false; + field.classList.add('is-invalid'); + const errorElement = document.createElement('span'); + errorElement.className = 'error-message'; + errorElement.textContent = error; + // Vstavi sporočilo o napaki za poljem + field.parentNode.insertBefore(errorElement, field.nextSibling); + } + }); + + return isValid; +} + +/** + * Pomožna funkcija za preverjanje veljavnosti e-poštnega naslova. + * @param {string} email - E-poštni naslov za preverjanje. + * @returns {boolean} + */ +function isValidEmail(email) { + const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return regex.test(String(email).toLowerCase()); +} diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..e69de29