Initial commit: ToolCTRL Landing Page
Statische Landing Page mit Lead-Formular, Impressum und Datenschutzerklärung, ausgeliefert von einem abhängigkeitsfreien Node-Server mit lokaler Lead-Erfassung. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
143748dc0d
33 files changed
+2180
No files matched your search
@@ -0,0 +1,127 @@
|
||||
/* ToolCTRL — Landing Page Interaktion */
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
/* ---- Jahr im Footer ---- */
|
||||
var yearEl = document.getElementById("year");
|
||||
if (yearEl) yearEl.textContent = String(new Date().getFullYear());
|
||||
|
||||
/* ---- Mobile-Navigation ---- */
|
||||
var toggle = document.querySelector(".nav-toggle");
|
||||
var mobileNav = document.querySelector(".mobile-nav");
|
||||
if (toggle && mobileNav) {
|
||||
toggle.addEventListener("click", function () {
|
||||
var open = mobileNav.hasAttribute("hidden");
|
||||
if (open) {
|
||||
mobileNav.removeAttribute("hidden");
|
||||
toggle.setAttribute("aria-expanded", "true");
|
||||
} else {
|
||||
mobileNav.setAttribute("hidden", "");
|
||||
toggle.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
});
|
||||
mobileNav.querySelectorAll("a").forEach(function (a) {
|
||||
a.addEventListener("click", function () {
|
||||
mobileNav.setAttribute("hidden", "");
|
||||
toggle.setAttribute("aria-expanded", "false");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ---- Lead-Formular ---- */
|
||||
var form = document.getElementById("lead-form");
|
||||
var status = document.getElementById("form-status");
|
||||
if (!form) return;
|
||||
|
||||
function setStatus(msg, kind) {
|
||||
if (!status) return;
|
||||
status.textContent = msg;
|
||||
status.className = "form-status " + (kind || "");
|
||||
status.hidden = false;
|
||||
}
|
||||
|
||||
function fieldRow(input) {
|
||||
return input.closest(".form-row");
|
||||
}
|
||||
|
||||
function validate() {
|
||||
var ok = true;
|
||||
["f-name", "f-email", "f-nachricht"].forEach(function (id) {
|
||||
var el = document.getElementById(id);
|
||||
var row = fieldRow(el);
|
||||
var valid = el.value.trim() !== "";
|
||||
if (id === "f-email" && valid) {
|
||||
valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(el.value.trim());
|
||||
}
|
||||
if (row) row.classList.toggle("invalid", !valid);
|
||||
if (!valid) ok = false;
|
||||
});
|
||||
return ok;
|
||||
}
|
||||
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validate()) {
|
||||
setStatus("Bitte füllen Sie die markierten Pflichtfelder aus.", "err");
|
||||
return;
|
||||
}
|
||||
|
||||
var btn = form.querySelector("button[type=submit]");
|
||||
var payload = {
|
||||
name: form.name.value.trim(),
|
||||
firma: form.firma.value.trim(),
|
||||
email: form.email.value.trim(),
|
||||
telefon: form.telefon.value.trim(),
|
||||
nachricht: form.nachricht.value.trim(),
|
||||
website: form.website.value.trim(), // Honeypot
|
||||
quelle: "Messe — Landing Page"
|
||||
};
|
||||
|
||||
if (btn) { btn.disabled = true; btn.textContent = "Wird gesendet …"; }
|
||||
setStatus("Anfrage wird übermittelt …", "");
|
||||
|
||||
fetch("/api/lead", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(function (res) {
|
||||
return res.json().then(function (data) {
|
||||
return { ok: res.ok, data: data };
|
||||
});
|
||||
})
|
||||
.then(function (r) {
|
||||
if (r.ok) {
|
||||
form.reset();
|
||||
setStatus(
|
||||
"Vielen Dank — Ihre Anfrage ist bei uns eingegangen. Wir melden uns zeitnah.",
|
||||
"ok"
|
||||
);
|
||||
} else {
|
||||
setStatus(
|
||||
(r.data && r.data.error) ||
|
||||
"Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
|
||||
"err"
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
setStatus(
|
||||
"Verbindung fehlgeschlagen. Bitte schreiben Sie uns direkt an admin@tool-ctrl.de.",
|
||||
"err"
|
||||
);
|
||||
})
|
||||
.finally(function () {
|
||||
if (btn) { btn.disabled = false; btn.textContent = "Anfrage senden"; }
|
||||
});
|
||||
});
|
||||
|
||||
/* Markierung beim Tippen entfernen */
|
||||
form.querySelectorAll("input, textarea").forEach(function (el) {
|
||||
el.addEventListener("input", function () {
|
||||
var row = fieldRow(el);
|
||||
if (row) row.classList.remove("invalid");
|
||||
});
|
||||
});
|
||||
})();
|
||||
Reference in new issue
Block a user