Clean, clickable cards that expand/collapse on click

Independent operation of each card
Smooth animations for better user experience
Mobile-friendly design with appropriate spacing and touch targets
Keyboard accessibility (Escape key support)
Click-outside behavior to close cards
Removed complex checkbox-based implementation in favor of simple JavaScript toggling
This commit is contained in:
ben7sys
2024-11-17 08:51:30 +01:00
parent 317cc79234
commit feeaf093d5
4 changed files with 199 additions and 209 deletions

View File

@@ -1,99 +1,84 @@
Der Default-Theme-Modus wird durch zwei Faktoren bestimmt: # 7SYS Website
Wenn ein Theme bereits im localStorage gespeichert wurde (unter dem Key 'theme'), wird dieses verwendet Eine professionelle Website für IT-Lösungen und digitale Souveränität.
Ansonsten wird das System-Theme des Betriebssystems verwendet:
Wenn das System auf "Dark Mode" eingestellt ist, wird Dark Mode aktiviert
Wenn das System auf "Light Mode" eingestellt ist, wird Light Mode aktiviert
Um den Default-Modus zu ändern, gibt es zwei Möglichkeiten:
Direkt im Code: In der Konstante DEFAULT_THEME in theme.js kann der Wert von 'light' auf 'dark' geändert werden ## Projektbeschreibung
Im Browser: Den localStorage-Eintrag 'theme' auf 'dark' oder 'light' setzen
Das Theme wird beim Laden der Seite sofort initialisiert (durch initThemeEarly()), um ein Flackern zu vermeiden. Danach wird ein Event-Listener eingerichtet, der auf Systemänderungen reagiert und das Theme automatisch anpasst, falls kein benutzerdefiniertes Theme gesetzt wurde.
--- Diese Website dient als digitale Präsenz von 7SYS, einem spezialisierten IT-Dienstleister mit Fokus auf maßgeschneiderte IT-Lösungen und digitale Souveränität. Die Plattform präsentiert das Leistungsportfolio und die Expertise im Bereich IT-Infrastruktur, Systemadministration und Automatisierung.
Successfully implemented the following improvements: ## Hauptfunktionen
Mobile Menu Optimization ✓ - Responsive Single-Page Design
Fixed duplicate script loading issue - Dynamisches Theme-System (Hell/Dunkel)
Improved menu closing behavior after item selection - Interaktive Service-Cards mit detaillierten Informationen
Added smooth scroll for anchor links - Modulare Komponenten-Architektur
Enhanced touch targets for better mobile usability - Optimierte Performance durch CSS-Animationen
Added proper ARIA attributes for accessibility - Barrierefreie Benutzeroberfläche
Implemented fade animation for menu transitions
Responsive Design Improvements ✓
Adjusted menu height to use viewport units
Added proper padding for notched phones
Improved touch target sizes
Enhanced menu item spacing and interaction feedback
Fixed menu scrolling on long content
Performance & Accessibility Enhancements ✓
Added meta description for SEO
Implemented proper aria-expanded states
Added smooth animations with performance considerations
Improved event listener efficiency
Added empty favicon to prevent 404 errors
Code Quality Improvements ✓
Removed duplicate code
Improved event handling
Enhanced error handling
Better organization of CSS media queries
Added proper touch device detection
All changes maintain existing functionality while improving user experience, accessibility, and performance. The mobile menu now behaves more naturally, with proper closing behavior and smooth transitions.
--- ## Technologien
Current Implementation Analysis: - **Frontend:**
- HTML5
- CSS3 (modulare Struktur mit separaten Dateien für bessere Wartbarkeit)
- Vanilla JavaScript (components.js, theme.js)
- Font Awesome Icons
- Google Fonts (Montserrat, Open Sans)
Theme System Architecture - **Architektur:**
CSS Variables (variables.css): ✓ Well-structured light/dark theme variables ✓ Logical separation of common tokens ✓ Clear naming conventions ✓ Efficient use of CSS custom properties - Komponenten-basierte Struktur
Theme Switching (theme.js): - Modulares CSS-System
Robust Implementation: ✓ IIFE for encapsulation ✓ Early initialization prevents FOUC ✓ System theme preference detection ✓ Local storage persistence ✓ Comprehensive error handling - Responsive Design mit CSS Variables
CSS Structure: - Progressive Enhancement
Modular Organization: ✓ Separate files for different concerns ✓ Clean inheritance patterns ✓ Proper cascade management ✓ Efficient variable usage
Integration:
Clean Component Integration: ✓ Theme toggle properly placed in header ✓ Smooth transitions between themes ✓ Proper script/style loading order
Strengths to Preserve:
The modular CSS architecture ## Setup/Installation
The CSS variables-based theming approach
The early theme initialization
The system preference detection
Minor Optimization Suggestions:
Theme Switching Performance: 1. Repository klonen:
```bash
git clone [repository-url]
```
/* Add to variables.css */ 2. Projektverzeichnis öffnen:
:root { ```bash
/* Add GPU acceleration for theme transitions */ cd web7syspub
--theme-transition: color var(--transition-speed) ease, ```
background-color var(--transition-speed) ease;
--gpu-accelerated: translate3d(0, 0, 0);
}
Theme Toggle Accessibility:
/* Add to header.css */ 3. Einen lokalen Webserver starten, zum Beispiel mit Python:
.theme-toggle:focus-visible { ```bash
outline: 2px solid var(--primary); # Python 3
outline-offset: 2px; python -m http.server 8000
border-radius: var(--border-radius); ```
}
Theme Persistence Enhancement:
// Add to theme.js persistTheme function 4. Website im Browser öffnen:
function persistTheme() { ```
try { http://localhost:8000/public
const currentTheme = getCurrentTheme(); ```
localStorage.setItem(THEME_STORAGE_KEY, currentTheme);
// Add theme to body for better SSR support
document.body.dataset.theme = currentTheme;
} catch (error) {
console.warn('Theme persistence error:', error);
}
}
These suggestions maintain the existing architecture while adding:
Improved performance through GPU acceleration ## Projektstruktur
Enhanced accessibility
Better server-side rendering support ```
The current implementation is well-structured and follows best practices. The suggested optimizations are minimal and non-invasive, preserving the existing functionality while making subtle improvements to performance and accessibility. public/
├── components/ # Wiederverwendbare HTML-Komponenten
├── css/ # Modulare CSS-Dateien
│ ├── animations.css
│ ├── base.css
│ ├── components.css
│ ├── layout.css
│ └── variables.css
├── js/ # JavaScript-Module
│ ├── components.js
│ └── theme.js
└── index.html # Hauptseite
```
## Features im Detail
- **Responsive Design:** Optimierte Darstellung auf allen Geräten
- **Themensystem:** Automatische Anpassung an Systemeinstellungen
- **Modulare CSS-Struktur:** Verbesserte Wartbarkeit und Performance
- **Barrierefreiheit:** Semantische HTML-Struktur und ARIA-Attribute
- **Performance:** Optimierte Ladezeiten durch modulare Ressourcen
## Kontakt
- E-Mail: info@7sys.de
- Signal: Verfügbar über Website-Link

View File

@@ -8,10 +8,6 @@
border-color var(--transition-speed) ease; border-color var(--transition-speed) ease;
} }
.card-base:hover {
border-color: var(--primary);
}
/* Mission Vision Cards */ /* Mission Vision Cards */
.mission-vision { .mission-vision {
display: grid; display: grid;
@@ -20,69 +16,56 @@
margin: var(--spacing-xl) 0; margin: var(--spacing-xl) 0;
} }
.mission-vision .tooltip-container { .tooltip-container {
background: var(--bg-card); background: var(--bg-card);
padding: var(--spacing-xl); padding: var(--spacing-xl);
border-radius: var(--border-radius); border-radius: var(--border-radius);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
text-align: center;
position: relative;
cursor: pointer; cursor: pointer;
transition: transform var(--transition-speed) ease, transition: border-color 0.3s ease;
border-color var(--transition-speed) ease;
} }
.mission-vision .tooltip-container:hover { .tooltip-container:hover {
transform: translateY(-5px);
border-color: var(--primary); border-color: var(--primary);
} }
.mission-vision h3 { .tooltip-container h3 {
color: var(--primary); color: var(--primary);
margin-bottom: var(--spacing-md); margin-bottom: var(--spacing-md);
} }
/* Tooltip Styles */ .tooltip-header {
.tooltip-container {
position: relative; position: relative;
padding-right: 30px;
} }
.tooltip { .tooltip-header::after {
visibility: hidden; content: '▼';
position: absolute;
right: 0;
top: 0;
color: var(--primary);
transition: transform 0.3s ease;
}
.tooltip-container.active .tooltip-header::after {
transform: rotate(180deg);
}
.tooltip-content {
max-height: 0;
overflow: hidden;
opacity: 0; opacity: 0;
position: absolute; transition: max-height 0.3s ease-out, opacity 0.3s ease-out, margin 0.3s ease-out;
bottom: 120%; margin-top: 0;
left: 50%;
transform: translateX(-50%);
background: var(--bg-card);
color: var(--text);
padding: var(--spacing-lg);
border-radius: var(--border-radius);
width: 300px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-color);
font-size: 0.9rem;
line-height: 1.5;
text-align: left;
z-index: 100;
transition: opacity var(--transition-speed) ease,
visibility var(--transition-speed) ease;
} }
.tooltip::after { .tooltip-container.active .tooltip-content {
content: ''; max-height: 500px;
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
border-width: 10px 10px 0;
border-style: solid;
border-color: var(--bg-card) transparent transparent transparent;
}
.tooltip-container:hover .tooltip {
visibility: visible;
opacity: 1; opacity: 1;
margin-top: var(--spacing-lg);
padding-top: var(--spacing-lg);
border-top: 1px solid var(--border-color);
} }
/* Service Cards */ /* Service Cards */
@@ -92,14 +75,11 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
margin: var(--spacing-lg) 0; margin: var(--spacing-lg) 0;
transition: transform var(--transition-speed) ease, transition: border-color 0.3s ease;
border-color var(--transition-speed) ease;
} }
.service-card:hover { .service-card:hover {
border-color: var(--primary); border-color: var(--primary);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
transition: all 0.3s ease;
} }
.service-card h3 { .service-card h3 {
@@ -107,6 +87,20 @@
margin-bottom: var(--spacing-md); margin-bottom: var(--spacing-md);
} }
.service-card li {
list-style: none;
margin-bottom: var(--spacing-sm);
position: relative;
padding-left: 1.5em;
}
.service-card li::before {
content: '•';
position: absolute;
left: 0;
color: var(--primary);
}
/* Contact Info Card */ /* Contact Info Card */
.contact-info { .contact-info {
background: var(--bg-card); background: var(--bg-card);
@@ -115,11 +109,11 @@
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
margin: var(--spacing-xl) 0; margin: var(--spacing-xl) 0;
text-align: center; text-align: center;
transition: border-color 0.3s ease;
} }
.contact-info:hover { .contact-info:hover {
border-color: var(--primary); border-color: var(--primary);
transition: all 0.3s ease;
} }
.contact-info p { .contact-info p {
@@ -149,7 +143,6 @@
.contact-link:hover { .contact-link:hover {
color: var(--primary) !important; color: var(--primary) !important;
border-color: var(--primary); border-color: var(--primary);
opacity: 1;
} }
.contact-link i { .contact-link i {
@@ -164,62 +157,13 @@
height: 1.2em; height: 1.2em;
} }
.contact-link:hover .signal-icon {
color: var(--primary);
}
/* Quote Styles */ /* Quote Styles */
.quote {
font-size: 1.2rem;
line-height: 1.6;
padding: var(--spacing-xl);
margin: var(--spacing-xl) 0;
background: var(--bg-card);
border-left: 4px solid var(--primary);
border-radius: 0 var(--border-radius) var(--border-radius) 0;
color: var(--text);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.hero-quote {
font-size: 1.3rem;
line-height: 1.7;
color: var(--text);
max-width: 900px;
margin: var(--spacing-xl) auto;
padding: var(--spacing-md) 0;
position: relative;
font-weight: 300;
opacity: 0.9;
}
.hero-quote::before {
content: '"';
position: absolute;
top: -30px;
left: -10px;
font-size: 3rem;
color: var(--primary);
opacity: 0.3;
}
.welcome-quote { .welcome-quote {
font-size: 1.1rem; font-size: 1.1rem;
text-align: center; text-align: center;
padding: var(--spacing-xl); padding: var(--spacing-xl);
} }
.welcome-quote:before {
content: '°';
position: absolute;
top: -10px;
left: 0;
font-size: 1rem;
color: var(--primary);
opacity: 0.2;
}
/* Logo Sub Text */
.logo-sub { .logo-sub {
display: block; display: block;
text-align: center; text-align: center;
@@ -230,3 +174,19 @@
line-height: 1.4; line-height: 1.4;
font-style: italic; font-style: italic;
} }
/* Mobile Optimizations */
@media (max-width: 768px) {
.tooltip-container {
padding: var(--spacing-lg);
}
.tooltip-content {
font-size: 1rem;
line-height: 1.6;
}
.service-card {
padding: var(--spacing-lg);
}
}

View File

@@ -31,19 +31,21 @@
<span class="logo-sub">Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better. - Edsger Wybe Dijkstra (19302002)</span> <span class="logo-sub">Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better. - Edsger Wybe Dijkstra (19302002)</span>
<div class="mission-vision"> <div class="mission-vision">
<div class="tooltip-container"> <div class="tooltip-container">
<div class="tooltip-header">
<h3>Meine Vision</h3> <h3>Meine Vision</h3>
<p>Digitale Souveränität</p> <p>Digitale Souveränität</p>
<div class="tooltip"> </div>
<div class="tooltip-content">
Ich strebe eine Zukunft an, in der jedes Individuum die volle Kontrolle über ihre digitalen Ressourcen hat. Digitale Souveränität bedeutet für mich, eine sichere, unabhängige und datenschutzkonforme Nutzung moderner Technologien zu ermöglichen, bei der jede Person die Kontrolle über ihre Daten, Zugriffe und IT-Systeme behält, ohne von externen Anbietern oder unsicheren Lösungen abhängig zu sein. Ich strebe eine Zukunft an, in der jedes Individuum die volle Kontrolle über ihre digitalen Ressourcen hat. Digitale Souveränität bedeutet für mich, eine sichere, unabhängige und datenschutzkonforme Nutzung moderner Technologien zu ermöglichen, bei der jede Person die Kontrolle über ihre Daten, Zugriffe und IT-Systeme behält, ohne von externen Anbietern oder unsicheren Lösungen abhängig zu sein.
</div> </div>
</div> </div>
<div class="tooltip-container"> <div class="tooltip-container">
<div class="tooltip-header">
<h3>Meine Mission</h3> <h3>Meine Mission</h3>
<p>Sichere und nachhaltige IT-Lösungen</p> <p>Sichere und nachhaltige IT-Lösungen</p>
<div class="tooltip"> </div>
<div class="tooltip-content">
Meine Mission ist es, Sie auf dem Weg zur digitalen Souveränität kompetent zu begleiten. Meine Mission ist es, Sie auf dem Weg zur digitalen Souveränität kompetent zu begleiten.
</div> </div>
</div> </div>
</div> </div>
@@ -58,7 +60,6 @@
<li>Analyse Ihrer bestehenden Systeme und Situation mit Blick auf die Zukunft</li> <li>Analyse Ihrer bestehenden Systeme und Situation mit Blick auf die Zukunft</li>
<li>Individuelle Lösungen für Ihre Bedürfnisse</li> <li>Individuelle Lösungen für Ihre Bedürfnisse</li>
<li>Zukunftsorientierte Technologieberatung</li> <li>Zukunftsorientierte Technologieberatung</li>
</div> </div>
<div class="service-card"> <div class="service-card">
@@ -79,8 +80,10 @@
<div class="service-card"> <div class="service-card">
<h3>Self-Hosted & Cloud Solutions</h3> <h3>Self-Hosted & Cloud Solutions</h3>
<p> <li>Wartung von Cloud- oder Self-Hosted-Infrastrukturen</li> <p>
<li>Wartung von Cloud- oder Self-Hosted-Infrastrukturen</li>
<li>Planung, Migration und Administration</li> <li>Planung, Migration und Administration</li>
</p>
</div> </div>
<div class="service-card"> <div class="service-card">
@@ -92,8 +95,6 @@
<li>Sicherheit (Firewalls, VPN, Antivirus, Backup)</li> <li>Sicherheit (Firewalls, VPN, Antivirus, Backup)</li>
<li>Automatisierung (Ansible, PowerShell, Bash).</li> <li>Automatisierung (Ansible, PowerShell, Bash).</li>
</div> </div>
</section> </section>
<section id="contact"> <section id="contact">

View File

@@ -24,14 +24,58 @@ document.addEventListener('DOMContentLoaded', function() {
loadComponent('components/footer.html', 'beforeend') loadComponent('components/footer.html', 'beforeend')
]).then(results => { ]).then(results => {
if (results.every(Boolean)) { if (results.every(Boolean)) {
// Dispatch custom event when all components are loaded
document.dispatchEvent(new Event('componentsLoaded')); document.dispatchEvent(new Event('componentsLoaded'));
initializeTooltips();
} }
}).catch(error => { }).catch(error => {
console.warn('Error loading components:', error); console.warn('Error loading components:', error);
}); });
// Initialize header functionality after it's loaded // Initialize tooltip functionality
function initializeTooltips() {
const tooltipContainers = document.querySelectorAll('.tooltip-container');
tooltipContainers.forEach(container => {
container.addEventListener('click', function(e) {
// Prevent click from propagating if clicking inside the content when expanded
if (this.classList.contains('active') &&
e.target.closest('.tooltip-content') &&
!e.target.closest('.tooltip-header')) {
return;
}
// Toggle current container
this.classList.toggle('active');
// Close other containers
tooltipContainers.forEach(otherContainer => {
if (otherContainer !== this && otherContainer.classList.contains('active')) {
otherContainer.classList.remove('active');
}
});
});
});
// Close tooltips when clicking outside
document.addEventListener('click', function(e) {
if (!e.target.closest('.tooltip-container')) {
tooltipContainers.forEach(container => {
container.classList.remove('active');
});
}
});
// Handle escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
tooltipContainers.forEach(container => {
container.classList.remove('active');
});
}
});
}
// Initialize header functionality
function initializeHeader() { function initializeHeader() {
const header = document.querySelector('header'); const header = document.querySelector('header');
if (!header) return; if (!header) return;