Compare commits

7 Commits

Author SHA1 Message Date
smueller
56f3f90d95 Merge branch 'dev' into ci 2026-06-02 16:23:30 +02:00
smueller
c6b483ca25 fix(it-dienstleistungen): zentriere zielgruppen-karten mit 1:1 layout
stabilisiert das layout der zielgruppen-karten auf der it-dienstleistungen-seite durch seitenlokale overrides ohne auswirkungen auf andere seiten.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 16:22:21 +02:00
smueller
0df5dc9b57 fix(footer): keep footer sections in one desktop row
Adjust footer grid and spacing so all footer sections stay in a single row on desktop while preserving responsive breakpoints for tablets and mobile.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 16:01:00 +02:00
smueller
9c92df4ae4 feat(footer): add andere dienste section with hexadns and hexa-mail
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 08:49:35 +02:00
smueller
e0bcf15121 fix(styles): scope legal breadcrumb colors to legal pages
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 08:36:00 +02:00
smueller
1d4b751316 chore(git): add conventional commit hooks and template
Add commit-msg hook, .gitmessage, and setup script. Ignore .cursor/ in gitignore and lower contact rate limit to 5 per hour.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 11:03:09 +02:00
smueller
186b5ae199 Implement product visibility management: Added configuration for product visibility in navigation and footer, along with helper functions to determine visibility and generate HTML attributes. Updated footer, header, and index files to utilize these new functions, enhancing the user interface by conditionally displaying products based on their visibility settings. 2026-05-29 10:52:56 +02:00
12 changed files with 185 additions and 18 deletions

29
.githooks/commit-msg Normal file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
# Validiert Commit-Messages nach Conventional Commits
# https://www.conventionalcommits.org/
commit_msg_file="$1"
first_line=$(sed '/^#/d;/^$/d' "$commit_msg_file" | head -n 1)
# Merge/Revert von Git erlauben
case "$first_line" in
Merge\ *|Revert\ *)
exit 0
;;
esac
pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\([a-z0-9._-]+\))?!?: .+'
if ! printf '%s\n' "$first_line" | grep -qE "$pattern"; then
echo >&2 "❌ Commit-Message entspricht nicht Conventional Commits."
echo >&2 ""
echo >&2 " Format: type(scope): description"
echo >&2 " Beispiel: feat(products): hide vpc in navigation"
echo >&2 ""
echo >&2 " Erlaubte types: feat, fix, docs, style, refactor, perf, test, build, ci, chore"
echo >&2 " Überspringen: git commit --no-verify"
exit 1
fi
exit 0

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@ build/
# Environment variables
.env
.cursorrules
.cursor/
.cursorrules.txt
.env.local
.env.development.local

16
.gitmessage Normal file
View File

@@ -0,0 +1,16 @@
# Conventional Commits nur die erste nicht-kommentierte Zeile wird verwendet
# Format: type(scope): description
#
# feat Neues Feature
# fix Bugfix
# docs Dokumentation
# style Formatierung (keine Logik)
# refactor Umbau ohne Feature/Fix
# perf Performance
# test Tests
# build Build / Dependencies
# ci CI/CD
# chore Sonstiges
#
# Beispiel (diese Zeile anpassen und Kommentare löschen oder stehen lassen):
# feat(products): hide vpc and vps in navigation

View File

@@ -13,7 +13,7 @@ define('SMTP_TO_EMAIL', 'info@hexahost.de'); // Empfänger-E-Mail für Kon
// Sicherheitseinstellungen
define('ENABLE_CSRF_PROTECTION', true); // CSRF-Schutz aktivieren
define('ENABLE_RATE_LIMITING', true); // Rate-Limiting aktivieren
define('MAX_REQUESTS_PER_HOUR', 10); // Max. Anfragen pro Stunde
define('MAX_REQUESTS_PER_HOUR', 5); // Max. Anfragen pro Stunde
// Spam-Schutz Einstellungen
define('ENABLE_SPAM_PROTECTION', true); // Spam-Schutz aktivieren

View File

@@ -443,10 +443,43 @@ $PRODUCTS['webhosting'] = [
],
];
// Sichtbarkeit in Navigation, Footer und auf der Startseite (Seiten bleiben per URL erreichbar)
$PRODUCT_VISIBILITY = [
'vpc' => false,
'vps' => false,
'mail-gateway' => false,
'webhosting' => true,
];
// ============================================================================
// HILFSFUNKTIONEN
// ============================================================================
/**
* Prüft, ob eine Produktkategorie in der Navigation angezeigt wird
*/
function isProductVisible(string $productId): bool {
global $PRODUCT_VISIBILITY;
return $PRODUCT_VISIBILITY[$productId] ?? true;
}
/**
* HTML hidden-Attribut für ausgeblendete Produktkategorien
*/
function productHiddenAttr(string $productId): string {
return isProductVisible($productId) ? '' : ' hidden';
}
/**
* Aktive Navigationsseiten für sichtbare Produktkategorien
*
* @return string[]
*/
function getVisibleProductPageIds(): array {
global $PRODUCT_VISIBILITY;
return array_keys(array_filter($PRODUCT_VISIBILITY, static fn(bool $visible): bool => $visible));
}
/**
* Alle Produkte abrufen
*/

View File

@@ -15,10 +15,17 @@
<div class="footer-section">
<h4>Produkte</h4>
<ul>
<li><a href="/vpc">Virtual Private Container</a></li>
<li><a href="/vps">Virtual Private Server</a></li>
<li><a href="/mail-gateway">Mail Gateway</a></li>
<li><a href="/webhosting">Webhosting</a></li>
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc">Virtual Private Container</a></li>
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps">Virtual Private Server</a></li>
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway">Mail Gateway</a></li>
<li<?php echo productHiddenAttr('webhosting'); ?>><a href="/webhosting">Webhosting</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Andere Dienste</h4>
<ul>
<li><a href="https://hexadns.de" target="_blank" rel="noopener noreferrer">hexadns.de</a></li>
<li><a href="https://www.hexa-mail.de/" target="_blank" rel="noopener noreferrer">hexa-mail.de</a></li>
</ul>
</div>
<div class="footer-section">

View File

@@ -3,6 +3,8 @@
* Helper functions for HexaHost.de
*/
require_once __DIR__ . '/../config/products-config.php';
// Sichere Session-Konfiguration
if (session_status() === PHP_SESSION_NONE) {
// Session-Cookie-Sicherheit

View File

@@ -59,12 +59,12 @@
<ul class="nav-menu">
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
<li class="nav-dropdown">
<a href="#" class="nav-link <?php echo (in_array($current_page, ['vpc', 'vps', 'mail-gateway', 'webhosting'])) ? 'active' : ''; ?>">Produkte</a>
<a href="#" class="nav-link <?php echo (in_array($current_page, getVisibleProductPageIds(), true)) ? 'active' : ''; ?>">Produkte</a>
<ul class="dropdown-menu">
<li><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
<li><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
<li><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
<li><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps" class="<?php echo ($current_page === 'vps') ? 'active' : ''; ?>">Virtual Private Server</a></li>
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway" class="<?php echo ($current_page === 'mail-gateway') ? 'active' : ''; ?>">Mail Gateway</a></li>
<li<?php echo productHiddenAttr('webhosting'); ?>><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
</ul>
</li>
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>

View File

@@ -16,6 +16,26 @@
margin-top: 2rem;
}
/* IT services page: center target-group cards without affecting other pages */
.it-services-page .values .values-grid {
display: flex !important;
flex-wrap: wrap !important;
justify-content: center !important;
align-items: stretch;
grid-template-columns: none !important;
gap: 1.5rem !important;
}
.it-services-page .values .value-item {
flex: 0 1 320px !important;
max-width: 360px;
aspect-ratio: 1 / 1;
margin: 0 !important;
display: flex;
flex-direction: column;
justify-content: center;
}
/* Legal pages: plain white content with black text */
.legal-hero,
.legal-content {
@@ -45,8 +65,10 @@
.legal-section h3,
.legal-block p,
.legal-block li,
.breadcrumb,
.breadcrumb span {
.legal-hero .breadcrumb,
.legal-hero .breadcrumb span,
.legal-content .breadcrumb,
.legal-content .breadcrumb span {
color: #000000;
}
@@ -81,12 +103,14 @@
}
.legal-block a,
.breadcrumb a {
.legal-hero .breadcrumb a,
.legal-content .breadcrumb a {
color: #0b57d0;
}
.legal-block a:hover,
.breadcrumb a:hover {
.legal-hero .breadcrumb a:hover,
.legal-content .breadcrumb a:hover {
color: #0b57d0;
text-decoration: none;
}
@@ -106,3 +130,41 @@
transition: none !important;
animation: none !important;
}
/* Keep footer sections in one row on desktop */
.footer-content {
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 1.5rem 1.25rem;
align-items: start;
}
.footer-section h4 {
margin-bottom: 0.65rem;
}
.footer-section ul li {
margin-bottom: 0.4rem;
}
@media (max-width: 1100px) {
.footer-content {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 520px) {
.footer-content {
grid-template-columns: 1fr;
}
.it-services-page .values .value-item {
flex-basis: 100%;
max-width: 100%;
}
}

View File

@@ -54,7 +54,7 @@ includeHeader($page_title, $page_description, $current_page);
</p>
</div>
<div class="products-grid">
<div class="product-card glass-card">
<div class="product-card glass-card"<?php echo productHiddenAttr('vpc'); ?>>
<div class="product-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 7V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v3"/>
@@ -74,7 +74,7 @@ includeHeader($page_title, $page_description, $current_page);
</ul>
<a href="/vpc" class="btn btn-primary">Mehr erfahren</a>
</div>
<div class="product-card glass-card">
<div class="product-card glass-card"<?php echo productHiddenAttr('vps'); ?>>
<div class="product-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
@@ -92,7 +92,7 @@ includeHeader($page_title, $page_description, $current_page);
</ul>
<a href="/vps" class="btn btn-primary">Mehr erfahren</a>
</div>
<div class="product-card glass-card">
<div class="product-card glass-card"<?php echo productHiddenAttr('mail-gateway'); ?>>
<div class="product-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>

View File

@@ -10,7 +10,7 @@ $current_page = 'it-dienstleistungen';
includeHeader($page_title, $page_description, $current_page);
?>
<main id="main-content">
<main id="main-content" class="it-services-page">
<!-- Services Hero -->
<section class="about-hero">
<div class="container">

View File

@@ -0,0 +1,17 @@
# Einmal pro Clone ausführen: Commit-Template + Conventional-Commits-Hook aktivieren
$ErrorActionPreference = "Stop"
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
Push-Location $repoRoot
try {
git config --local commit.template .gitmessage
git config --local core.hooksPath .githooks
Write-Host "Git Hooks aktiv:" -ForegroundColor Green
Write-Host " commit.template = .gitmessage"
Write-Host " core.hooksPath = .githooks"
Write-Host ""
Write-Host "Commit-Format: feat(scope): beschreibung"
} finally {
Pop-Location
}