SEO Quick-Wins: Schema.org, Meta-Hygiene, llms.txt, Performance, Aufraeumen

- Title Iran-Konflikt mit Bindestrich (Konsistenz mit OG/Schema)
- Meta-Hygiene auf 12 Seiten: robots index/follow + max-image-preview:large, theme-color #0A1832, author AegisSight UG
- sitemap.xml: lastmod-Tag pro URL (besseres Crawl-Signal)
- Hauptseite (DE+EN): Schema.org WebSite + SoftwareApplication ergaenzt (Sitelinks, Rich Result fuer Software-Produkt)
- Lagen-Seiten (6): Schema.org BreadcrumbList (Home -> Topic)
- llms.txt: Site-Struktur fuer KI-Crawler (mit Hinweis Live-Search-Bots erlaubt, Training-Bots geblockt)
- Performance: Hero-Slides 2-5 preload=metadata -> none (Slide 1 bleibt auto/LCP)
- Aufraeumen: 5 tote CSS-Files, 7 tote JS-Files, robots-launch.txt + sitemap-launch.xml entfernt
Dieser Commit ist enthalten in:
claude-dev
2026-05-10 15:17:47 +02:00
Ursprung 025ddfcebd
Commit d00bb4ba1d
29 geänderte Dateien mit 356 neuen und 4106 gelöschten Zeilen

Datei anzeigen

@@ -1,233 +0,0 @@
/**
* Enhanced Animations and Interactions
* Premium effects for modern web experience
*/
const EnhancedAnimations = {
init() {
this.initScrollAnimations();
this.initParallaxEffects();
this.initMagneticButtons();
this.initTextAnimations();
this.initCardTilt();
this.initSmoothScroll();
this.initCursorEffects();
this.initRevealOnScroll();
this.initNavbarEffects();
},
// Smooth scroll with easing
initSmoothScroll() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
const offset = 100;
const targetPosition = target.offsetTop - offset;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
},
// Parallax scrolling effects
initParallaxEffects() {
const parallaxElements = document.querySelectorAll('.parallax');
let ticking = false;
function updateParallax() {
const scrolled = window.pageYOffset;
parallaxElements.forEach(element => {
const speed = element.dataset.speed || 0.5;
const yPos = -(scrolled * speed);
element.style.transform = `translateY(${yPos}px)`;
});
ticking = false;
}
function requestTick() {
if (!ticking) {
window.requestAnimationFrame(updateParallax);
ticking = true;
}
}
window.addEventListener('scroll', requestTick);
},
// Magnetic button effects
initMagneticButtons() {
const magneticButtons = document.querySelectorAll('.primary-button, .secondary-button, .cta-button');
magneticButtons.forEach(button => {
button.addEventListener('mousemove', (e) => {
const rect = button.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
button.style.transform = `translate(${x * 0.2}px, ${y * 0.2}px) scale(1.05)`;
});
button.addEventListener('mouseleave', () => {
button.style.transform = '';
});
});
},
// Advanced text animations
initTextAnimations() {
// Typewriter effect for hero title - DISABLED to prevent duplication
// The title already has CSS animations applied
/* Commented out to fix duplication issue
const heroTitle = document.querySelector('.main-title');
if (heroTitle && !heroTitle.dataset.animated) {
heroTitle.dataset.animated = 'true';
const text = heroTitle.textContent;
heroTitle.textContent = '';
heroTitle.style.opacity = '1';
let index = 0;
const typeWriter = () => {
if (index < text.length) {
heroTitle.textContent += text.charAt(index);
index++;
setTimeout(typeWriter, 50);
}
};
// Start typewriter after a short delay
setTimeout(typeWriter, 500);
}
*/
// Word-by-word reveal for hero text
const heroText = document.querySelector('.hero-text');
if (heroText) {
const words = heroText.textContent.split(' ');
heroText.innerHTML = words.map(word =>
`<span class="word-reveal" style="opacity: 0; display: inline-block; transform: translateY(20px); transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);">${word}</span>`
).join(' ');
const wordSpans = heroText.querySelectorAll('.word-reveal');
wordSpans.forEach((word, index) => {
setTimeout(() => {
word.style.opacity = '1';
word.style.transform = 'translateY(0)';
}, 1000 + index * 100);
});
}
},
// Card tilt removed - zu verspielt für Behördenkontext
initCardTilt() {
// Deaktiviert - CSS hover-Effekte reichen aus
},
// Custom cursor effects - DISABLED
initCursorEffects() {
// Cursor removed as requested
return;
},
// Reveal elements on scroll
initRevealOnScroll() {
const revealElements = document.querySelectorAll('.about-panel, .tool-card, .value-card, .why-card, .competency-item');
revealElements.forEach((element, index) => {
element.style.opacity = '0';
element.style.transform = 'translateY(50px)';
element.style.transition = 'all 0.8s cubic-bezier(0.4, 0, 0.2, 1)';
});
const revealOnScroll = () => {
const windowHeight = window.innerHeight;
revealElements.forEach((element, index) => {
const elementTop = element.getBoundingClientRect().top;
const elementVisible = 100;
if (elementTop < windowHeight - elementVisible) {
setTimeout(() => {
element.style.opacity = '1';
element.style.transform = 'translateY(0)';
}, index * 50);
}
});
};
window.addEventListener('scroll', revealOnScroll);
revealOnScroll(); // Check on initial load
},
// Scroll-based animations
initScrollAnimations() {
let lastScrollY = window.scrollY;
let ticking = false;
function updateScrollAnimations() {
const scrollY = window.scrollY;
const scrollDirection = scrollY > lastScrollY ? 'down' : 'up';
// Hero parallax
const hero = document.querySelector('.hero-content');
if (hero) {
hero.style.transform = `translateY(${scrollY * 0.5}px)`;
hero.style.opacity = 1 - (scrollY / 800);
}
// Video parallax
const heroVideos = document.querySelector('.hero-video-container');
if (heroVideos) {
heroVideos.style.transform = `translateY(${scrollY * 0.3}px) scale(${1 + scrollY * 0.0003})`;
}
lastScrollY = scrollY;
ticking = false;
}
function requestTick() {
if (!ticking) {
window.requestAnimationFrame(updateScrollAnimations);
ticking = true;
}
}
window.addEventListener('scroll', requestTick);
},
// Enhanced navbar effects
initNavbarEffects() {
const navbar = document.querySelector('.navbar');
let lastScrollY = window.scrollY;
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
if (scrollY > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
// Keep navbar always visible
navbar.style.transform = 'translateY(0)';
lastScrollY = scrollY;
});
}
};
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => EnhancedAnimations.init());
} else {
EnhancedAnimations.init();
}

Datei anzeigen

@@ -1,403 +0,0 @@
/**
* Animation module for AegisSight website
* Contains all animation logic and visual effects
*/
// Particle Animation System
const ParticleAnimation = {
canvas: null,
ctx: null,
particles: [],
/**
* Initialize particle animation
*/
init() {
this.canvas = document.querySelector(SELECTORS.PARTICLE_CANVAS);
if (!this.canvas) return;
this.ctx = this.canvas.getContext('2d');
this.resizeCanvas();
this.createParticles();
this.animate();
// Handle window resize
window.addEventListener('resize', () => this.resizeCanvas());
},
/**
* Resize canvas to window size
*/
resizeCanvas() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
},
/**
* Create particle objects
*/
createParticles() {
this.particles = [];
for (let i = 0; i < CONFIG.ANIMATION.PARTICLE_COUNT; i++) {
this.particles.push(new Particle(this.canvas));
}
},
/**
* Main animation loop
*/
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Update and draw particles
this.particles.forEach(particle => {
particle.update(this.canvas);
particle.draw(this.ctx);
});
// Draw connections between particles
this.drawConnections();
requestAnimationFrame(() => this.animate());
},
/**
* Draw connections between nearby particles
*/
drawConnections() {
for (let a = 0; a < this.particles.length; a++) {
for (let b = a + 1; b < this.particles.length; b++) {
const distance = Math.sqrt(
Math.pow(this.particles[a].x - this.particles[b].x, 2) +
Math.pow(this.particles[a].y - this.particles[b].y, 2)
);
if (distance < CONFIG.ANIMATION.CONNECTION_DISTANCE) {
const opacity = 0.15 * (1 - distance / CONFIG.ANIMATION.CONNECTION_DISTANCE);
// Use darker blue for better visibility on light background
this.ctx.strokeStyle = `rgba(15, 114, 181, ${opacity})`;
this.ctx.lineWidth = 1;
this.ctx.beginPath();
this.ctx.moveTo(this.particles[a].x, this.particles[a].y);
this.ctx.lineTo(this.particles[b].x, this.particles[b].y);
this.ctx.stroke();
}
}
}
}
};
/**
* Particle class for animation
*/
class Particle {
constructor(canvas) {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.size = Math.random() * (CONFIG.ANIMATION.PARTICLE_SIZE_MAX - CONFIG.ANIMATION.PARTICLE_SIZE_MIN) + CONFIG.ANIMATION.PARTICLE_SIZE_MIN;
this.speedX = (Math.random() - 0.5) * CONFIG.ANIMATION.PARTICLE_SPEED;
this.speedY = (Math.random() - 0.5) * CONFIG.ANIMATION.PARTICLE_SPEED;
this.opacity = Math.random() * 0.5 + 0.2;
}
update(canvas) {
this.x += this.speedX;
this.y += this.speedY;
// Wrap around screen edges
if (this.x > canvas.width) this.x = 0;
else if (this.x < 0) this.x = canvas.width;
if (this.y > canvas.height) this.y = 0;
else if (this.y < 0) this.y = canvas.height;
}
draw(ctx) {
// Use darker blue for better visibility on light background
ctx.fillStyle = `rgba(15, 114, 181, ${this.opacity * 0.7})`;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
}
}
// Counter Animation
const CounterAnimation = {
/**
* Animate all counter elements
*/
animateAll() {
const counters = document.querySelectorAll(SELECTORS.INDICATOR_VALUE);
counters.forEach(counter => this.animateCounter(counter));
},
/**
* Animate a single counter
* @param {HTMLElement} counter - Counter element to animate
*/
animateCounter(counter) {
const target = parseFloat(counter.getAttribute(DATA_ATTRS.TARGET));
const increment = target / CONFIG.ANIMATION.COUNTER_SPEED;
let current = 0;
const updateCounter = () => {
current += increment;
if (current < target) {
counter.innerText = Math.ceil(current);
setTimeout(updateCounter, CONFIG.TIMING.COUNTER_UPDATE_INTERVAL);
} else {
// Set final value with proper formatting
if (target === CONFIG.TRUST_INDICATORS.AVAILABILITY) {
counter.innerText = target + '%';
} else if (target === CONFIG.TRUST_INDICATORS.AUTHORITIES_COUNT) {
counter.innerText = target + '+';
} else if (target === CONFIG.TRUST_INDICATORS.SUPPORT_HOURS) {
counter.innerText = target + '/7';
}
}
};
updateCounter();
}
};
// Scroll Animations
const ScrollAnimations = {
scrollIndicator: null,
/**
* Initialize scroll-based animations
*/
init() {
this.scrollIndicator = document.querySelector(SELECTORS.SCROLL_INDICATOR);
this.setupScrollIndicator();
this.setupIntersectionObserver();
},
/**
* Setup scroll indicator behavior
*/
setupScrollIndicator() {
if (!this.scrollIndicator) return;
// Click to scroll to about section
this.scrollIndicator.addEventListener('click', () => {
const aboutSection = document.querySelector('#about');
if (aboutSection) {
aboutSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
// Hide/show based on scroll position
let scrollTimeout;
window.addEventListener('scroll', () => {
const hero = document.querySelector(SELECTORS.HERO);
if (window.scrollY > CONFIG.ANIMATION.SCROLL_THRESHOLD) {
if (hero) hero.classList.add(CLASSES.SCROLLED);
if (this.scrollIndicator) this.scrollIndicator.style.opacity = '0';
} else {
if (hero) hero.classList.remove(CLASSES.SCROLLED);
if (this.scrollIndicator) this.scrollIndicator.style.opacity = '1';
}
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
if (window.scrollY > CONFIG.ANIMATION.SCROLL_THRESHOLD && this.scrollIndicator) {
this.scrollIndicator.style.display = 'none';
} else if (this.scrollIndicator) {
this.scrollIndicator.style.display = 'flex';
}
}, CONFIG.TIMING.SCROLL_HIDE_DELAY);
});
},
/**
* Setup intersection observer for scroll-triggered animations
*/
setupIntersectionObserver() {
const observerOptions = {
threshold: CONFIG.OBSERVER.THRESHOLD,
rootMargin: CONFIG.OBSERVER.ROOT_MARGIN
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Trust indicators animation
if (entry.target.classList.contains('trust-indicators')) {
CounterAnimation.animateAll();
observer.unobserve(entry.target);
}
// Timeline animation
if (entry.target.classList.contains('timeline')) {
const items = entry.target.querySelectorAll('.timeline-item');
items.forEach((item, index) => {
setTimeout(() => {
item.classList.add(CLASSES.VISIBLE);
}, index * 300);
});
observer.unobserve(entry.target);
}
// Feature nodes animation
if (entry.target.classList.contains('feature-nodes')) {
const nodes = entry.target.querySelectorAll('.node');
nodes.forEach((node, index) => {
setTimeout(() => {
node.style.opacity = '1';
node.style.transform = 'translateY(0)';
}, index * 150);
});
observer.unobserve(entry.target);
}
}
});
}, observerOptions);
// Observe elements
const trustIndicators = document.querySelector(SELECTORS.TRUST_INDICATORS);
if (trustIndicators) {
trustIndicators.style.opacity = '0';
observer.observe(trustIndicators);
}
const timeline = document.querySelector('.timeline');
if (timeline) observer.observe(timeline);
const featureNodes = document.querySelector('.feature-nodes');
if (featureNodes) {
document.querySelectorAll('.node').forEach(node => {
node.style.opacity = '0';
node.style.transform = 'translateY(30px)';
node.style.transition = 'all 0.6s ease';
});
observer.observe(featureNodes);
}
}
};
// Glitch Effect
const GlitchEffect = {
/**
* Apply glitch effect to element on hover
* @param {HTMLElement} element - Element to apply effect to
*/
apply(element) {
if (!element) return;
let glitchInterval;
element.addEventListener('mouseenter', () => {
let count = 0;
glitchInterval = setInterval(() => {
element.style.textShadow = `
${Math.random() * 5}px ${Math.random() * 5}px 0 rgba(0, 212, 255, 0.5),
${Math.random() * -5}px ${Math.random() * 5}px 0 rgba(255, 0, 128, 0.5)
`;
count++;
if (count > CONFIG.ANIMATION.GLITCH_ITERATIONS) {
clearInterval(glitchInterval);
element.style.textShadow = 'none';
}
}, CONFIG.ANIMATION.GLITCH_INTERVAL);
});
}
};
// Interactive Elements
const InteractiveElements = {
/**
* Initialize all interactive element animations
*/
init() {
this.setupNodeHoverEffects();
this.setupWidgetHoverEffects();
this.setupInteractiveIcon();
},
/**
* Setup hover effects for node elements
*/
setupNodeHoverEffects() {
document.querySelectorAll('.node').forEach(node => {
node.addEventListener('mouseenter', function() {
const icon = this.querySelector('.node-icon');
if (icon) icon.style.transform = 'scale(1.2) rotate(5deg)';
});
node.addEventListener('mouseleave', function() {
const icon = this.querySelector('.node-icon');
if (icon) icon.style.transform = 'scale(1) rotate(0deg)';
});
});
},
/**
* Setup hover effects for widget elements
*/
setupWidgetHoverEffects() {
document.querySelectorAll('.widget').forEach(widget => {
widget.addEventListener('mouseenter', function() {
this.style.boxShadow = '0 5px 20px rgba(0, 212, 255, 0.3)';
});
widget.addEventListener('mouseleave', function() {
this.style.boxShadow = 'none';
});
});
},
/**
* Setup 3D interactive icon effect
*/
setupInteractiveIcon() {
const icon = document.querySelector(SELECTORS.INTERACTIVE_ICON);
if (!icon) return;
document.addEventListener('mousemove', (e) => {
const rect = icon.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const mouseX = (e.clientX - centerX) / 20;
const mouseY = (e.clientY - centerY) / 20;
icon.style.transform = `perspective(1000px) rotateY(${mouseX}deg) rotateX(${-mouseY}deg)`;
});
}
};
// Initialize all animations
const Animations = {
/**
* Initialize all animation systems
*/
init() {
// Core animations
ParticleAnimation.init();
ScrollAnimations.init();
InteractiveElements.init();
// Apply glitch effect to main title
const mainTitle = document.querySelector('.main-title');
if (mainTitle) {
GlitchEffect.apply(mainTitle);
}
// Page load animations
window.addEventListener('load', () => {
document.body.classList.add(CLASSES.LOADED);
// Fade in hero content
setTimeout(() => {
const heroContent = document.querySelector(SELECTORS.HERO_CONTENT);
if (heroContent) {
heroContent.style.opacity = '1';
heroContent.style.transform = 'translateY(0)';
}
}, 100);
});
}
};

Datei anzeigen

@@ -1,515 +0,0 @@
/**
* UI Components module for AegisSight website
* Contains all interactive UI component logic
*/
// Language Toggle Component
const LanguageToggle = {
element: null,
/**
* Initialize language toggle
*/
init() {
this.element = document.querySelector(SELECTORS.LANG_TOGGLE);
if (!this.element) return;
this.element.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
this.toggle();
});
},
/**
* Toggle between languages
*/
toggle() {
const newLanguage = getCurrentLanguage() === 'de' ? 'en' : 'de';
switchLanguage(newLanguage);
// Update expand button text after language change
ProductShowcase.updateExpandButtonText();
}
};
// Navigation Component
const Navigation = {
navbar: null,
/**
* Initialize navigation component
*/
init() {
this.navbar = document.querySelector(SELECTORS.NAVBAR);
this.setupSmoothScrolling();
this.setupMobileMenu();
},
/**
* Setup smooth scrolling for anchor links
*/
setupSmoothScrolling() {
document.querySelectorAll(SELECTORS.SMOOTH_LINKS).forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const target = document.querySelector(targetId);
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
},
/**
* Setup mobile menu functionality
*/
setupMobileMenu() {
// Mobile menu logic would go here if needed
// Currently not implemented as per YAGNI principle
}
};
// About Section Tabs
const AboutTabs = {
tabs: null,
panels: null,
/**
* Initialize about section tabs
*/
init() {
this.tabs = document.querySelectorAll(SELECTORS.ABOUT_TABS);
this.panels = document.querySelectorAll(SELECTORS.ABOUT_PANELS);
if (!this.tabs.length) return;
this.tabs.forEach(tab => {
tab.addEventListener('click', () => this.switchTab(tab));
});
},
/**
* Switch to selected tab
* @param {HTMLElement} selectedTab - Tab element that was clicked
*/
switchTab(selectedTab) {
const targetPanelId = selectedTab.getAttribute(DATA_ATTRS.TAB);
// Remove active class from all tabs and panels
this.tabs.forEach(tab => tab.classList.remove(CLASSES.ACTIVE));
this.panels.forEach(panel => panel.classList.remove(CLASSES.ACTIVE));
// Add active class to selected tab and corresponding panel
selectedTab.classList.add(CLASSES.ACTIVE);
const targetPanel = document.getElementById(targetPanelId);
if (targetPanel) {
targetPanel.classList.add(CLASSES.ACTIVE);
}
}
};
// Product Showcase Component
const ProductShowcase = {
expandButton: null,
toolsGrid: null,
/**
* Initialize product showcase
*/
init() {
this.expandButton = document.querySelector(SELECTORS.EXPAND_BUTTON);
this.toolsGrid = document.querySelector(SELECTORS.TOOLS_GRID);
if (!this.expandButton || !this.toolsGrid) return;
this.expandButton.addEventListener('click', () => this.toggleExpand());
},
/**
* Toggle expand/collapse state
*/
toggleExpand() {
const isExpanded = this.expandButton.getAttribute(DATA_ATTRS.EXPANDED) === 'true';
if (isExpanded) {
this.collapse();
} else {
this.expand();
}
},
/**
* Expand the tools grid
*/
expand() {
this.toolsGrid.classList.remove(CLASSES.COLLAPSED);
this.expandButton.setAttribute(DATA_ATTRS.EXPANDED, 'true');
this.updateExpandButtonText();
},
/**
* Collapse the tools grid
*/
collapse() {
this.toolsGrid.classList.add(CLASSES.COLLAPSED);
this.expandButton.setAttribute(DATA_ATTRS.EXPANDED, 'false');
this.updateExpandButtonText();
},
/**
* Update expand button text based on state
*/
updateExpandButtonText() {
const expandText = this.expandButton?.querySelector('.expand-text');
if (!expandText) return;
const isExpanded = this.expandButton.getAttribute(DATA_ATTRS.EXPANDED) === 'true';
expandText.textContent = getTranslation(isExpanded ? 'hideDetails' : 'expandDetails');
}
};
// Login Modal Component
const LoginModal = {
modalElement: null,
modalStyles: null,
/**
* Show login modal
*/
show() {
this.createModal();
this.attachEventListeners();
},
/**
* Create modal HTML and styles
*/
createModal() {
// Create modal element
this.modalElement = document.createElement('div');
this.modalElement.className = 'login-modal';
this.modalElement.innerHTML = this.getModalHTML();
document.body.appendChild(this.modalElement);
// Add modal styles if not already added
if (!this.modalStyles) {
this.addModalStyles();
}
},
/**
* Get modal HTML content
* @returns {string} Modal HTML
*/
getModalHTML() {
const t = getTranslation;
return `
<div class="modal-content">
<button class="modal-close">×</button>
<div class="modal-header">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="lock-icon">
<rect x="5" y="11" width="14" height="10" rx="2" stroke="currentColor" stroke-width="2"/>
<path d="M7 11V7C7 4.23858 9.23858 2 12 2C14.7614 2 17 4.23858 17 7V11" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="16" r="1" fill="currentColor"/>
</svg>
<h3>${t('authRequired')}</h3>
</div>
<p>${t('authDescription')}</p>
<form id="loginForm">
<div class="form-group">
<label for="auth-password">${t('accessCode')}</label>
<input type="password" id="auth-password" placeholder="${t('accessCodePlaceholder')}" required autofocus>
</div>
<button type="submit" class="primary-button">${t('grantAccess')}</button>
</form>
<p class="auth-note">${t('noAccess')} <a href="mailto:info@aegis-sight.de">${t('contactUs')}</a></p>
</div>
`;
},
/**
* Add modal styles to document
*/
addModalStyles() {
this.modalStyles = document.createElement('style');
this.modalStyles.textContent = `
.login-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(10, 24, 50, 0.85);
backdrop-filter: blur(12px);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
animation: fadeIn 0.3s ease;
}
.modal-content {
background: #0A1832;
border-radius: 12px;
padding: 2.5rem;
max-width: 400px;
width: 90%;
position: relative;
border: 1px solid rgba(200, 168, 81, 0.3);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.modal-header {
text-align: center;
margin-bottom: 1.5rem;
}
.modal-header .lock-icon {
width: 48px;
height: 48px;
color: #C8A851;
margin-bottom: 1rem;
}
.modal-close {
position: absolute;
top: 1rem;
right: 1rem;
background: none;
border: none;
color: rgba(255, 255, 255, 0.4);
font-size: 2rem;
cursor: pointer;
transition: all 0.3s ease;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.modal-close:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
.modal-content h3 {
color: #FFFFFF;
margin-bottom: 0.5rem;
font-size: 1.5rem;
font-weight: 600;
}
.modal-content p {
color: rgba(255, 255, 255, 0.6);
margin-bottom: 2rem;
text-align: center;
}
.modal-content .form-group {
margin-bottom: 1.5rem;
}
.modal-content label {
display: block;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 0.5rem;
font-weight: 500;
}
.modal-content input {
width: 100%;
padding: 0.875rem;
background: rgba(255, 255, 255, 0.05);
border: 2px solid rgba(255, 255, 255, 0.15);
border-radius: 8px;
color: #FFFFFF;
font-size: 1rem;
transition: all 0.3s ease;
}
.modal-content input:focus {
outline: none;
border-color: #C8A851;
background: rgba(255, 255, 255, 0.08);
}
.modal-content input::placeholder {
color: rgba(255, 255, 255, 0.3);
}
.modal-content .primary-button {
width: 100%;
padding: 0.875rem;
background: #C8A851;
color: #0A1832;
border: none;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.modal-content .primary-button:hover {
background: #D4B96A;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(200, 168, 81, 0.4);
}
.auth-note {
text-align: center;
margin-top: 1.5rem;
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.4);
}
.auth-note a {
color: #C8A851;
text-decoration: none;
}
.auth-note a:hover {
text-decoration: underline;
}
`;
document.head.appendChild(this.modalStyles);
},
/**
* Attach event listeners to modal
*/
attachEventListeners() {
// Close button
const closeBtn = this.modalElement.querySelector('.modal-close');
closeBtn.addEventListener('click', () => this.close());
// Form submission
const form = this.modalElement.querySelector('#loginForm');
form.addEventListener('submit', (e) => this.handleSubmit(e));
// Click outside to close
this.modalElement.addEventListener('click', (e) => {
if (e.target === this.modalElement) {
this.close();
}
});
},
/**
* Handle form submission
* @param {Event} e - Submit event
*/
async handleSubmit(e) {
e.preventDefault();
const password = document.getElementById('auth-password').value;
try {
// Validate token via Insights API
const response = await fetch('/insights/api/validate-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token: password })
});
const result = await response.json();
if (result.valid) {
sessionStorage.setItem(CONFIG.AUTH.SESSION_KEY, 'true');
this.close();
window.location.href = CONFIG.AUTH.REDIRECT_PAGE;
} else {
alert(getTranslation('wrongCode'));
document.getElementById('auth-password').value = '';
document.getElementById('auth-password').focus();
}
} catch (error) {
console.error('Token validation error:', error);
alert(getTranslation('wrongCode'));
}
},
/**
* Close and remove modal
*/
close() {
if (this.modalElement) {
this.modalElement.remove();
this.modalElement = null;
}
}
};
// Contact Form Component
const ContactForm = {
form: null,
/**
* Initialize contact form
*/
init() {
this.form = document.querySelector(SELECTORS.CONTACT_FORM);
if (!this.form) return;
this.form.addEventListener('submit', (e) => this.handleSubmit(e));
},
/**
* Handle form submission
* @param {Event} e - Submit event
*/
handleSubmit(e) {
e.preventDefault();
// Get form data
const formData = new FormData(this.form);
const data = Object.fromEntries(formData.entries());
// In production, this would send data to server
console.log('Form submission:', data);
// Show success message
alert(getTranslation('contactFormSuccess'));
this.form.reset();
}
};
// Demo Request Handler
const DemoRequest = {
/**
* Initialize demo request buttons
*/
init() {
document.querySelectorAll('.primary-button, .secondary-button, .cta-button').forEach(button => {
if (button.textContent.toLowerCase().includes('demo')) {
button.addEventListener('click', (e) => this.handleDemoRequest(e));
}
});
},
/**
* Handle demo request
* @param {Event} e - Click event
*/
handleDemoRequest(e) {
e.preventDefault();
alert(getTranslation('demoRequestAlert'));
}
};
// Initialize all components
const Components = {
/**
* Initialize all UI components
*/
init() {
LanguageToggle.init();
Navigation.init();
AboutTabs.init();
ProductShowcase.init();
ContactForm.init();
DemoRequest.init();
}
};
// Make showLoginModal globally available for onclick attribute
window.showLoginModal = function() {
LoginModal.show();
};
// Make closeLoginModal globally available for onclick attribute
window.closeLoginModal = function() {
LoginModal.close();
};

Datei anzeigen

@@ -1,209 +0,0 @@
/**
* Hero Video Rotation System
* Manages rotating background videos in hero section
*/
const HeroVideoRotation = {
videos: [],
currentIndex: 0,
rotationInterval: null,
isTransitioning: false,
/**
* Initialize the video rotation system
*/
init() {
// Get all video elements
this.videos = document.querySelectorAll('.hero-video');
if (!this.videos.length) return;
// Setup event listeners
this.setupEventListeners();
// Start rotation
this.startRotation();
// Ensure first video is playing
this.playVideo(0);
},
/**
* Setup event listeners for videos
*/
setupEventListeners() {
// Indicators removed - no click handlers needed
// Pause rotation on hover (optional)
const heroSection = document.querySelector('.hero');
if (heroSection) {
heroSection.addEventListener('mouseenter', () => {
// Optional: pause rotation on hover
// this.stopRotation();
});
heroSection.addEventListener('mouseleave', () => {
// Optional: resume rotation
// this.startRotation();
});
}
// Handle video load errors gracefully
this.videos.forEach((video, index) => {
video.addEventListener('error', () => {
console.warn(`Video ${index} failed to load, skipping...`);
// If current video fails, move to next
if (index === this.currentIndex) {
this.nextVideo();
}
});
// Ensure videos are ready to play
video.addEventListener('loadeddata', () => {
console.log(`Video ${index} loaded successfully`);
});
});
},
/**
* Start automatic rotation
*/
startRotation() {
// Clear any existing interval
this.stopRotation();
// Set new interval
this.rotationInterval = setInterval(() => {
this.nextVideo();
}, CONFIG.HERO_VIDEOS.ROTATION_INTERVAL);
},
/**
* Stop automatic rotation
*/
stopRotation() {
if (this.rotationInterval) {
clearInterval(this.rotationInterval);
this.rotationInterval = null;
}
},
/**
* Switch to next video
*/
nextVideo() {
const nextIndex = (this.currentIndex + 1) % this.videos.length;
this.switchToVideo(nextIndex);
},
/**
* Switch to previous video
*/
previousVideo() {
const prevIndex = (this.currentIndex - 1 + this.videos.length) % this.videos.length;
this.switchToVideo(prevIndex);
},
/**
* Switch to specific video by index
* @param {number} index - Video index to switch to
*/
switchToVideo(index) {
if (this.isTransitioning || index === this.currentIndex) return;
this.isTransitioning = true;
const currentVideo = this.videos[this.currentIndex];
const nextVideo = this.videos[index];
// Indicators removed - no update needed
// Prepare next video
this.prepareVideo(nextVideo);
// Fade out current video
currentVideo.classList.add('fading-out');
// After half the fade duration, start fading in the next video
setTimeout(() => {
nextVideo.classList.add('active');
nextVideo.classList.remove('fading-out');
// Play next video
this.playVideo(index);
}, CONFIG.HERO_VIDEOS.FADE_DURATION / 2);
// Complete transition
setTimeout(() => {
currentVideo.classList.remove('active', 'fading-out');
this.currentIndex = index;
this.isTransitioning = false;
}, CONFIG.HERO_VIDEOS.FADE_DURATION);
},
/**
* Prepare video for playback
* @param {HTMLVideoElement} video - Video element to prepare
*/
prepareVideo(video) {
// Reset video to beginning
video.currentTime = 0;
// Ensure video is ready to play
const playPromise = video.play();
if (playPromise !== undefined) {
playPromise.catch(error => {
console.warn('Video autoplay was prevented:', error);
});
}
},
/**
* Play specific video
* @param {number} index - Index of video to play
*/
playVideo(index) {
const video = this.videos[index];
if (video) {
const playPromise = video.play();
if (playPromise !== undefined) {
playPromise.catch(error => {
console.warn(`Could not play video ${index}:`, error);
});
}
}
},
/**
* Pause all videos
*/
pauseAllVideos() {
this.videos.forEach(video => {
video.pause();
});
},
/**
* Handle page visibility change (pause when tab is not visible)
*/
handleVisibilityChange() {
if (document.hidden) {
this.stopRotation();
this.pauseAllVideos();
} else {
this.playVideo(this.currentIndex);
this.startRotation();
}
}
};
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
HeroVideoRotation.init();
});
// Handle page visibility API
document.addEventListener('visibilitychange', () => {
HeroVideoRotation.handleVisibilityChange();
});

Datei anzeigen

@@ -1,54 +0,0 @@
/**
* Minimal JavaScript for legal pages (Impressum & Datenschutz)
* Only includes necessary functionality for language switching
*/
// Set current year in footer
function setCurrentYear() {
const currentYear = new Date().getFullYear();
const yearElements = document.querySelectorAll('.current-year');
yearElements.forEach(element => {
element.textContent = currentYear;
});
}
// Simple language toggle for legal pages
document.addEventListener('DOMContentLoaded', function() {
// Set current year immediately
setCurrentYear();
// Get the language toggle button
const langToggle = document.querySelector('.lang-toggle');
if (langToggle) {
langToggle.addEventListener('click', function(e) {
e.preventDefault();
// Get current language from button
const currentLang = this.getAttribute('data-lang') || 'de';
const newLang = currentLang === 'de' ? 'en' : 'de';
// Store language preference
if (typeof(Storage) !== 'undefined') {
localStorage.setItem('aegissight_language', newLang);
}
// Get current page name
const currentPage = window.location.pathname.split('/').pop();
// Determine redirect URL
let redirectUrl = '';
if (currentPage === 'impressum.html' || currentPage === 'impressum-en.html') {
redirectUrl = newLang === 'en' ? 'impressum-en.html' : 'impressum.html';
} else if (currentPage === 'datenschutz.html' || currentPage === 'datenschutz-en.html') {
redirectUrl = newLang === 'en' ? 'datenschutz-en.html' : 'datenschutz.html';
}
// Redirect to the appropriate version
if (redirectUrl) {
window.location.href = redirectUrl;
}
});
}
});

Datei anzeigen

@@ -1,305 +0,0 @@
/**
* Main application entry point for AegisSight website
* Initializes all modules and coordinates application startup
*/
/**
* Toggle tools grid visibility
*/
function toggleTools(button) {
// Find the tools grid within the same product card
const productCard = button.closest('.product-card');
const toolsGrid = productCard.querySelector('.tools-grid');
if (toolsGrid) {
const isExpanded = toolsGrid.classList.contains('expanded');
const currentLang = getCurrentLanguage ? getCurrentLanguage() : 'de';
if (isExpanded) {
toolsGrid.classList.remove('expanded');
toolsGrid.classList.add('collapsed');
button.setAttribute('data-expanded', 'false');
button.querySelector('span').textContent = currentLang === 'de' ? 'Details anzeigen' : 'Show Details';
} else {
// Force browser reflow before adding expanded class
toolsGrid.style.display = 'grid';
void toolsGrid.offsetHeight; // Trigger reflow
toolsGrid.classList.remove('collapsed');
toolsGrid.classList.add('expanded');
button.setAttribute('data-expanded', 'true');
button.querySelector('span').textContent = currentLang === 'de' ? 'Details verbergen' : 'Hide Details';
// Ensure all tool cards are visible
setTimeout(() => {
const toolCards = toolsGrid.querySelectorAll('.tool-card');
toolCards.forEach((card, index) => {
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
});
}, 100);
}
}
}
/**
* Application initialization
*/
const App = {
/**
* Initialize the entire application
*/
init() {
// Check DOM ready state
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.start());
} else {
// DOM is already ready
this.start();
}
},
/**
* Start the application after DOM is ready
*/
start() {
console.log('AegisSight Website Initializing...');
// Initialize modules in correct order
try {
// 1. Initialize translations first (includes year replacement)
initTranslations();
console.log('✓ Translations initialized');
// 2. Initialize UI components
Components.init();
console.log('✓ Components initialized');
// 3. Initialize animations
Animations.init();
console.log('✓ Animations initialized');
// 4. Setup error handling
this.setupErrorHandling();
// 5. Setup performance monitoring
this.setupPerformanceMonitoring();
console.log('AegisSight Website Ready!');
} catch (error) {
console.error('Failed to initialize application:', error);
this.handleInitError(error);
}
},
/**
* Setup global error handling
*/
setupErrorHandling() {
window.addEventListener('error', (event) => {
console.error('Global error:', event.error);
// In production, this would send errors to monitoring service
});
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled promise rejection:', event.reason);
// In production, this would send errors to monitoring service
});
},
/**
* Setup performance monitoring
*/
setupPerformanceMonitoring() {
// Monitor page load performance
window.addEventListener('load', () => {
if (window.performance && window.performance.timing) {
const timing = window.performance.timing;
const loadTime = timing.loadEventEnd - timing.navigationStart;
console.log(`Page load time: ${loadTime}ms`);
// Log other performance metrics
const metrics = {
domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart,
domComplete: timing.domComplete - timing.navigationStart,
firstPaint: this.getFirstPaintTime()
};
console.log('Performance metrics:', metrics);
}
});
},
/**
* Set current year in footer and update translations dynamically
*/
setCurrentYear() {
const currentYear = new Date().getFullYear();
// Set current year in main footer span element
const yearElement = document.getElementById('currentYear');
if (yearElement) {
yearElement.textContent = currentYear;
}
// Set current year in legal pages footer spans
const legalYearElements = document.querySelectorAll('.current-year');
legalYearElements.forEach(element => {
element.textContent = currentYear;
});
// Update copyright translation with current year
if (window.translations) {
Object.keys(window.translations).forEach(lang => {
if (window.translations[lang].copyright) {
window.translations[lang].copyright = window.translations[lang].copyright.replace('{year}', currentYear);
}
});
}
},
/**
* Get first paint time if available
* @returns {number|null} First paint time in milliseconds
*/
getFirstPaintTime() {
if (window.performance && window.performance.getEntriesByType) {
const paintEntries = window.performance.getEntriesByType('paint');
const firstPaint = paintEntries.find(entry => entry.name === 'first-paint');
return firstPaint ? Math.round(firstPaint.startTime) : null;
}
return null;
},
/**
* Handle initialization errors
* @param {Error} error - The error that occurred
*/
handleInitError(error) {
// Create a fallback error message for users
const errorContainer = document.createElement('div');
errorContainer.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #ff4444;
color: white;
padding: 15px 20px;
border-radius: 5px;
z-index: 10000;
max-width: 300px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
`;
errorContainer.textContent = 'Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu.';
document.body.appendChild(errorContainer);
// Auto-remove after 5 seconds
setTimeout(() => {
errorContainer.remove();
}, 5000);
}
};
/**
* Utility functions
*/
const Utils = {
/**
* Debounce function to limit function calls
* @param {Function} func - Function to debounce
* @param {number} wait - Wait time in milliseconds
* @returns {Function} Debounced function
*/
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
/**
* Throttle function to limit function calls
* @param {Function} func - Function to throttle
* @param {number} limit - Time limit in milliseconds
* @returns {Function} Throttled function
*/
throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
},
/**
* Check if element is in viewport
* @param {HTMLElement} element - Element to check
* @returns {boolean} True if element is in viewport
*/
isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
},
/**
* Load script dynamically
* @param {string} src - Script source URL
* @returns {Promise} Promise that resolves when script is loaded
*/
loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
},
/**
* Get cookie value by name
* @param {string} name - Cookie name
* @returns {string|null} Cookie value or null
*/
getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return parts.pop().split(';').shift();
}
return null;
},
/**
* Set cookie
* @param {string} name - Cookie name
* @param {string} value - Cookie value
* @param {number} days - Days until expiration
*/
setCookie(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = `expires=${date.toUTCString()}`;
document.cookie = `${name}=${value};${expires};path=/`;
}
};
// Make Utils globally available if needed
window.Utils = Utils;
// Start the application
App.init();

Datei anzeigen

@@ -1,130 +0,0 @@
/**
* Section Transitions & Effects
* Modern animations for section dividers
*/
const SectionTransitions = {
init() {
this.initParticleBridge();
this.initScrollReveal();
this.initWaveAnimation();
this.initParallaxDividers();
},
// Animated particles between sections
initParticleBridge() {
const bridge = document.getElementById('particleBridge');
if (!bridge) return;
// Create floating particles
for (let i = 0; i < 30; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = Math.random() * 5 + 's';
particle.style.animationDuration = (5 + Math.random() * 5) + 's';
particle.style.animation = `floatParticle ${5 + Math.random() * 5}s linear infinite`;
bridge.appendChild(particle);
}
},
// Reveal sections on scroll
initScrollReveal() {
const sections = document.querySelectorAll('.fade-section');
const revealSection = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
// Add shimmer effect on reveal
const shimmer = document.createElement('div');
shimmer.style.cssText = `
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(15, 114, 181, 0.2), transparent);
animation: shimmerPass 1s ease-out forwards;
pointer-events: none;
z-index: 100;
`;
entry.target.style.position = 'relative';
entry.target.appendChild(shimmer);
setTimeout(() => shimmer.remove(), 1000);
}
});
};
const observer = new IntersectionObserver(revealSection, {
threshold: 0.1,
rootMargin: '0px 0px -100px 0px'
});
sections.forEach(section => observer.observe(section));
},
// Animate wave dividers
initWaveAnimation() {
const waves = document.querySelectorAll('.wave-divider path');
waves.forEach(wave => {
let time = 0;
const animateWave = () => {
time += 0.02;
const points = [];
for (let i = 0; i <= 10; i++) {
const x = (i / 10) * 1200;
const y = Math.sin((i / 10) * Math.PI * 2 + time) * 10 + 56;
points.push(`${x},${y}`);
}
// Create smooth wave path
const d = `M0,56 Q${points[2]} T${points[4]} T${points[6]} T${points[8]} T1200,56 L1200,0 L0,0 Z`;
wave.setAttribute('d', d);
requestAnimationFrame(animateWave);
};
// Start wave animation
// animateWave(); // Commented out for performance, uncomment for wave motion
});
},
// Parallax effect for dividers
initParallaxDividers() {
const dividers = document.querySelectorAll('.blob-divider, .gradient-divider, .flow-lines');
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
dividers.forEach(divider => {
const speed = divider.dataset.speed || 0.5;
const yPos = -(scrolled * speed);
divider.style.transform = `translateY(${yPos}px)`;
});
});
}
};
// Add shimmer animation
const style = document.createElement('style');
style.textContent = `
@keyframes shimmerPass {
to {
left: 100%;
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => SectionTransitions.init());
} else {
SectionTransitions.init();
}