feat: Neue Produktseite AegisSight Monitor unter /vorschau/
Produktfokussierte Landing Page mit: - Hero: Klare Produktbotschaft und CTAs - Problem/Solution: Warum OSINT-Automation nötig ist - Features: 6 Kernfähigkeiten des Monitors - Live-Demos: 3 Lagen-Cards (Iran live + 2 Platzhalter) - Trust-Signale: Made in Germany, DSGVO, Hosting DE - Light-Mode Design mit Navy/Gold Akzenten - Live-Daten-Fetch aus /lagen/iran-konflikt/data/current.json - Responsive (Desktop/Tablet/Mobile) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
107
vorschau/js/app.js
Normale Datei
107
vorschau/js/app.js
Normale Datei
@@ -0,0 +1,107 @@
|
||||
/* AegisSight Monitor - Product Page JS */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* ==================== NAVBAR SHADOW ==================== */
|
||||
var navbar = document.getElementById('navbar');
|
||||
window.addEventListener('scroll', function () {
|
||||
if (window.scrollY > 10) {
|
||||
navbar.classList.add('scrolled');
|
||||
} else {
|
||||
navbar.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
|
||||
/* ==================== MOBILE MENU ==================== */
|
||||
var toggle = document.querySelector('.mobile-menu-toggle');
|
||||
var menu = document.getElementById('mobile-menu');
|
||||
var overlay = document.getElementById('mobile-overlay');
|
||||
|
||||
function openMenu() {
|
||||
toggle.classList.add('active');
|
||||
menu.classList.add('open');
|
||||
overlay.classList.add('open');
|
||||
toggle.setAttribute('aria-expanded', 'true');
|
||||
menu.setAttribute('aria-hidden', 'false');
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
toggle.classList.remove('active');
|
||||
menu.classList.remove('open');
|
||||
overlay.classList.remove('open');
|
||||
toggle.setAttribute('aria-expanded', 'false');
|
||||
menu.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', function () {
|
||||
if (menu.classList.contains('open')) {
|
||||
closeMenu();
|
||||
} else {
|
||||
openMenu();
|
||||
}
|
||||
});
|
||||
|
||||
overlay.addEventListener('click', closeMenu);
|
||||
|
||||
// Close on link click
|
||||
menu.querySelectorAll('a').forEach(function (link) {
|
||||
link.addEventListener('click', closeMenu);
|
||||
});
|
||||
|
||||
/* ==================== SMOOTH SCROLL ==================== */
|
||||
document.querySelectorAll('a[href^="#"]').forEach(function (link) {
|
||||
link.addEventListener('click', function (e) {
|
||||
var target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
e.preventDefault();
|
||||
target.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* ==================== LIVE DATA FETCH ==================== */
|
||||
function timeAgo(dateStr) {
|
||||
var now = new Date();
|
||||
var then = new Date(dateStr);
|
||||
var diffMs = now - then;
|
||||
var diffMin = Math.floor(diffMs / 60000);
|
||||
|
||||
if (diffMin < 1) return 'Gerade eben aktualisiert';
|
||||
if (diffMin < 60) return 'Aktualisiert vor ' + diffMin + ' Min.';
|
||||
var diffH = Math.floor(diffMin / 60);
|
||||
if (diffH < 24) return 'Aktualisiert vor ' + diffH + ' Std.';
|
||||
var diffD = Math.floor(diffH / 24);
|
||||
return 'Aktualisiert vor ' + diffD + (diffD === 1 ? ' Tag' : ' Tagen');
|
||||
}
|
||||
|
||||
function loadLiveData() {
|
||||
fetch('/lagen/iran-konflikt/data/current.json?t=' + Date.now())
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||||
return res.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
var incident = data.incident || {};
|
||||
var lagebild = data.current_lagebild || {};
|
||||
|
||||
var elArticles = document.getElementById('stat-articles');
|
||||
var elSources = document.getElementById('stat-sources');
|
||||
var elFactchecks = document.getElementById('stat-factchecks');
|
||||
var elUpdated = document.getElementById('demo-updated');
|
||||
|
||||
if (elArticles) elArticles.textContent = incident.article_count || '—';
|
||||
if (elSources) elSources.textContent = incident.source_count || '—';
|
||||
if (elFactchecks) elFactchecks.textContent = incident.factcheck_count || '—';
|
||||
if (elUpdated && lagebild.updated_at) {
|
||||
elUpdated.textContent = timeAgo(lagebild.updated_at);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
var elUpdated = document.getElementById('demo-updated');
|
||||
if (elUpdated) elUpdated.textContent = 'Daten derzeit nicht verfügbar';
|
||||
});
|
||||
}
|
||||
|
||||
loadLiveData();
|
||||
})();
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren