From eb9b30bfb56f367627f07d730cb63ea8b2d70ab6 Mon Sep 17 00:00:00 2001 From: Andreas Pieper Date: Sat, 28 Feb 2026 19:10:44 +0000 Subject: [PATCH] multithame --- compose.yml | 2 + html/index.html | 38 ++++-- html/script.js | 68 +++++++++++ html/style.css | 301 +++++++++++++++++++++++++++++++----------------- 4 files changed, 292 insertions(+), 117 deletions(-) create mode 100644 html/script.js diff --git a/compose.yml b/compose.yml index a77fe19..5663a64 100644 --- a/compose.yml +++ b/compose.yml @@ -10,6 +10,8 @@ services: volumes: - ./html/index.html:/usr/share/nginx/html/index.html:ro - ./html/style.css:/usr/share/nginx/html/style.css:ro + - ./html/script.js:/usr/share/nginx/html/script.js:ro + # Wir mounten das Template - Nginx macht daraus beim Start die echte index.html #- ./html/index.html.template:/etc/nginx/templates/index.html.template:ro diff --git a/html/index.html b/html/index.html index dad79d1..78ad0a2 100644 --- a/html/index.html +++ b/html/index.html @@ -11,19 +11,32 @@
@@ -183,5 +196,6 @@ }); }); + \ No newline at end of file diff --git a/html/script.js b/html/script.js new file mode 100644 index 0000000..7d81d86 --- /dev/null +++ b/html/script.js @@ -0,0 +1,68 @@ +/* ========================================== + NAVIGATION & MOBILE MENU + ========================================== */ +function toggleHamburger() { + const navLinks = document.getElementById('navLinks'); + const hamburger = document.querySelector('.hamburger'); + navLinks.classList.toggle('mobile-open'); + hamburger.classList.toggle('active'); +} + +/* ========================================== + THEME SWITCHER LOGIC + ========================================== */ +const themeBtn = document.getElementById('themeBtn'); +const themeDropdown = document.getElementById('themeDropdown'); +const themeButtons = document.querySelectorAll('.theme-dropdown button'); +const htmlEl = document.documentElement; + +// Dropdown öffnen/schließen +if (themeBtn) { + themeBtn.addEventListener('click', (e) => { + e.stopPropagation(); + themeDropdown.classList.toggle('show'); + }); +} + +// Theme auswählen +themeButtons.forEach(btn => { + btn.addEventListener('click', () => { + const theme = btn.getAttribute('data-theme'); + applyTheme(theme); + themeDropdown.classList.remove('show'); + }); +}); + +// Theme anwenden +function applyTheme(theme) { + if (theme === 'auto') { + localStorage.removeItem('theme'); + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + htmlEl.setAttribute('data-theme', prefersDark ? 'dark' : 'light'); + themeBtn.innerHTML = '🌓'; + } else { + htmlEl.setAttribute('data-theme', theme); + localStorage.setItem('theme', theme); + themeBtn.innerHTML = theme === 'dark' ? '🌙' : '☀️'; + } +} + +// Initialisierung beim Laden +document.addEventListener('DOMContentLoaded', () => { + const savedTheme = localStorage.getItem('theme') || 'auto'; + applyTheme(savedTheme); +}); + +// Klick außerhalb schließt Dropdown +window.addEventListener('click', () => { + if (themeDropdown) themeDropdown.classList.remove('show'); +}); + +// Mobile Menü schließen bei Klick auf Link +document.querySelectorAll('.nav-links a').forEach(link => { + link.addEventListener('click', () => { + document.getElementById('navLinks').classList.remove('mobile-open'); + const hamburger = document.querySelector('.hamburger'); + if (hamburger) hamburger.classList.remove('active'); + }); +}); \ No newline at end of file diff --git a/html/style.css b/html/style.css index c3ad49f..7f677e0 100644 --- a/html/style.css +++ b/html/style.css @@ -1,3 +1,58 @@ +/* ========================================== + 0. THEME VARIABLEN (Vollständig Dynamisch) + ========================================== */ +:root { + /* --- Hell-Modus --- */ + --bg-body: #ffffff; + --bg-section-alt: #f8f9fa; + --text-main: #333333; + --text-muted: #666666; + --header-bg: rgba(255, 255, 255, 0.95); + + /* Cards */ + --card-bg: #ffffff; + --card-shadow: rgba(0, 0, 0, 0.08); + --border-color: #eeeeee; + + /* Hero & Akzente */ + --accent: #667eea; + --accent-dark: #764ba2; + --hero-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --hero-text: #ffffff; + --hero-h1-gradient: linear-gradient(45deg, #ffffff, #d1d8ff); + + /* Footer */ + --footer-bg: #1a1a1a; + --footer-text: #bbbbbb; + --footer-link-hover: #ffffff; +} + +[data-theme="dark"] { + /* --- Dunkel-Modus --- */ + --bg-body: #0f111a; + --bg-section-alt: #161925; + --text-main: #e0e6ed; + --text-muted: #94a3b8; + --header-bg: rgba(15, 17, 26, 0.96); + + /* Cards */ + --card-bg: #1c2132; + --card-shadow: rgba(0, 0, 0, 0.3); + --border-color: #2d334a; + + /* Hero & Akzente (Im Darkmode etwas entspannter) */ + --accent: #39348c; + --accent-dark: #3d4593; + --hero-gradient: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%); + --hero-text: #e2e8f0; + --hero-h1-gradient: linear-gradient(45deg, #818cf8, #c084fc); + + /* Footer */ + --footer-bg: #070910; + --footer-text: #64748b; + --footer-link-hover: #818cf8; +} + /* ========================================== 1. RESET & BASIS STILE ========================================== */ @@ -14,21 +69,23 @@ html { body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; - color: #333; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: var(--text-main); + background-color: var(--bg-body); overflow-x: hidden; + transition: all 0.3s ease; } .container { max-width: 1200px; margin: 0 auto; + padding: 0 20px; } /* ========================================== 2. HEADER & NAVIGATION ========================================== */ header { - background: rgba(255, 255, 255, 0.95); + background-color: var(--header-bg); backdrop-filter: blur(10px); box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1); position: fixed; @@ -44,10 +101,18 @@ nav { padding: 1rem 0; } +.nav-right { + display: flex; + align-items: center; + gap: 1.5rem; +} + + + .logo { font-size: 1.5rem; font-weight: bold; - color: #667eea; + color: var(--accent); text-decoration: none; } @@ -58,32 +123,72 @@ nav { } .nav-links a { - color: #333; + color: var(--text-main); text-decoration: none; font-weight: 500; - transition: color 0.3s; } .nav-links a:hover { - color: #667eea; + color: var(--accent); +} + +/* Theme Switcher */ +.theme-switch { position: relative; } +.theme-btn { + background: none; + border: 1px solid var(--border-color); + border-radius: 50%; + width: 40px; + height: 40px; + cursor: pointer; + font-size: 1.2rem; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-main); +} + +.theme-dropdown { + position: absolute; + top: 120%; + right: 0; + background-color: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 8px; + box-shadow: 0 5px 15px var(--card-shadow); + display: none; + flex-direction: column; + min-width: 130px; + z-index: 2000; + overflow: hidden; +} + +.theme-dropdown.show { display: flex; } +.theme-dropdown button { + background: none; + border: none; + padding: 12px 15px; + text-align: left; + cursor: pointer; + color: var(--text-main); +} +.theme-dropdown button:hover { + background-color: var(--accent); + color: white; } -/* Hamburger Icon (Standard versteckt) */ .hamburger { display: none; flex-direction: column; - cursor: pointer; gap: 5px; - z-index: 1100; + cursor: pointer; } - .hamburger span { display: block; width: 25px; height: 3px; - background-color: #667eea; + background-color: var(--accent); border-radius: 3px; - transition: all 0.3s ease; } /* ========================================== @@ -95,18 +200,16 @@ nav { align-items: center; justify-content: center; text-align: center; - color: rgb(38, 38, 38); - padding-top: 80px; -} - -.hero-content { - max-width: 800px; + background: var(--hero-gradient); + color: var(--hero-text); + padding: 80px 20px; + transition: background 0.5s ease; } .hero h1 { font-size: 3.5rem; margin-bottom: 1rem; - background: linear-gradient(45deg, #091e7a, #667eea); + background: var(--hero-h1-gradient); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -120,67 +223,69 @@ nav { } /* ========================================== - 4. BUTTONS & CTAs + 4. BUTTONS ========================================== */ .cta-button { display: inline-block; - background: #667eea; + background-color: var(--accent); color: white; padding: 1rem 2rem; text-decoration: none; border-radius: 50px; font-weight: bold; - transition: transform 0.3s, box-shadow 0.3s; - box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); + transition: all 0.3s ease; } .cta-button:hover { transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6); + background-color: var(--accent-dark); } .demo-buttons { display: flex; gap: 1rem; justify-content: center; + padding: 1rem; flex-wrap: wrap; - padding: 0.5rem 3rem; + margin-top: 2rem; } .demo-button { - background: #667eea; + background-color: var(--accent); color: white; - padding: 0.5rem 1.2rem; + padding: 0.6rem 1.4rem; text-decoration: none; border-radius: 25px; - font-weight: 500; - transition: background 0.3s, transform 0.3s; + transition: all 0.3s ease; } .demo-button:hover { - background: #5a6fd8; + background-color: var(--accent-dark); transform: translateY(-2px); } /* ========================================== - 5. SECTIONS & CONTENT CARDS + 5. SECTIONS & CARDS + ========================================== */ +/* ========================================== + 5. SECTIONS & CARDS ========================================== */ section { - /* KEIN margin nutzen, nur padding! */ - background: white; + padding: 80px 0; + background-color: var(--bg-body); } .section-dark { - background: #f8f9fa; /* Das Grau füllt jetzt die komplette Breite/Höhe aus */ + background-color: var(--bg-section-alt); } h2 { text-align: center; font-size: 2.5rem; - padding: 1.5rem; - /*margin-top: 1.5rem;*/ - margin-bottom: 0.5rem; - color: #333; + padding: 2.5rem 0; + margin-bottom: -2rem; + color: var(--text-main); } .text { @@ -189,118 +294,104 @@ h2 { text-align: center; font-size: 1.1rem; line-height: 1.8; + color: var(--text-muted); } +/* Hier ist die wichtige Änderung für das Nebeneinanderstehen */ .projects, .tech-features { display: grid; + /* Erzeugt so viele Spalten wie nebeneinander passen (mind. 300px breit) */ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 2.5rem; - /*margin-top: 3rem; - margin-bottom: 2rem;*/ + gap: 2rem; + margin-top: 3rem; } .project-card, .tech-card { - background: white; + background-color: var(--card-bg); border-radius: 15px; padding: 2.5rem; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); - transition: transform 0.3s, box-shadow 0.3s; + box-shadow: 0 10px 30px var(--card-shadow); + border: 1px solid var(--border-color); text-align: center; -} - -.project-card:hover { - transform: translateY(-5px); - box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15); + transition: transform 0.3s ease, background-color 0.3s; + + /* Flexbox Korrektur */ + display: flex; + flex-direction: column; + justify-content: flex-start; /* Schiebt alles nach oben */ + height: 100%; /* Sorgt dafür, dass alle Karten in einer Reihe gleich hoch sind */ } .project-card h3, .tech-card h3 { - color: #667eea; - margin-bottom: 1.2rem; + color: var(--accent); + margin-bottom: 1.2rem; /* Abstand zwischen Überschrift und Text */ font-size: 1.5rem; } .project-card p, .tech-card p { - color: #666; + color: var(--text-muted); line-height: 1.6; + margin-bottom: 0; /* Verhindert unnötigen Platz nach unten */ } +.project-card:hover, .tech-card:hover { + transform: translateY(-5px); +} + + /* ========================================== - 6. FOOTER & SEPARATOR + 6. FOOTER ========================================== */ -.separator-line { - width: 100%; - height: 1px; - background: #eee; -} - footer { - background: #222; - color: white; + background-color: var(--footer-bg); + color: var(--footer-text); text-align: center; - padding: 80px 0; /* Großer Innenabstand oben sorgt für Distanz */ - margin: 0; /* Sicherstellen, dass kein Außenabstand Lila zeigt */ -} - -.separator-line { - display: none; /* Wir brauchen sie nicht mehr, da die Farben direkt aneinanderschließen */ -} - -.footer-links { - display: flex; - justify-content: center; - gap: 2rem; - margin-bottom: 2rem; - flex-wrap: wrap; + padding: 60px 0; + transition: background 0.3s ease; } .footer-links a { - color: #bbb; + color: var(--footer-text); text-decoration: none; - transition: color 0.3s; + margin: 0 1rem; } .footer-links a:hover { - color: white; -} - -footer p:last-child { - margin-top: 2rem; - font-size: 0.9rem; - color: #777; + color: var(--footer-link-hover); } /* ========================================== 7. RESPONSIVENESS ========================================== */ -@media (max-width: 768px) { - section { - padding: 4rem 0; - } - +@media (max-width: 850px) { .hamburger { display: flex; } - + .nav-links { + position: absolute; + top: 100%; left: 0; width: 100%; + background-color: var(--header-bg); + flex-direction: column; + max-height: 0; + overflow: hidden; + transition: max-height 0.4s ease; + } + .nav-links.mobile-open { max-height: 500px; } + .nav-links li { border-bottom: 1px solid var(--border-color); } + .nav-links a { padding: 1.2rem; display: block; } + .hero h1 { font-size: 2.2rem; } .nav-links { position: absolute; top: 100%; left: 0; width: 100%; - background: rgba(255, 255, 255, 0.98); + background-color: var(--header-bg); + display: flex; flex-direction: column; - gap: 0; max-height: 0; overflow: hidden; transition: max-height 0.4s ease-in-out; - box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); + box-shadow: 0 10px 15px var(--card-shadow); + + /* Nav-Links müssen über dem Content, aber unter dem Dropdown sein */ + z-index: 999; } - - .nav-links.mobile-open { max-height: 500px; } - .nav-links li { border-bottom: 1px solid #eee; } - .nav-links a { padding: 1.2rem; display: block; } - - .hamburger.active span:nth-child(1) { transform: translateY(8px) rotate(45deg); } - .hamburger.active span:nth-child(2) { opacity: 0; } - .hamburger.active span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); } - - .hero h1 { font-size: 2.2rem; } - .hero p { font-size: 1.1rem; } } \ No newline at end of file