Update site visuals and assets
This commit is contained in:
1 parent
41a5958184
commit
39faad9624
27 files changed
+2087
-610
No files matched your search
+253
-2
@@ -36,6 +36,50 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* ---- Console-Easter-Eggs fuer neugierige Inspektoren ---- */
|
||||
var inspectAscii = [
|
||||
" _______ _______ _______ ___ _______ _______ _______ ",
|
||||
"| || || || | | || || |",
|
||||
"|_ _|| _ || _ || | | ||_ _|| ___|",
|
||||
" | | | | | || | | || | | | | | | |___ ",
|
||||
" | | | |_| || |_| || |___ | _| | | | ___|",
|
||||
" | | | || || || |_ | | | |___ ",
|
||||
" |___| |_______||_______||_______||_______| |___| |_______|"
|
||||
].join("\n");
|
||||
var inspectHints = [
|
||||
"CTRL-KEY EVENT: Inspect gedrueckt. Bitte keine Produktivsysteme anfassen.",
|
||||
"Hidden combo: window.toolctrl.press()",
|
||||
"Status: schwarz/weiss. Farbe wurde zurueck in den Werkzeugkoffer gelegt."
|
||||
];
|
||||
var inspectLogged = false;
|
||||
|
||||
function logControlConsole(reason) {
|
||||
if (reason === "devtools" && inspectLogged) return;
|
||||
if (reason === "devtools") inspectLogged = true;
|
||||
console.log(
|
||||
"%c" + inspectAscii,
|
||||
"font-family: monospace; font-weight: 900; color: #000; background: #fff; padding: 10px; border: 3px solid #000;"
|
||||
);
|
||||
console.log("%c" + inspectHints[Math.floor(Math.random() * inspectHints.length)],
|
||||
"font-family: monospace; color: #fff; background: #000; padding: 6px 8px;");
|
||||
}
|
||||
|
||||
window.toolctrl = window.toolctrl || {};
|
||||
window.toolctrl.press = function () {
|
||||
console.log("%c[ CTRL ] *klack* Ablauf uebernommen.", "font-family: monospace; font-weight: 900;");
|
||||
return "pressed";
|
||||
};
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
setTimeout(function () { logControlConsole("load"); }, 450);
|
||||
});
|
||||
setInterval(function () {
|
||||
var open = Math.abs(window.outerWidth - window.innerWidth) > 160 ||
|
||||
Math.abs(window.outerHeight - window.innerHeight) > 160;
|
||||
document.documentElement.toggleAttribute("data-inspecting", open);
|
||||
if (open) logControlConsole("devtools");
|
||||
}, 1200);
|
||||
|
||||
/* ---- Dezente Scroll-Reveals ---- */
|
||||
var reduceMotion = window.matchMedia &&
|
||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
@@ -43,16 +87,20 @@
|
||||
".hero-copy > *",
|
||||
".hero-visual",
|
||||
".trust-strip span",
|
||||
".mission-head",
|
||||
".mission-step",
|
||||
".stance-head > *",
|
||||
".stance-card",
|
||||
".product-copy > *",
|
||||
".product-ui",
|
||||
".velocity-copy > *",
|
||||
".velocity-item",
|
||||
".section-head",
|
||||
".card",
|
||||
".industry-card",
|
||||
".step",
|
||||
".arbeit-copy > *",
|
||||
".kanban-wrap",
|
||||
".event-poster",
|
||||
".mini-terminal",
|
||||
".event-card",
|
||||
".kontakt-copy > *",
|
||||
".contact-promises li",
|
||||
@@ -82,6 +130,209 @@
|
||||
revealEls.forEach(function (el) { observer.observe(el); });
|
||||
}
|
||||
|
||||
/* ---- Hero Workflow Nodes: ziehbare Kontrollpunkte ---- */
|
||||
var board = document.querySelector("[data-control-board]");
|
||||
if (board) {
|
||||
var lineSvg = board.querySelector(".control-lines");
|
||||
var logoNode = board.querySelector("[data-logo-node]");
|
||||
var nodes = Array.prototype.slice.call(board.querySelectorAll("[data-node]"));
|
||||
var draggableItems = nodes.concat(logoNode ? [logoNode] : []);
|
||||
var activeDrag = null;
|
||||
var lineFrame = 0;
|
||||
|
||||
if (logoNode) {
|
||||
logoNode.addEventListener("dragstart", function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
function boardRect() {
|
||||
return board.getBoundingClientRect();
|
||||
}
|
||||
|
||||
function centerOf(el, b) {
|
||||
var r = el.getBoundingClientRect();
|
||||
return {
|
||||
x: r.left - b.left + r.width / 2,
|
||||
y: r.top - b.top + r.height / 2
|
||||
};
|
||||
}
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
function updateLines() {
|
||||
if (!lineSvg || !logoNode) return;
|
||||
var b = boardRect();
|
||||
var target = centerOf(logoNode, b);
|
||||
lineSvg.setAttribute("viewBox", "0 0 " + b.width + " " + b.height);
|
||||
nodes.forEach(function (node) {
|
||||
var path = lineSvg.querySelector('[data-line="' + node.dataset.node + '"]');
|
||||
if (!path) return;
|
||||
var nodeCenter = centerOf(node, b);
|
||||
var isOutput = node.classList.contains("is-output");
|
||||
var start = isOutput ? target : nodeCenter;
|
||||
var end = isOutput ? nodeCenter : target;
|
||||
var bend = Math.max(44, Math.abs(end.x - start.x) * 0.38);
|
||||
var c1x = start.x + (end.x > start.x ? bend : -bend);
|
||||
var c2x = end.x + (end.x > start.x ? -bend : bend);
|
||||
var d = "M " + start.x + " " + start.y +
|
||||
" C " + c1x + " " + start.y +
|
||||
", " + c2x + " " + end.y +
|
||||
", " + end.x + " " + end.y;
|
||||
path.classList.toggle("is-output", isOutput);
|
||||
path.setAttribute("d", d);
|
||||
});
|
||||
lineFrame = 0;
|
||||
}
|
||||
|
||||
function requestLineUpdate() {
|
||||
if (lineFrame) return;
|
||||
lineFrame = window.requestAnimationFrame(updateLines);
|
||||
}
|
||||
|
||||
draggableItems.forEach(function (item) {
|
||||
item.addEventListener("pointerdown", function (e) {
|
||||
var r = item.getBoundingClientRect();
|
||||
if (item === logoNode) item.classList.add("is-positioned");
|
||||
activeDrag = {
|
||||
node: item,
|
||||
isLogo: item === logoNode,
|
||||
offsetX: e.clientX - r.left,
|
||||
offsetY: e.clientY - r.top
|
||||
};
|
||||
item.classList.add("is-dragging");
|
||||
item.setPointerCapture(e.pointerId);
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
item.addEventListener("pointermove", function (e) {
|
||||
if (!activeDrag || activeDrag.node !== item) return;
|
||||
var b = boardRect();
|
||||
var x = clamp(e.clientX - b.left - activeDrag.offsetX, 8, b.width - item.offsetWidth - 8);
|
||||
var y = clamp(e.clientY - b.top - activeDrag.offsetY, 8, b.height - item.offsetHeight - 8);
|
||||
item.style.left = x + "px";
|
||||
item.style.top = y + "px";
|
||||
if (activeDrag.isLogo) {
|
||||
item.classList.add("is-positioned");
|
||||
} else {
|
||||
item.style.removeProperty("--x");
|
||||
item.style.removeProperty("--y");
|
||||
}
|
||||
requestLineUpdate();
|
||||
});
|
||||
|
||||
item.addEventListener("pointerup", function (e) {
|
||||
if (!activeDrag || activeDrag.node !== item) return;
|
||||
item.classList.remove("is-dragging");
|
||||
item.releasePointerCapture(e.pointerId);
|
||||
activeDrag = null;
|
||||
requestLineUpdate();
|
||||
});
|
||||
|
||||
item.addEventListener("pointercancel", function () {
|
||||
item.classList.remove("is-dragging");
|
||||
activeDrag = null;
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("resize", requestLineUpdate, { passive: true });
|
||||
updateLines();
|
||||
setTimeout(requestLineUpdate, 150);
|
||||
}
|
||||
|
||||
/* ---- Produktwirkung: klickbare Workflow-Zustaende ---- */
|
||||
var productUi = document.querySelector(".product-ui");
|
||||
if (productUi) {
|
||||
var productStates = {
|
||||
eingang: {
|
||||
kicker: "Heute · 14 aktive Vorgänge",
|
||||
title: "Workflow Control",
|
||||
pill: "3 Blocker",
|
||||
flow: ["Anfrage", "Prüfung", "Angebot", "Termin", "Rechnung"],
|
||||
active: 1,
|
||||
done: 0,
|
||||
metrics: [["Antwortzeit", "18 min"], ["Auto-Schritte", "74%"], ["Offene Übergaben", "03"]],
|
||||
rows: [["Kunde wartet auf Rückmeldung", "Jetzt", "is-hot"], ["Dokumente aus Postfach übernommen", "Auto", ""], ["Team-Zuständigkeit gesetzt", "11:15", ""], ["Status an Leitung gemeldet", "Erledigt", "is-done"]]
|
||||
},
|
||||
angebote: {
|
||||
kicker: "Vertrieb · 8 Angebote offen",
|
||||
title: "Angebote steuern",
|
||||
pill: "2 fällig",
|
||||
flow: ["Lead", "Kalkulation", "Freigabe", "Versand", "Follow-up"],
|
||||
active: 2,
|
||||
done: 1,
|
||||
metrics: [["Durchlauf", "2,4 h"], ["Vorlagen", "91%"], ["Rückfragen", "05"]],
|
||||
rows: [["Angebot braucht interne Freigabe", "Heute", "is-hot"], ["PDF aus Kundendaten erstellt", "Auto", ""], ["Nachfass-Termin gesetzt", "Morgen", ""], ["Alte Version archiviert", "Erledigt", "is-done"]]
|
||||
},
|
||||
planung: {
|
||||
kicker: "Team · 21 Einsätze geplant",
|
||||
title: "Planung sichtbar",
|
||||
pill: "1 Konflikt",
|
||||
flow: ["Auftrag", "Ressource", "Slot", "Route", "Update"],
|
||||
active: 2,
|
||||
done: 1,
|
||||
metrics: [["Auslastung", "82%"], ["Auto-Routen", "68%"], ["Konflikte", "01"]],
|
||||
rows: [["Termin überschneidet sich", "Prüfen", "is-hot"], ["Route für Außendienst gebaut", "Auto", ""], ["Materialliste angehängt", "09:40", ""], ["Kunde informiert", "Erledigt", "is-done"]]
|
||||
},
|
||||
abschluss: {
|
||||
kicker: "Abschluss · 36 Vorgänge fertig",
|
||||
title: "Betrieb im Blick",
|
||||
pill: "0 kritisch",
|
||||
flow: ["Abnahme", "Doku", "Rechnung", "Feedback", "Archiv"],
|
||||
active: 3,
|
||||
done: 2,
|
||||
metrics: [["Abnahmen", "96%"], ["Auto-Doku", "88%"], ["Offen", "00"]],
|
||||
rows: [["Feedback für nächste Version notiert", "Neu", ""], ["Rechnung vorbereitet", "Auto", ""], ["Abnahme protokolliert", "13:20", "is-done"], ["Projekt sauber archiviert", "Erledigt", "is-done"]]
|
||||
}
|
||||
};
|
||||
var productTabs = Array.prototype.slice.call(productUi.querySelectorAll("[data-product-tab]"));
|
||||
var productKicker = productUi.querySelector("[data-product-kicker]");
|
||||
var productTitle = productUi.querySelector("[data-product-title]");
|
||||
var productPill = productUi.querySelector("[data-product-pill]");
|
||||
var productFlow = productUi.querySelector("[data-product-flow]");
|
||||
var productMetrics = productUi.querySelector("[data-product-metrics]");
|
||||
var productTable = productUi.querySelector("[data-product-table]");
|
||||
|
||||
function setProductState(key) {
|
||||
var state = productStates[key];
|
||||
if (!state) return;
|
||||
productUi.classList.add("is-switching");
|
||||
productTabs.forEach(function (tab) {
|
||||
tab.classList.toggle("active", tab.dataset.productTab === key);
|
||||
});
|
||||
window.setTimeout(function () {
|
||||
if (productKicker) productKicker.textContent = state.kicker;
|
||||
if (productTitle) productTitle.textContent = state.title;
|
||||
if (productPill) productPill.textContent = state.pill;
|
||||
if (productFlow) {
|
||||
productFlow.innerHTML = state.flow.map(function (label, index) {
|
||||
var cls = index === state.active ? "active" : (index <= state.done ? "done" : "");
|
||||
return '<span class="' + cls + '">' + label + '</span>';
|
||||
}).join("");
|
||||
}
|
||||
if (productMetrics) {
|
||||
productMetrics.innerHTML = state.metrics.map(function (metric) {
|
||||
return "<div><span>" + metric[0] + "</span><strong>" + metric[1] + "</strong></div>";
|
||||
}).join("");
|
||||
}
|
||||
if (productTable) {
|
||||
productTable.innerHTML = state.rows.map(function (row) {
|
||||
return '<div class="ui-row ' + row[2] + '"><span>' + row[0] + '</span><b>' + row[1] + '</b></div>';
|
||||
}).join("");
|
||||
}
|
||||
productUi.classList.remove("is-switching");
|
||||
}, 90);
|
||||
}
|
||||
|
||||
productTabs.forEach(function (tab) {
|
||||
tab.addEventListener("click", function () {
|
||||
setProductState(tab.dataset.productTab);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ---- Lead-Formular ---- */
|
||||
var form = document.getElementById("lead-form");
|
||||
var status = document.getElementById("form-status");
|
||||
|
||||
Reference in new issue
Block a user