Compare commits
7 Commits
bbc3cbae4e
...
v1.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56f3f90d95 | ||
|
|
c6b483ca25 | ||
|
|
0df5dc9b57 | ||
|
|
9c92df4ae4 | ||
|
|
e0bcf15121 | ||
|
|
1d4b751316 | ||
|
|
186b5ae199 |
29
.githooks/commit-msg
Normal file
29
.githooks/commit-msg
Normal 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
1
.gitignore
vendored
@@ -13,6 +13,7 @@ build/
|
|||||||
# Environment variables
|
# Environment variables
|
||||||
.env
|
.env
|
||||||
.cursorrules
|
.cursorrules
|
||||||
|
.cursor/
|
||||||
.cursorrules.txt
|
.cursorrules.txt
|
||||||
.env.local
|
.env.local
|
||||||
.env.development.local
|
.env.development.local
|
||||||
|
|||||||
16
.gitmessage
Normal file
16
.gitmessage
Normal 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
|
||||||
@@ -13,7 +13,7 @@ define('SMTP_TO_EMAIL', 'info@hexahost.de'); // Empfänger-E-Mail für Kon
|
|||||||
// Sicherheitseinstellungen
|
// Sicherheitseinstellungen
|
||||||
define('ENABLE_CSRF_PROTECTION', true); // CSRF-Schutz aktivieren
|
define('ENABLE_CSRF_PROTECTION', true); // CSRF-Schutz aktivieren
|
||||||
define('ENABLE_RATE_LIMITING', true); // Rate-Limiting 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
|
// Spam-Schutz Einstellungen
|
||||||
define('ENABLE_SPAM_PROTECTION', true); // Spam-Schutz aktivieren
|
define('ENABLE_SPAM_PROTECTION', true); // Spam-Schutz aktivieren
|
||||||
|
|||||||
@@ -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
|
// 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
|
* Alle Produkte abrufen
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,10 +15,17 @@
|
|||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
<h4>Produkte</h4>
|
<h4>Produkte</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/vpc">Virtual Private Container</a></li>
|
<li<?php echo productHiddenAttr('vpc'); ?>><a href="/vpc">Virtual Private Container</a></li>
|
||||||
<li><a href="/vps">Virtual Private Server</a></li>
|
<li<?php echo productHiddenAttr('vps'); ?>><a href="/vps">Virtual Private Server</a></li>
|
||||||
<li><a href="/mail-gateway">Mail Gateway</a></li>
|
<li<?php echo productHiddenAttr('mail-gateway'); ?>><a href="/mail-gateway">Mail Gateway</a></li>
|
||||||
<li><a href="/webhosting">Webhosting</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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* Helper functions for HexaHost.de
|
* Helper functions for HexaHost.de
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../config/products-config.php';
|
||||||
|
|
||||||
// Sichere Session-Konfiguration
|
// Sichere Session-Konfiguration
|
||||||
if (session_status() === PHP_SESSION_NONE) {
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
// Session-Cookie-Sicherheit
|
// Session-Cookie-Sicherheit
|
||||||
|
|||||||
@@ -59,12 +59,12 @@
|
|||||||
<ul class="nav-menu">
|
<ul class="nav-menu">
|
||||||
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
|
<li><a href="/" class="nav-link <?php echo ($current_page === 'home') ? 'active' : ''; ?>">Home</a></li>
|
||||||
<li class="nav-dropdown">
|
<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">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="/vpc" class="<?php echo ($current_page === 'vpc') ? 'active' : ''; ?>">Virtual Private Container</a></li>
|
<li<?php echo productHiddenAttr('vpc'); ?>><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<?php echo productHiddenAttr('vps'); ?>><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<?php echo productHiddenAttr('mail-gateway'); ?>><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('webhosting'); ?>><a href="/webhosting" class="<?php echo ($current_page === 'webhosting') ? 'active' : ''; ?>">Webhosting</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
|
<li><a href="/it-dienstleistungen" class="nav-link <?php echo ($current_page === 'it-dienstleistungen') ? 'active' : ''; ?>">IT-Dienstleistungen</a></li>
|
||||||
|
|||||||
@@ -16,6 +16,26 @@
|
|||||||
margin-top: 2rem;
|
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 pages: plain white content with black text */
|
||||||
.legal-hero,
|
.legal-hero,
|
||||||
.legal-content {
|
.legal-content {
|
||||||
@@ -45,8 +65,10 @@
|
|||||||
.legal-section h3,
|
.legal-section h3,
|
||||||
.legal-block p,
|
.legal-block p,
|
||||||
.legal-block li,
|
.legal-block li,
|
||||||
.breadcrumb,
|
.legal-hero .breadcrumb,
|
||||||
.breadcrumb span {
|
.legal-hero .breadcrumb span,
|
||||||
|
.legal-content .breadcrumb,
|
||||||
|
.legal-content .breadcrumb span {
|
||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +103,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.legal-block a,
|
.legal-block a,
|
||||||
.breadcrumb a {
|
.legal-hero .breadcrumb a,
|
||||||
|
.legal-content .breadcrumb a {
|
||||||
color: #0b57d0;
|
color: #0b57d0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legal-block a:hover,
|
.legal-block a:hover,
|
||||||
.breadcrumb a:hover {
|
.legal-hero .breadcrumb a:hover,
|
||||||
|
.legal-content .breadcrumb a:hover {
|
||||||
color: #0b57d0;
|
color: #0b57d0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@@ -106,3 +130,41 @@
|
|||||||
transition: none !important;
|
transition: none !important;
|
||||||
animation: 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%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ includeHeader($page_title, $page_description, $current_page);
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="products-grid">
|
<div class="products-grid">
|
||||||
<div class="product-card glass-card">
|
<div class="product-card glass-card"<?php echo productHiddenAttr('vpc'); ?>>
|
||||||
<div class="product-icon">
|
<div class="product-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"/>
|
<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>
|
</ul>
|
||||||
<a href="/vpc" class="btn btn-primary">Mehr erfahren</a>
|
<a href="/vpc" class="btn btn-primary">Mehr erfahren</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="product-card glass-card">
|
<div class="product-card glass-card"<?php echo productHiddenAttr('vps'); ?>>
|
||||||
<div class="product-icon">
|
<div class="product-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"/>
|
<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>
|
</ul>
|
||||||
<a href="/vps" class="btn btn-primary">Mehr erfahren</a>
|
<a href="/vps" class="btn btn-primary">Mehr erfahren</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="product-card glass-card">
|
<div class="product-card glass-card"<?php echo productHiddenAttr('mail-gateway'); ?>>
|
||||||
<div class="product-icon">
|
<div class="product-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"/>
|
<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"/>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ $current_page = 'it-dienstleistungen';
|
|||||||
includeHeader($page_title, $page_description, $current_page);
|
includeHeader($page_title, $page_description, $current_page);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content">
|
<main id="main-content" class="it-services-page">
|
||||||
<!-- Services Hero -->
|
<!-- Services Hero -->
|
||||||
<section class="about-hero">
|
<section class="about-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
17
scripts/setup-git-hooks.ps1
Normal file
17
scripts/setup-git-hooks.ps1
Normal 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user