new file: Dockerfile new file: README.md new file: app.py new file: index.html new file: projekte des/PROJECT_DESCRIPTION.txt new file: projekte des/WEBSITE_DESCRIPTION.md new file: projekte des/website_project_description_en.txt new file: requirements.txt new file: script.js new file: static/css/styles.css new file: static/js/script.js new file: styles.css new file: templates/about.html new file: templates/base.html new file: templates/contact.html new file: templates/index.html new file: templates/minecraft.html new file: templates/project_detail.html new file: templates/projects.html
220 lines
6.5 KiB
JavaScript
220 lines
6.5 KiB
JavaScript
// Mobile Navigation Toggle
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const hamburger = document.querySelector('.hamburger');
|
|
const navLinks = document.querySelector('.nav-links');
|
|
|
|
hamburger.addEventListener('click', function() {
|
|
navLinks.classList.toggle('active');
|
|
hamburger.classList.toggle('active');
|
|
});
|
|
|
|
// Close mobile nav when clicking on a link
|
|
document.querySelectorAll('.nav-links a').forEach(link => {
|
|
link.addEventListener('click', () => {
|
|
navLinks.classList.remove('active');
|
|
hamburger.classList.remove('active');
|
|
});
|
|
});
|
|
});
|
|
|
|
// Smooth scrolling for navigation links
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
const target = document.querySelector(this.getAttribute('href'));
|
|
if (target) {
|
|
target.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Navbar background on scroll
|
|
window.addEventListener('scroll', function() {
|
|
const navbar = document.querySelector('.navbar');
|
|
if (window.scrollY > 100) {
|
|
navbar.style.background = 'rgba(10, 10, 10, 0.98)';
|
|
} else {
|
|
navbar.style.background = 'rgba(10, 10, 10, 0.95)';
|
|
}
|
|
});
|
|
|
|
// Intersection Observer for animations
|
|
const observeElements = () => {
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.style.opacity = '1';
|
|
entry.target.style.transform = 'translateY(0)';
|
|
}
|
|
});
|
|
}, {
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -50px 0px'
|
|
});
|
|
|
|
// Observe project cards
|
|
document.querySelectorAll('.project-card').forEach(card => {
|
|
card.style.opacity = '0';
|
|
card.style.transform = 'translateY(30px)';
|
|
card.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
|
observer.observe(card);
|
|
});
|
|
|
|
// Observe tech items
|
|
document.querySelectorAll('.tech-item').forEach((item, index) => {
|
|
item.style.opacity = '0';
|
|
item.style.transform = 'translateY(30px)';
|
|
item.style.transition = `opacity 0.6s ease ${index * 0.1}s, transform 0.6s ease ${index * 0.1}s`;
|
|
observer.observe(item);
|
|
});
|
|
|
|
// Observe contact cards
|
|
document.querySelectorAll('.contact-card').forEach((card, index) => {
|
|
card.style.opacity = '0';
|
|
card.style.transform = 'translateY(30px)';
|
|
card.style.transition = `opacity 0.6s ease ${index * 0.2}s, transform 0.6s ease ${index * 0.2}s`;
|
|
observer.observe(card);
|
|
});
|
|
};
|
|
|
|
// Initialize animations when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', observeElements);
|
|
|
|
// Add hover effects for project cards
|
|
document.querySelectorAll('.project-card').forEach(card => {
|
|
card.addEventListener('mouseenter', function() {
|
|
this.style.transform = 'translateY(-10px) scale(1.02)';
|
|
});
|
|
|
|
card.addEventListener('mouseleave', function() {
|
|
this.style.transform = 'translateY(0) scale(1)';
|
|
});
|
|
});
|
|
|
|
// Typing effect for hero text (optional enhancement)
|
|
const typeWriter = (element, text, speed = 100) => {
|
|
let i = 0;
|
|
element.innerHTML = '';
|
|
const timer = setInterval(() => {
|
|
if (i < text.length) {
|
|
element.innerHTML += text.charAt(i);
|
|
i++;
|
|
} else {
|
|
clearInterval(timer);
|
|
}
|
|
}, speed);
|
|
};
|
|
|
|
// Add some interactive particles (optional)
|
|
const createParticles = () => {
|
|
const particles = document.createElement('div');
|
|
particles.className = 'particles';
|
|
particles.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
`;
|
|
|
|
for (let i = 0; i < 50; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.style.cssText = `
|
|
position: absolute;
|
|
width: 2px;
|
|
height: 2px;
|
|
background: rgba(0, 212, 255, 0.5);
|
|
border-radius: 50%;
|
|
animation: float ${Math.random() * 3 + 2}s ease-in-out infinite;
|
|
left: ${Math.random() * 100}%;
|
|
top: ${Math.random() * 100}%;
|
|
animation-delay: ${Math.random() * 2}s;
|
|
`;
|
|
particles.appendChild(particle);
|
|
}
|
|
|
|
document.body.appendChild(particles);
|
|
};
|
|
|
|
// Initialize particles on hero section
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if (window.innerWidth > 768) {
|
|
// createParticles();
|
|
}
|
|
});
|
|
|
|
// Add active state to navigation links based on scroll position
|
|
const updateActiveNav = () => {
|
|
const sections = document.querySelectorAll('section[id]');
|
|
const navLinks = document.querySelectorAll('.nav-links a[href^="#"]');
|
|
|
|
let current = '';
|
|
|
|
sections.forEach(section => {
|
|
const sectionTop = section.offsetTop;
|
|
const sectionHeight = section.clientHeight;
|
|
if (pageYOffset >= sectionTop - 200) {
|
|
current = section.getAttribute('id');
|
|
}
|
|
});
|
|
|
|
navLinks.forEach(link => {
|
|
link.classList.remove('active');
|
|
if (link.getAttribute('href') === `#${current}`) {
|
|
link.classList.add('active');
|
|
}
|
|
});
|
|
};
|
|
|
|
window.addEventListener('scroll', updateActiveNav);
|
|
|
|
// Add CSS for active nav links
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
.nav-links a.active {
|
|
color: #00d4ff !important;
|
|
}
|
|
|
|
.nav-links a.active::before {
|
|
width: 100% !important;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.nav-links {
|
|
position: fixed;
|
|
top: 70px;
|
|
right: -100%;
|
|
width: 100%;
|
|
height: calc(100vh - 70px);
|
|
background: rgba(10, 10, 10, 0.98);
|
|
flex-direction: column;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
padding-top: 2rem;
|
|
transition: right 0.3s ease;
|
|
}
|
|
|
|
.nav-links.active {
|
|
right: 0;
|
|
}
|
|
|
|
.hamburger.active span:nth-child(1) {
|
|
transform: rotate(-45deg) translate(-5px, 6px);
|
|
}
|
|
|
|
.hamburger.active span:nth-child(2) {
|
|
opacity: 0;
|
|
}
|
|
|
|
.hamburger.active span:nth-child(3) {
|
|
transform: rotate(45deg) translate(-5px, -6px);
|
|
}
|
|
}
|
|
`;
|
|
|
|
document.head.appendChild(style); |