916d936332
Git archaeology: the grid was never a deliberate removal. It lived as a fixed `body::before` in index.html's inline <style> block and was dropped whenbed8675("D3 Part 2: index + kapcsolat on design system v2") migrated the page onto site.css.dd54e4c, which created site.css, has no body::before — it was a porting omission, and nothing took its place. No asset was lost; it was pure CSS. Restored at its original geometry and subtlety (50px cells, 1px lines, 3%), not redesigned. Only change: the accent is the v2 --blue #0083D8 instead of the retired legacy #0088cc, which site_gates.py bans. Scoped to body.page-index because index is the only page that ever had it. site.css cache-bust bumped to v=2 across all seven pages (nginx caches 7d). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nn3VgQk9iwEGgyx6QJ2NvE
598 lines
29 KiB
HTML
598 lines
29 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="hu">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Kapcsolat — Kérj személyre szabott ajánlatot otthoni szerveredhez | Felhom.eu</title>
|
|
<meta name="description" content="Írj nekünk és személyre szabott ajánlatot készítünk otthoni szerveredhez. Kérdésed van? Segítünk! Email: info@felhom.eu">
|
|
|
|
<meta name="keywords" content="kapcsolat, ajánlatkérés, otthoni szerver ajánlat, Felhom elérhetőség">
|
|
<meta name="robots" content="index, follow">
|
|
<link rel="canonical" href="https://felhom.eu/kapcsolat">
|
|
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:url" content="https://felhom.eu/kapcsolat">
|
|
<meta property="og:title" content="Kapcsolat — Felhom.eu">
|
|
<meta property="og:description" content="Írj nekünk és személyre szabott ajánlatot készítünk otthoni szerveredhez.">
|
|
<meta property="og:image" content="https://felhom.eu/assets/og-image.png">
|
|
<meta property="og:locale" content="hu_HU">
|
|
<meta property="og:site_name" content="Felhom.eu">
|
|
|
|
<meta name="twitter:card" content="summary">
|
|
<meta name="twitter:title" content="Kapcsolat — Felhom.eu">
|
|
<meta name="twitter:description" content="Kérdésed van? Írj nekünk: info@felhom.eu">
|
|
<meta name="twitter:image" content="https://felhom.eu/assets/og-image.png">
|
|
<!-- shared assets: bump ?v= together on any site.css/icons.svg change -->
|
|
<link rel="stylesheet" href="/assets/site.css?v=2">
|
|
<link rel="icon" type="image/png" href="/assets/logo_favicon_2.svg">
|
|
<script defer src="https://stats.felhom.eu/script.js" data-website-id="d419db57-5e1c-48df-bdb3-c29f25fb1661"></script>
|
|
</head>
|
|
<body class="page-kapcsolat">
|
|
<nav>
|
|
<div class="container">
|
|
<a href="/" class="logo">
|
|
<img src="/assets/logo.png" alt="Felhom.eu logo">
|
|
<span class="logo-text">felhom.eu</span>
|
|
</a>
|
|
<ul class="nav-links">
|
|
<li><a href="/#szolgaltatasok">Szolgáltatások</a></li>
|
|
<li><a href="/alkalmazasok">Alkalmazások</a></li>
|
|
<li><a href="/technologiak">Technológiák</a></li>
|
|
<li><a href="/biztonsagimentes">Mentések</a></li>
|
|
<li><a href="/gyik">GYIK</a></li>
|
|
<li><a href="/kapcsolat" class="active">Kapcsolat</a></li>
|
|
</ul>
|
|
<button class="hamburger" id="hamburger" aria-label="Menü megnyitása" aria-expanded="false">
|
|
<span class="hamburger-box">
|
|
<span class="hamburger-line"></span>
|
|
<span class="hamburger-line"></span>
|
|
<span class="hamburger-line"></span>
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
<div class="mobile-overlay" id="mobileOverlay"></div>
|
|
|
|
<section class="page-header">
|
|
<div class="container">
|
|
<h1>Írj nekünk <span>bátran!</span></h1>
|
|
<p>Kérdésed van, vagy szeretnéd megbeszélni az igényeidet? Töltsd ki az űrlapot, és hamarosan válaszolunk.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<main>
|
|
<section class="content-section" style="padding-top: 0;">
|
|
<div class="container">
|
|
<div class="contact-layout">
|
|
|
|
<!-- Form -->
|
|
<div class="contact-form-card">
|
|
<div id="formStatus" class="form-status"></div>
|
|
|
|
<form id="contactForm" novalidate>
|
|
<div style="position:absolute;left:-9999px;" aria-hidden="true">
|
|
<input type="text" name="website" tabindex="-1" autocomplete="off">
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="name">Név <span class="required">*</span></label>
|
|
<input type="text" id="name" name="name" placeholder="Teljes neved" required>
|
|
<div class="error-message" id="nameError">Kérlek, add meg a neved.</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="email">Email <span class="required">*</span></label>
|
|
<input type="email" id="email" name="email" placeholder="pelda@email.hu" required>
|
|
<div class="error-message" id="emailError">Kérlek, adj meg egy érvényes email címet.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="subject">Tárgy <span class="required">*</span></label>
|
|
<select id="subject" name="subject" required>
|
|
<option value="" disabled selected>Válassz témát...</option>
|
|
<option value="zart-teszt">Zárt teszt — jelentkezem tesztelőnek</option>
|
|
<option value="erdeklodes">Érdeklődés — szeretném megismerni a szolgáltatást</option>
|
|
<option value="arajanlat">Árajánlat kérés — konkrét igényeim vannak</option>
|
|
<option value="tamogatas">Támogatás — meglévő szerveremet érintő kérdés</option>
|
|
<option value="egyeb">Egyéb</option>
|
|
</select>
|
|
<div class="error-message" id="subjectError">Kérlek, válassz egy témát.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="message">Üzenet <span class="required">*</span></label>
|
|
<textarea id="message" name="message" placeholder="Írd le, miben segíthetünk..." required></textarea>
|
|
<div class="error-message" id="messageError">Kérlek, írd le az üzeneted.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Fájl csatolás <span style="color: var(--text-3); font-weight: 400;">(opcionális)</span></label>
|
|
<div class="file-upload-zone" id="dropZone">
|
|
<input type="file" id="fileInput" multiple accept=".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.webp,.txt,.csv,.zip,.7z">
|
|
<div class="upload-icon"><svg class="ico-tile" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-paperclip"/></svg></div>
|
|
<div class="upload-text">
|
|
<strong>Kattints ide</strong> vagy húzd ide a fájlokat
|
|
</div>
|
|
<div class="upload-hint">PDF, képek, dokumentumok · Max. 20 MB összesen</div>
|
|
</div>
|
|
<div class="file-list" id="fileList"></div>
|
|
<div class="file-total-size" id="fileTotalSize"></div>
|
|
</div>
|
|
|
|
<div class="checkbox-group">
|
|
<input type="checkbox" id="privacy" name="privacy" required>
|
|
<label for="privacy">
|
|
Elfogadom, hogy az űrlapon megadott adataimat a Felhom.eu a megkeresésem megválaszolásához felhasználja. Az adatokat harmadik félnek nem adjuk ki.
|
|
</label>
|
|
</div>
|
|
<div class="error-message" id="privacyError" style="margin-top: -16px; margin-bottom: 16px;">Az adatkezelési hozzájárulás szükséges.</div>
|
|
|
|
<button type="submit" class="submit-button" id="submitBtn">
|
|
<span class="btn-text">Üzenet küldése →</span>
|
|
<span class="spinner"></span>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="contact-sidebar">
|
|
<div class="sidebar-card">
|
|
<h3><span class="icon"><svg class="ico-lg" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-mail"/></svg></span> Közvetlen email</h3>
|
|
<p>Ha inkább emailben írnál:</p>
|
|
<a href="mailto:info@felhom.eu" class="direct-email">
|
|
<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-mail"/></svg> info@felhom.eu
|
|
</a>
|
|
</div>
|
|
|
|
<div class="sidebar-card">
|
|
<h3><span class="icon"><svg class="ico-lg" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-clock"/></svg></span> Válaszidő</h3>
|
|
<p>Általában <strong style="color: var(--blue-bright);">24 órán belül</strong> válaszolunk munkanapokon.</p>
|
|
<p>Sürgős támogatási kérdés esetén jelezd a tárgyban.</p>
|
|
</div>
|
|
|
|
<div class="sidebar-card">
|
|
<h3><span class="icon"><svg class="ico-lg" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-lightbulb"/></svg></span> Miben segíthetünk?</h3>
|
|
<ul class="sidebar-list">
|
|
<li><span class="li-icon"><svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-monitor"/></svg></span> Szerver konfiguráció tanácsadás</li>
|
|
<li><span class="li-icon"><svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-package"/></svg></span> Alkalmazás telepítés és beállítás</li>
|
|
<li><span class="li-icon"><svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-lock"/></svg></span> Biztonsági mentés kialakítás</li>
|
|
<li><span class="li-icon"><svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-globe"/></svg></span> Távoli elérés beállítása</li>
|
|
<li><span class="li-icon"><svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-wrench"/></svg></span> Meglévő szerver karbantartás</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<footer>
|
|
<div class="container">
|
|
<p>© 2026 felhom.eu — Saját felhőd, saját szabályaid</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
(() => {
|
|
'use strict';
|
|
|
|
// ==============================================
|
|
// CONFIGURATION
|
|
// ==============================================
|
|
const CONFIG = {
|
|
// TODO: Replace with your actual form backend endpoint.
|
|
// Options:
|
|
// 1. Self-hosted: Deploy a small container (e.g. Go/Python) that receives POST and sends via SMTP
|
|
// 2. Formspree: 'https://formspree.io/f/YOUR_FORM_ID'
|
|
// 3. Cloudflare Workers: Deploy a worker that forwards to email
|
|
//
|
|
// For now, falls back to mailto: if no endpoint is configured.
|
|
formEndpoint: '/api/contact',
|
|
|
|
maxTotalFileSize: 20 * 1024 * 1024, // 20 MB
|
|
maxSingleFileSize: 10 * 1024 * 1024, // 10 MB per file
|
|
maxFiles: 5,
|
|
allowedExtensions: ['pdf','doc','docx','xls','xlsx','png','jpg','jpeg','gif','webp','txt','csv','zip','7z'],
|
|
};
|
|
|
|
// ==============================================
|
|
// DOM REFS
|
|
// ==============================================
|
|
const form = document.getElementById('contactForm');
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
const formStatus = document.getElementById('formStatus');
|
|
const dropZone = document.getElementById('dropZone');
|
|
const fileInput = document.getElementById('fileInput');
|
|
const fileListEl = document.getElementById('fileList');
|
|
const fileTotalSizeEl = document.getElementById('fileTotalSize');
|
|
|
|
let attachedFiles = [];
|
|
|
|
// Preselect the subject from ?tema= (the „Zárt teszt" CTA on the landing page
|
|
// links here as /kapcsolat?tema=zart-teszt). Unknown values are ignored.
|
|
(function preselectSubject() {
|
|
const wanted = new URLSearchParams(window.location.search).get('tema');
|
|
if (!wanted) return;
|
|
const select = document.getElementById('subject');
|
|
if (!select) return;
|
|
const match = Array.from(select.options).some(o => o.value === wanted);
|
|
if (match) {
|
|
select.value = wanted;
|
|
} else {
|
|
console.warn('[kapcsolat] unknown ?tema= value, ignoring:', wanted);
|
|
}
|
|
})();
|
|
|
|
// ==============================================
|
|
// VALIDATION
|
|
// ==============================================
|
|
function validateField(field) {
|
|
const errorEl = document.getElementById(field.id + 'Error');
|
|
let valid = true;
|
|
|
|
if (field.type === 'checkbox') {
|
|
valid = field.checked;
|
|
} else if (field.required && !field.value.trim()) {
|
|
valid = false;
|
|
} else if (field.type === 'email' && field.value.trim()) {
|
|
valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(field.value.trim());
|
|
}
|
|
|
|
if (valid) {
|
|
field.classList.remove('error');
|
|
if (errorEl) errorEl.classList.remove('visible');
|
|
} else {
|
|
field.classList.add('error');
|
|
if (errorEl) errorEl.classList.add('visible');
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
function validateForm() {
|
|
const fields = ['name', 'email', 'subject', 'message', 'privacy'];
|
|
let allValid = true;
|
|
|
|
fields.forEach(id => {
|
|
const field = document.getElementById(id);
|
|
if (!validateField(field)) allValid = false;
|
|
});
|
|
|
|
return allValid;
|
|
}
|
|
|
|
// Live validation on blur
|
|
['name', 'email', 'subject', 'message', 'privacy'].forEach(id => {
|
|
const el = document.getElementById(id);
|
|
const event = el.type === 'checkbox' ? 'change' : 'blur';
|
|
el.addEventListener(event, () => validateField(el));
|
|
// Clear error on input
|
|
el.addEventListener('input', () => {
|
|
if (el.classList.contains('error')) validateField(el);
|
|
});
|
|
});
|
|
|
|
// ==============================================
|
|
// FILE HANDLING
|
|
// ==============================================
|
|
function formatFileSize(bytes) {
|
|
if (bytes < 1024) return bytes + ' B';
|
|
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
}
|
|
|
|
function getFileIcon(name) {
|
|
const ext = name.split('.').pop().toLowerCase();
|
|
const icons = {
|
|
pdf: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-file-text"/></svg>', doc: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-file-text"/></svg>', docx: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-file-text"/></svg>', xls: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-chart-column"/></svg>', xlsx: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-chart-column"/></svg>',
|
|
png: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-image"/></svg>', jpg: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-image"/></svg>', jpeg: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-image"/></svg>', gif: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-image"/></svg>', webp: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-image"/></svg>',
|
|
txt: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-file-text"/></svg>', csv: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-chart-column"/></svg>', zip: '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-package"/></svg>', '7z': '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-package"/></svg>',
|
|
};
|
|
return icons[ext] || '<svg class="ico" aria-hidden="true"><use href="/assets/icons.svg?v=1#i-paperclip"/></svg>';
|
|
}
|
|
|
|
function getTotalFileSize() {
|
|
return attachedFiles.reduce((sum, f) => sum + f.size, 0);
|
|
}
|
|
|
|
function addFiles(fileArray) {
|
|
for (const file of fileArray) {
|
|
// Check extension
|
|
const ext = file.name.split('.').pop().toLowerCase();
|
|
if (!CONFIG.allowedExtensions.includes(ext)) {
|
|
showStatus(`A "${file.name}" fájltípus nem engedélyezett.`, 'error-state');
|
|
continue;
|
|
}
|
|
|
|
// Check single file size
|
|
if (file.size > CONFIG.maxSingleFileSize) {
|
|
showStatus(`A "${file.name}" túl nagy (max. ${formatFileSize(CONFIG.maxSingleFileSize)} / fájl).`, 'error-state');
|
|
continue;
|
|
}
|
|
|
|
// Check max file count
|
|
if (attachedFiles.length >= CONFIG.maxFiles) {
|
|
showStatus(`Maximum ${CONFIG.maxFiles} fájl csatolható.`, 'error-state');
|
|
break;
|
|
}
|
|
|
|
// Check total size
|
|
if (getTotalFileSize() + file.size > CONFIG.maxTotalFileSize) {
|
|
showStatus(`Összesített fájlméret meghaladja a ${formatFileSize(CONFIG.maxTotalFileSize)} limitet.`, 'error-state');
|
|
break;
|
|
}
|
|
|
|
// Check duplicate
|
|
if (attachedFiles.some(f => f.name === file.name && f.size === file.size)) {
|
|
continue;
|
|
}
|
|
|
|
attachedFiles.push(file);
|
|
}
|
|
|
|
renderFileList();
|
|
}
|
|
|
|
function removeFile(index) {
|
|
attachedFiles.splice(index, 1);
|
|
renderFileList();
|
|
// Reset file input so same file can be re-added
|
|
fileInput.value = '';
|
|
}
|
|
|
|
function renderFileList() {
|
|
if (attachedFiles.length === 0) {
|
|
fileListEl.innerHTML = '';
|
|
fileTotalSizeEl.textContent = '';
|
|
return;
|
|
}
|
|
|
|
fileListEl.innerHTML = attachedFiles.map((file, i) => `
|
|
<div class="file-item">
|
|
<span class="file-icon">${getFileIcon(file.name)}</span>
|
|
<div class="file-info">
|
|
<div class="file-name" title="${file.name}">${file.name}</div>
|
|
<div class="file-size">${formatFileSize(file.size)}</div>
|
|
</div>
|
|
<button type="button" class="file-remove" data-index="${i}" title="Eltávolítás">×</button>
|
|
</div>
|
|
`).join('');
|
|
|
|
// Bind remove buttons
|
|
fileListEl.querySelectorAll('.file-remove').forEach(btn => {
|
|
btn.addEventListener('click', () => removeFile(parseInt(btn.dataset.index)));
|
|
});
|
|
|
|
// Total size indicator
|
|
const total = getTotalFileSize();
|
|
const pct = (total / CONFIG.maxTotalFileSize) * 100;
|
|
fileTotalSizeEl.textContent = `${formatFileSize(total)} / ${formatFileSize(CONFIG.maxTotalFileSize)}`;
|
|
fileTotalSizeEl.className = 'file-total-size';
|
|
if (pct > 90) fileTotalSizeEl.classList.add('error-text');
|
|
else if (pct > 70) fileTotalSizeEl.classList.add('warning');
|
|
}
|
|
|
|
// File input change
|
|
fileInput.addEventListener('change', () => {
|
|
if (fileInput.files.length) {
|
|
addFiles(Array.from(fileInput.files));
|
|
fileInput.value = '';
|
|
}
|
|
});
|
|
|
|
// Drag & drop
|
|
['dragenter', 'dragover'].forEach(evt => {
|
|
dropZone.addEventListener(evt, e => {
|
|
e.preventDefault();
|
|
dropZone.classList.add('dragover');
|
|
});
|
|
});
|
|
|
|
['dragleave', 'drop'].forEach(evt => {
|
|
dropZone.addEventListener(evt, e => {
|
|
e.preventDefault();
|
|
dropZone.classList.remove('dragover');
|
|
});
|
|
});
|
|
|
|
dropZone.addEventListener('drop', e => {
|
|
if (e.dataTransfer.files.length) {
|
|
addFiles(Array.from(e.dataTransfer.files));
|
|
}
|
|
});
|
|
|
|
// ==============================================
|
|
// STATUS MESSAGES
|
|
// ==============================================
|
|
function showStatus(message, type) {
|
|
formStatus.textContent = message;
|
|
formStatus.className = 'form-status ' + type;
|
|
formStatus.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
|
|
if (type === 'error-state') {
|
|
setTimeout(() => {
|
|
formStatus.className = 'form-status';
|
|
}, 6000);
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// FORM SUBMISSION
|
|
// ==============================================
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
formStatus.className = 'form-status';
|
|
|
|
if (!validateForm()) {
|
|
// Build specific error message
|
|
const missing = [];
|
|
if (!document.getElementById('name').value.trim()) missing.push('név');
|
|
const emailVal = document.getElementById('email').value.trim();
|
|
if (!emailVal || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailVal)) missing.push('email');
|
|
if (!document.getElementById('subject').value) missing.push('tárgy');
|
|
if (!document.getElementById('message').value.trim()) missing.push('üzenet');
|
|
if (!document.getElementById('privacy').checked) missing.push('adatkezelési hozzájárulás');
|
|
|
|
if (missing.length === 1 && missing[0] === 'adatkezelési hozzájárulás') {
|
|
showStatus('Kérlek, fogadd el az adatkezelési hozzájárulást a küldéshez.', 'error-state');
|
|
} else {
|
|
showStatus('Kérlek, töltsd ki az összes kötelező mezőt.', 'error-state');
|
|
}
|
|
return;
|
|
}
|
|
|
|
submitBtn.classList.add('loading');
|
|
submitBtn.disabled = true;
|
|
|
|
const formData = {
|
|
name: document.getElementById('name').value.trim(),
|
|
email: document.getElementById('email').value.trim(),
|
|
subject: document.getElementById('subject').value,
|
|
message: document.getElementById('message').value.trim(),
|
|
};
|
|
|
|
// Subject label mapping
|
|
const subjectLabels = {
|
|
'zart-teszt': 'Jelentkezés — zárt teszt',
|
|
erdeklodes: 'Érdeklődés',
|
|
arajanlat: 'Árajánlat kérés',
|
|
tamogatas: 'Támogatás',
|
|
egyeb: 'Egyéb',
|
|
};
|
|
|
|
try {
|
|
if (CONFIG.formEndpoint) {
|
|
// --- Backend submission ---
|
|
const data = new FormData();
|
|
data.append('name', formData.name);
|
|
data.append('email', formData.email);
|
|
data.append('subject', subjectLabels[formData.subject] || formData.subject);
|
|
data.append('message', formData.message);
|
|
|
|
attachedFiles.forEach(file => {
|
|
data.append('attachments', file);
|
|
});
|
|
|
|
const response = await fetch(CONFIG.formEndpoint, {
|
|
method: 'POST',
|
|
body: data,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Szerver hiba: ${response.status}`);
|
|
}
|
|
|
|
showStatus('Üzeneted sikeresen elküldtük! Hamarosan válaszolunk.', 'success');
|
|
form.reset();
|
|
attachedFiles = [];
|
|
renderFileList();
|
|
|
|
} else {
|
|
// --- Fallback: mailto ---
|
|
const subjectLine = `[Felhom.eu] ${subjectLabels[formData.subject] || formData.subject}`;
|
|
const body = [
|
|
`Név: ${formData.name}`,
|
|
`Email: ${formData.email}`,
|
|
``,
|
|
formData.message,
|
|
].join('\n');
|
|
|
|
const mailtoUrl = `mailto:info@felhom.eu?subject=${encodeURIComponent(subjectLine)}&body=${encodeURIComponent(body)}`;
|
|
window.location.href = mailtoUrl;
|
|
|
|
if (attachedFiles.length > 0) {
|
|
showStatus('Az email kliens megnyílt. A csatolt fájlokat kézzel kell hozzáadnod az emailhez, mert a mailto: link nem támogatja a mellékleteket.', 'error-state');
|
|
} else {
|
|
showStatus('Az email kliens megnyílt az üzeneteddel. Küld el az emailt a kapcsolatfelvételhez!', 'success');
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('Form submission error:', err);
|
|
showStatus(`Hiba történt a küldés során. Kérlek, próbáld újra vagy írj közvetlenül az info@felhom.eu címre.`, 'error-state');
|
|
} finally {
|
|
submitBtn.classList.remove('loading');
|
|
submitBtn.disabled = false;
|
|
}
|
|
});
|
|
|
|
// ==============================================
|
|
// DEBUG HELPER
|
|
// ==============================================
|
|
// Uncomment to test form states:
|
|
// window.debugForm = {
|
|
// showSuccess: () => showStatus('Üzeneted sikeresen elküldtük!', 'success'),
|
|
// showError: () => showStatus('Hiba történt.', 'error-state'),
|
|
// getFiles: () => console.log(attachedFiles),
|
|
// getFormData: () => {
|
|
// const fd = new FormData(form);
|
|
// for (const [k,v] of fd.entries()) console.log(k, v);
|
|
// },
|
|
// };
|
|
|
|
})();
|
|
</script>
|
|
<script>
|
|
(function() {
|
|
var hamburger = document.getElementById('hamburger');
|
|
var navLinks = document.querySelector('.nav-links');
|
|
var overlay = document.getElementById('mobileOverlay');
|
|
var body = document.body;
|
|
|
|
if (!hamburger || !navLinks || !overlay) {
|
|
console.warn('[mobile-menu] Missing elements:', {
|
|
hamburger: !!hamburger,
|
|
navLinks: !!navLinks,
|
|
overlay: !!overlay
|
|
});
|
|
return;
|
|
}
|
|
|
|
function openMenu() {
|
|
hamburger.classList.add('is-active');
|
|
navLinks.classList.add('is-open');
|
|
overlay.classList.add('is-visible');
|
|
body.classList.add('menu-open');
|
|
hamburger.setAttribute('aria-expanded', 'true');
|
|
hamburger.setAttribute('aria-label', 'Menü bezárása');
|
|
}
|
|
|
|
function closeMenu() {
|
|
hamburger.classList.remove('is-active');
|
|
navLinks.classList.remove('is-open');
|
|
overlay.classList.remove('is-visible');
|
|
body.classList.remove('menu-open');
|
|
hamburger.setAttribute('aria-expanded', 'false');
|
|
hamburger.setAttribute('aria-label', 'Menü megnyitása');
|
|
}
|
|
|
|
hamburger.addEventListener('click', function() {
|
|
if (navLinks.classList.contains('is-open')) {
|
|
closeMenu();
|
|
} else {
|
|
openMenu();
|
|
}
|
|
});
|
|
|
|
overlay.addEventListener('click', closeMenu);
|
|
|
|
navLinks.querySelectorAll('a').forEach(function(link) {
|
|
link.addEventListener('click', closeMenu);
|
|
});
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape' && navLinks.classList.contains('is-open')) {
|
|
closeMenu();
|
|
}
|
|
});
|
|
|
|
window.addEventListener('resize', function() {
|
|
if (window.innerWidth > 900 && navLinks.classList.contains('is-open')) {
|
|
closeMenu();
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|