Compare commits

28 Commits

Author SHA1 Message Date
smueller
b113bdeaa2 Implement strict hover effect removal for legal text: Added CSS rules to ensure no hover, focus, or active effects on legal hero and content sections, enhancing readability and user experience. 2026-05-27 14:45:10 +02:00
smueller
5d2be60dfa Refine legal page styles in custom CSS: Updated hover effects for glass cards and links to enhance user interaction and visual consistency. Improved text decoration on hover for legal blocks and breadcrumbs. 2026-05-27 14:43:46 +02:00
smueller
62d0076799 Enhance legal page styles in custom CSS: Added new styles for legal hero and content sections, adjusted margins and padding, and modified section hover effects for improved visual consistency and readability. 2026-05-27 14:42:32 +02:00
smueller
e920fdfc8e Add legal styling to custom CSS: Implemented styles for legal pages, including background and text color adjustments, section borders, and hover effects to enhance readability and visual consistency. 2026-05-27 14:05:55 +02:00
smueller
5d953fda7b Enhance product configuration and ordering functionality: Updated products-config.php to include shop URLs for various packages, improving the central management of product information. Added new functions for generating order URLs based on product and package selections. Updated public pages for VPC, VPS, Mail Gateway, and Webhosting to utilize the new order URL functionality, enhancing user experience and streamlining the ordering process. 2026-05-27 13:51:54 +02:00
smueller
6ca4786955 Remove legacy build scripts: Deleted outdated PowerShell and Bash scripts for publishing and running builds, streamlining the project structure and eliminating redundancy. These scripts were previously used for production builds and have been replaced by more efficient methods. 2026-05-27 13:24:20 +02:00
smueller
b9bd339607 Refactor configuration files for HexaHost.de: Updated mail and product configuration files to improve clarity and maintainability. Added deprecation notices in the old config file, migrated email handling to a new structure, and enhanced documentation for better understanding. Improved header comments across various public pages for better organization and readability. 2026-05-27 13:22:46 +02:00
smueller
b893272d64 Merge branch 'main' of https://git.hexahost.dev/smueller/HexaHost-Frontend 2026-05-27 13:14:23 +02:00
smueller
3dd707ab93 chore(release): production build 2026-05-27 13:05 2026-05-27 13:05:22 +02:00
smueller
cc1a48943a Merge branch 'main' of https://git.hexahost.dev/smueller/HexaHost-Frontend 2026-05-27 12:39:56 +02:00
smueller
dfc781f3ed chore(release): production build 2026-05-27 12:38 2026-05-27 12:38:30 +02:00
smueller
d0e5baa443 Revert main to dev deployment model: remove bootstrap and use ../backend/ paths
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 14:10:21 +02:00
smueller
8afba16905 Enhance configuration management: Updated README.md with Windows sync instructions, refactored backend configuration files to improve loading logic, and ensured consistent function definitions. Improved error handling in bootstrap.php for better user feedback during application startup. 2026-05-22 14:07:27 +02:00
smueller
96a5977283 Refactor configuration loading: Updated multiple public PHP files to require a new bootstrap file for configuration management. Adjusted paths for product configuration to enhance maintainability and consistency across the application. 2026-05-22 13:58:30 +02:00
TheOnlyMace
ec8686761c Enhance IT services section: Updated index.php to include new CSS classes for the IT services section, improving layout and responsiveness. Added styles for a 3x2 grid layout in custom.css, ensuring better presentation across different screen sizes. 2026-04-09 21:31:32 +02:00
TheOnlyMace
d3da589a1d Add animated gradient background for "Beliebt" badge: Introduced a new CSS class for the featured badge with a linear gradient and animation effects. Added media query to disable animation for users preferring reduced motion, enhancing accessibility. 2026-04-09 21:26:29 +02:00
TheOnlyMace
b6e268855e Update CSS styles: Enhanced style.css with refined layout and improved responsiveness. Adjusted CSS variables for better visual consistency and user experience across the application. 2026-04-09 21:17:11 +02:00
TheOnlyMace
d02377c735 Update CSS styles: Refined style.css to enhance layout consistency and responsiveness. Adjusted CSS variables for improved visual appeal and user experience across the application. 2026-04-09 21:13:08 +02:00
TheOnlyMace
d62d6b576d Refactor CSS styles: Updated style.css to improve layout consistency and responsiveness. Adjusted CSS variables for better visual appeal and user experience across the application. 2026-04-09 21:12:31 +02:00
TheOnlyMace
2c0138f55d Update CSS styles: Refactored and optimized the style.css file to enhance layout and visual consistency across the application. Adjusted various CSS variables and properties for improved responsiveness and user experience. 2026-04-09 21:11:25 +02:00
TheOnlyMace
2074707c9d Add product visibility control: Introduced a mechanism to hide specific products ('vpc', 'vps') from the shop. Updated relevant templates to conditionally display these products based on visibility status, enhancing user experience and product management. 2026-04-09 21:07:48 +02:00
TheOnlyMace
55f9fdd957 Update products configuration: Removed outdated features from 'mail-gateway' offerings, including email archiving and calendar & contacts, to streamline product details and improve clarity. 2026-04-09 21:04:21 +02:00
TheOnlyMace
ab81d1c49f Update webhosting configuration: Adjusted price for 'Webhosting Professional' from '9,99' to '13,99' to reflect updated pricing strategy. 2026-04-09 21:02:52 +02:00
TheOnlyMace
b40ad53d9c Update webhosting configuration: Changed 'Domains Inkl.' value from '3' to '1' to accurately reflect product offerings and specifications. 2026-04-09 21:01:59 +02:00
TheOnlyMace
e5402189ea Update webhosting configuration: Specify database type in product details by changing 'Datenbanken' value to '20 MySQL' for improved clarity in offerings. 2026-04-09 21:01:10 +02:00
TheOnlyMace
e544720900 Update webhosting configuration and content: Enhanced product descriptions, pricing, and specifications for webhosting packages. Transitioned from cPanel/Webmin to Plesk Webhosting, and updated PHP version to 8.4. Improved clarity and appeal of offerings in both backend configuration and public-facing web page. 2026-04-09 20:59:37 +02:00
a5bba86db0 Merge pull request 'Enhance Content Security Policy in .htaccess: Updated img-src and connect-src directives to include Google Tag Manager and additional Google services, improving security while ensuring compatibility with analytics tools.' (#4) from dev into main
Reviewed-on: smueller/HexaHost-Frontend#4
2026-04-09 13:50:00 +00:00
d34dbbb079 Merge pull request 'Update .htaccess for enhanced security and Google Tag Assistant compatibility: Removed X-Frame-Options header and adjusted Content Security Policy to allow Google Tag Manager and Google Analytics, ensuring compliance with security standards while maint…' (#3) from dev into main
Reviewed-on: smueller/HexaHost-Frontend#3
2026-04-09 13:46:46 +00:00
11 changed files with 152 additions and 537 deletions

View File

@@ -2,7 +2,8 @@
/** /**
* HexaHost.de Produkt-Konfiguration * HexaHost.de Produkt-Konfiguration
* *
* Hier können Sie alle Preise und Produktinformationen zentral verwalten. * Hier können Sie alle Preise, Shop-Links und Produktinformationen zentral verwalten.
* Pro Paket: shop_url (WHMCS/Warenkorb-Link, z. B. https://shop.hexahost.de/cart.php?a=add&pid=123)
* Nach Änderungen: npm run build && npm run deploy * Nach Änderungen: npm run build && npm run deploy
* *
* Verwendung in PHP-Seiten: * Verwendung in PHP-Seiten:
@@ -30,6 +31,7 @@ $PRODUCTS['vpc'] = [
'starter' => [ 'starter' => [
'name' => 'VPC Starter', 'name' => 'VPC Starter',
'price' => '4,99', 'price' => '4,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '1 vCore'], ['label' => 'CPU Kerne', 'value' => '1 vCore'],
@@ -49,6 +51,7 @@ $PRODUCTS['vpc'] = [
'business' => [ 'business' => [
'name' => 'VPC Business', 'name' => 'VPC Business',
'price' => '9,99', 'price' => '9,99',
'shop_url' => '',
'featured' => true, 'featured' => true,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '2 vCores'], ['label' => 'CPU Kerne', 'value' => '2 vCores'],
@@ -69,6 +72,7 @@ $PRODUCTS['vpc'] = [
'professional' => [ 'professional' => [
'name' => 'VPC Professional', 'name' => 'VPC Professional',
'price' => '19,99', 'price' => '19,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '4 vCores'], ['label' => 'CPU Kerne', 'value' => '4 vCores'],
@@ -90,6 +94,7 @@ $PRODUCTS['vpc'] = [
'enterprise' => [ 'enterprise' => [
'name' => 'VPC Enterprise', 'name' => 'VPC Enterprise',
'price' => '39,99', 'price' => '39,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '8 vCores'], ['label' => 'CPU Kerne', 'value' => '8 vCores'],
@@ -132,6 +137,7 @@ $PRODUCTS['vps'] = [
'starter' => [ 'starter' => [
'name' => 'VPS Starter', 'name' => 'VPS Starter',
'price' => '9,99', 'price' => '9,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '1 vCore'], ['label' => 'CPU Kerne', 'value' => '1 vCore'],
@@ -151,6 +157,7 @@ $PRODUCTS['vps'] = [
'business' => [ 'business' => [
'name' => 'VPS Business', 'name' => 'VPS Business',
'price' => '19,99', 'price' => '19,99',
'shop_url' => '',
'featured' => true, 'featured' => true,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '2 vCores'], ['label' => 'CPU Kerne', 'value' => '2 vCores'],
@@ -171,6 +178,7 @@ $PRODUCTS['vps'] = [
'professional' => [ 'professional' => [
'name' => 'VPS Professional', 'name' => 'VPS Professional',
'price' => '39,99', 'price' => '39,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '4 vCores'], ['label' => 'CPU Kerne', 'value' => '4 vCores'],
@@ -192,6 +200,7 @@ $PRODUCTS['vps'] = [
'enterprise' => [ 'enterprise' => [
'name' => 'VPS Enterprise', 'name' => 'VPS Enterprise',
'price' => '79,99', 'price' => '79,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'CPU Kerne', 'value' => '8 vCores'], ['label' => 'CPU Kerne', 'value' => '8 vCores'],
@@ -234,6 +243,7 @@ $PRODUCTS['mail-gateway'] = [
'starter' => [ 'starter' => [
'name' => 'Mail Starter', 'name' => 'Mail Starter',
'price' => '4,99', 'price' => '4,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'Postfächer', 'value' => '5'], ['label' => 'Postfächer', 'value' => '5'],
@@ -252,6 +262,7 @@ $PRODUCTS['mail-gateway'] = [
'business' => [ 'business' => [
'name' => 'Mail Business', 'name' => 'Mail Business',
'price' => '14,99', 'price' => '14,99',
'shop_url' => '',
'featured' => true, 'featured' => true,
'specs' => [ 'specs' => [
['label' => 'Postfächer', 'value' => '25'], ['label' => 'Postfächer', 'value' => '25'],
@@ -272,6 +283,7 @@ $PRODUCTS['mail-gateway'] = [
'professional' => [ 'professional' => [
'name' => 'Mail Professional', 'name' => 'Mail Professional',
'price' => '29,99', 'price' => '29,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'Postfächer', 'value' => '100'], ['label' => 'Postfächer', 'value' => '100'],
@@ -293,6 +305,7 @@ $PRODUCTS['mail-gateway'] = [
'enterprise' => [ 'enterprise' => [
'name' => 'Mail Enterprise', 'name' => 'Mail Enterprise',
'price' => '59,99', 'price' => '59,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'Postfächer', 'value' => 'Unbegrenzt'], ['label' => 'Postfächer', 'value' => 'Unbegrenzt'],
@@ -336,6 +349,7 @@ $PRODUCTS['webhosting'] = [
'starter' => [ 'starter' => [
'name' => 'Webhosting Starter', 'name' => 'Webhosting Starter',
'price' => '4,99', 'price' => '4,99',
'shop_url' => 'https://shop.hexahost.de/store/webserver/webhosting-starter',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'Webspace', 'value' => '10 GB'], ['label' => 'Webspace', 'value' => '10 GB'],
@@ -358,6 +372,7 @@ $PRODUCTS['webhosting'] = [
'business' => [ 'business' => [
'name' => 'Webhosting Business', 'name' => 'Webhosting Business',
'price' => '7,99', 'price' => '7,99',
'shop_url' => 'https://shop.hexahost.de/store/webserver/webhosting-business',
'featured' => true, 'featured' => true,
'specs' => [ 'specs' => [
['label' => 'Webspace', 'value' => '30 GB'], ['label' => 'Webspace', 'value' => '30 GB'],
@@ -380,6 +395,7 @@ $PRODUCTS['webhosting'] = [
'professional' => [ 'professional' => [
'name' => 'Webhosting Professional', 'name' => 'Webhosting Professional',
'price' => '9,99', 'price' => '9,99',
'shop_url' => 'https://shop.hexahost.de/store/webserver/webhosting-professional',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'Webspace', 'value' => '50 GB'], ['label' => 'Webspace', 'value' => '50 GB'],
@@ -402,6 +418,7 @@ $PRODUCTS['webhosting'] = [
'enterprise' => [ 'enterprise' => [
'name' => 'Webhosting Enterprise', 'name' => 'Webhosting Enterprise',
'price' => '29,99', 'price' => '29,99',
'shop_url' => '',
'featured' => false, 'featured' => false,
'specs' => [ 'specs' => [
['label' => 'Webspace', 'value' => '200 GB'], ['label' => 'Webspace', 'value' => '200 GB'],
@@ -485,6 +502,38 @@ function formatPrice($price, $withCurrency = true) {
return $withCurrency ? $price . '€' : $price; return $withCurrency ? $price . '€' : $price;
} }
/**
* Bestell-Link für ein Paket (Online-Shop oder Kontaktformular)
*/
function getOrderUrl($productId, $packageId) {
$package = getPackage($productId, $packageId);
if ($package && !empty($package['shop_url'])) {
return $package['shop_url'];
}
return sprintf('contact.php?package=%s-%s', $productId, $packageId);
}
/**
* Bestell-Link für CTA (beliebtes Paket oder erstes Paket)
*/
function getProductOrderUrl($productId) {
$packages = getProductPackages($productId);
foreach ($packages as $packageId => $package) {
if (!empty($package['featured'])) {
return getOrderUrl($productId, $packageId);
}
}
$firstPackageId = array_key_first($packages);
if ($firstPackageId !== null) {
return getOrderUrl($productId, $firstPackageId);
}
return sprintf('contact.php?product=%s', $productId);
}
/** /**
* Generiert HTML für eine Paket-Karte * Generiert HTML für eine Paket-Karte
*/ */
@@ -522,7 +571,7 @@ function renderPackageCard($productId, $packageId, $package) {
<div class="package-features"> <div class="package-features">
%s %s
</div> </div>
<a href="contact.php?package=%s-%s" class="btn btn-primary">Jetzt bestellen</a> <a href="%s" class="btn btn-primary">Jetzt bestellen</a>
</div>', </div>',
$featuredClass, $featuredClass,
$featuredBadge, $featuredBadge,
@@ -530,8 +579,7 @@ function renderPackageCard($productId, $packageId, $package) {
$package['price'], $package['price'],
$specsHtml, $specsHtml,
$featuresHtml, $featuresHtml,
$productId, htmlspecialchars(getOrderUrl($productId, $packageId), ENT_QUOTES, 'UTF-8')
$packageId
); );
} }

View File

@@ -15,3 +15,94 @@
justify-content: center; justify-content: center;
margin-top: 2rem; margin-top: 2rem;
} }
/* Legal pages: plain white content with black text */
.legal-hero,
.legal-content {
background: #ffffff;
color: #000000;
}
.legal-hero {
margin-top: 70px;
padding: 2rem 0 1.5rem;
border-bottom: 1px solid #e5e5e5;
}
.legal-content {
padding-top: 2rem;
}
.legal-hero-title {
background: none;
-webkit-text-fill-color: #000000;
color: #000000;
margin-bottom: 0.5rem;
}
.legal-hero-description,
.legal-section h2,
.legal-section h3,
.legal-block p,
.legal-block li,
.breadcrumb,
.breadcrumb span {
color: #000000;
}
.legal-section,
.legal-section.glass-card {
background: transparent;
border: none;
box-shadow: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border-radius: 0;
padding: 0;
}
.legal-section:hover,
.legal-section.glass-card:hover {
transform: none;
box-shadow: none;
border: none;
background: transparent;
}
.legal-content .glass-card:hover {
transform: none;
box-shadow: none;
}
.legal-section h2 {
border-bottom: 1px solid #e5e5e5;
padding-bottom: 0.5rem;
margin-bottom: 0.8rem;
}
.legal-block a,
.breadcrumb a {
color: #0b57d0;
}
.legal-block a:hover,
.breadcrumb a:hover {
color: #0b57d0;
text-decoration: none;
}
/* Ensure absolutely no hover effects on legal text/content */
.legal-hero *,
.legal-content *,
.legal-hero *:hover,
.legal-content *:hover,
.legal-hero *:focus,
.legal-content *:focus,
.legal-hero *:active,
.legal-content *:active {
transform: none !important;
box-shadow: none !important;
text-shadow: none !important;
transition: none !important;
animation: none !important;
}

View File

@@ -166,8 +166,8 @@ includeHeader($page_title, $page_description, $current_page);
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2> <h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p> <p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
<div class="cta-actions"> <div class="cta-actions">
<a href="contact.php?product=mail-gateway" class="btn btn-primary">Jetzt bestellen</a> <a href="<?php echo htmlspecialchars(getProductOrderUrl('mail-gateway'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a> <a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -166,8 +166,8 @@ includeHeader($page_title, $page_description, $current_page);
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2> <h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p> <p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
<div class="cta-actions"> <div class="cta-actions">
<a href="contact.php?product=vpc" class="btn btn-primary">Jetzt bestellen</a> <a href="<?php echo htmlspecialchars(getProductOrderUrl('vpc'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a> <a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -171,8 +171,8 @@ includeHeader($page_title, $page_description, $current_page);
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2> <h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p> <p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
<div class="cta-actions"> <div class="cta-actions">
<a href="contact.php?product=vps" class="btn btn-primary">Jetzt bestellen</a> <a href="<?php echo htmlspecialchars(getProductOrderUrl('vps'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a> <a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -95,7 +95,7 @@ includeHeader($page_title, $page_description, $current_page);
<polyline points="10,9 9,9 8,9"/> <polyline points="10,9 9,9 8,9"/>
</svg> </svg>
</div> </div>
<h3>cPanel/Webmin</h3> <h3>Plesk</h3>
<p>Benutzerfreundliche Verwaltungsoberfläche für einfache Website-Verwaltung und E-Mail-Konfiguration.</p> <p>Benutzerfreundliche Verwaltungsoberfläche für einfache Website-Verwaltung und E-Mail-Konfiguration.</p>
</div> </div>
<div class="detail-card glass-card"> <div class="detail-card glass-card">
@@ -170,8 +170,8 @@ includeHeader($page_title, $page_description, $current_page);
<h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2> <h2><?php echo htmlspecialchars($product['cta_title'] ?? ('Bereit für ' . $product['name'] . '?')); ?></h2>
<p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p> <p><?php echo htmlspecialchars($product['cta_description'] ?? ('Starten Sie noch heute mit ' . $product['name'])); ?></p>
<div class="cta-actions"> <div class="cta-actions">
<a href="contact.php?product=webhosting" class="btn btn-primary">Jetzt bestellen</a> <a href="<?php echo htmlspecialchars(getProductOrderUrl('webhosting'), ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-primary">Jetzt bestellen</a>
<a href="/contact" class="btn btn-secondary">Beratung anfordern</a> <a href="contact.php" class="btn btn-secondary">Beratung anfordern</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,185 +0,0 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Erstellt einen Production-Build und veroeffentlicht ihn auf den Branch main.
.DESCRIPTION
1. Wechselt auf main und setzt ihn auf den Stand von dev
2. Entfernt Kommentare, minifiziert CSS, obfuskiert JavaScript
3. Committet und pusht main (optional)
4. Wechselt zurueck auf dev (Quellcode bleibt unveraendert)
.PARAMETER Push
Pusht main nach origin (Standard: nur lokaler Commit)
.PARAMETER DryRun
Fuehrt Git-Schritte nur simuliert aus (Build wird trotzdem erstellt)
.PARAMETER AllowDirty
Erlaubt uncommittete Aenderungen
.PARAMETER Message
Commit-Nachricht fuer den Production-Build
.EXAMPLE
.\scripts\publish-to-main.ps1
.EXAMPLE
.\scripts\publish-to-main.ps1 -Push
#>
[CmdletBinding()]
param(
[switch]$Push,
[switch]$DryRun,
[switch]$AllowDirty,
[string]$Message = ""
)
$ErrorActionPreference = "Stop"
$Root = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$BuildDir = Join-Path $Root "scripts\build"
$OriginalBranch = ""
function Write-Step([string]$Text) {
Write-Host ""
Write-Host "==> $Text" -ForegroundColor Cyan
}
function Ensure-GitClean {
$status = git -C $Root status --porcelain
if ($status) {
throw "Uncommittete Aenderungen im Repository. Bitte zuerst committen oder stashen."
}
}
function Resolve-NodeTool([string]$ToolName) {
$command = Get-Command $ToolName -ErrorAction SilentlyContinue
if ($command) {
return $command.Source
}
$candidates = @(
(Join-Path $env:ProgramFiles "nodejs\$ToolName.cmd"),
(Join-Path ${env:ProgramFiles(x86)} "nodejs\$ToolName.cmd"),
(Join-Path $env:LOCALAPPDATA "Programs\nodejs\$ToolName.cmd"),
"c:\Program Files\cursor\resources\app\resources\helpers\node.exe"
)
foreach ($candidate in $candidates) {
if ($ToolName -eq "node" -and (Test-Path $candidate)) {
return $candidate
}
if ($ToolName -ne "node" -and (Test-Path $candidate)) {
return $candidate
}
}
return $null
}
function Ensure-Node {
$script:NodeExe = Resolve-NodeTool "node"
$script:NpmExe = Resolve-NodeTool "npm"
if (-not $script:NodeExe) {
throw "Node.js ist nicht installiert. Bitte Node.js 18+ installieren: https://nodejs.org/"
}
if (-not $script:NpmExe) {
throw "npm wurde nicht gefunden. Bitte Node.js inkl. npm installieren und PATH setzen."
}
}
try {
Set-Location $Root
Ensure-Node
if (-not $AllowDirty) {
Ensure-GitClean
} else {
Write-Warning "AllowDirty aktiv - uncommittete Aenderungen werden mit veroeffentlicht."
}
$OriginalBranch = (git branch --show-current).Trim()
if ($OriginalBranch -ne "dev") {
Write-Warning "Empfohlen: Auf Branch 'dev' starten (aktuell: $OriginalBranch)"
}
if ([string]::IsNullOrWhiteSpace($Message)) {
$Message = "chore(release): production build $(Get-Date -Format 'yyyy-MM-dd HH:mm')"
}
Write-Step "Installiere Build-Abhaengigkeiten"
Set-Location $BuildDir
if (-not $DryRun) {
& $NpmExe ci --no-fund --no-audit
if ($LASTEXITCODE -ne 0) { throw "npm ci fehlgeschlagen" }
}
Write-Step "Wechsle auf main und synchronisiere mit dev"
Set-Location $Root
if ($DryRun) {
Write-Host '[DryRun] git checkout main'
Write-Host '[DryRun] git reset --hard dev'
} else {
git checkout main
git reset --hard dev
}
Write-Step "Production-Build (Kommentare entfernen, JS obfuscaten)"
Set-Location $BuildDir
if ($DryRun) {
Write-Host '[DryRun] npm run build:in-place'
} else {
& $NpmExe run build:in-place
if ($LASTEXITCODE -ne 0) { throw "Production-Build fehlgeschlagen" }
}
Write-Step "Production-Build committen"
Set-Location $Root
if ($DryRun) {
Write-Host '[DryRun] git add -A'
Write-Host ('[DryRun] git commit -m "' + $Message + '"')
} else {
git add -A
$null = git diff --cached --quiet
if ($LASTEXITCODE -eq 0) {
Write-Warning "Keine Build-Aenderungen - nichts zu committen."
} else {
git commit -m $Message
}
}
if ($Push) {
Write-Step "Push nach origin/main"
if ($DryRun) {
Write-Host '[DryRun] git push origin main'
} else {
git push origin main
}
} else {
Write-Host "Hinweis: Ohne -Push wurde nur lokal auf main gebaut." -ForegroundColor Yellow
}
Write-Step "Zurueck auf $OriginalBranch"
if (-not $DryRun) {
if ([string]::IsNullOrWhiteSpace($OriginalBranch)) {
git checkout dev
} else {
git checkout $OriginalBranch
}
}
Write-Host ""
Write-Host "Production-Release abgeschlossen." -ForegroundColor Green
if (-not $Push -and -not $DryRun) {
Write-Host "Zum Veroeffentlichen: git push origin main" -ForegroundColor Yellow
}
}
catch {
Write-Host ""
Write-Host ('FEHLER: ' + $_.Exception.Message) -ForegroundColor Red
Set-Location $Root
if ($OriginalBranch -and -not $DryRun) {
git checkout $OriginalBranch 2>$null
}
exit 1
}

View File

@@ -1,187 +0,0 @@
#!/usr/bin/env bash
#
# Erstellt einen Production-Build und veröffentlicht ihn auf den Branch main.
#
# 1. Wechselt auf main und setzt ihn auf den Stand von dev
# 2. Entfernt Kommentare, minifiziert CSS, obfuskiert JavaScript
# 3. Committet und pusht main (optional)
# 4. Wechselt zurück auf den ursprünglichen Branch (dev bleibt unverändert)
#
# Nutzung:
# ./scripts/publish-to-main.sh
# ./scripts/publish-to-main.sh --push
# ./scripts/publish-to-main.sh --dry-run
# ./scripts/publish-to-main.sh --allow-dirty --message "chore(release): v1.2"
#
set -euo pipefail
PUSH=false
DRY_RUN=false
ALLOW_DIRTY=false
MESSAGE=""
usage() {
cat <<'EOF'
Usage: publish-to-main.sh [OPTIONS]
Options:
--push Push nach origin/main
--dry-run Git-Schritte nur anzeigen (Build wird ausgeführt)
--allow-dirty Uncommittete Änderungen erlauben
--message TEXT Commit-Nachricht
-h, --help Hilfe anzeigen
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--push)
PUSH=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
--allow-dirty)
ALLOW_DIRTY=true
shift
;;
--message)
MESSAGE="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unbekannte Option: $1" >&2
usage >&2
exit 1
;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BUILD_DIR="$ROOT/scripts/build"
ORIGINAL_BRANCH=""
step() {
echo ""
echo "==> $1"
}
require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "FEHLER: '$1' nicht gefunden. Bitte installieren und PATH setzen." >&2
exit 1
fi
}
ensure_git_clean() {
if [[ -n "$(git -C "$ROOT" status --porcelain)" ]]; then
echo "FEHLER: Uncommittete Änderungen. Bitte zuerst committen oder stashen." >&2
exit 1
fi
}
cleanup_on_error() {
echo ""
echo "FEHLER: Abgebrochen." >&2
cd "$ROOT" || true
if [[ -n "$ORIGINAL_BRANCH" && "$DRY_RUN" == false ]]; then
git checkout "$ORIGINAL_BRANCH" 2>/dev/null || true
fi
}
trap cleanup_on_error ERR
require_command node
require_command npm
require_command git
cd "$ROOT"
if [[ "$ALLOW_DIRTY" == false ]]; then
ensure_git_clean
else
echo "WARNUNG: --allow-dirty aktiv uncommittete Änderungen werden mit veröffentlicht." >&2
fi
ORIGINAL_BRANCH="$(git branch --show-current | tr -d '[:space:]')"
if [[ "$ORIGINAL_BRANCH" != "dev" ]]; then
echo "WARNUNG: Empfohlen auf Branch 'dev' zu starten (aktuell: ${ORIGINAL_BRANCH:-detached})" >&2
fi
if [[ -z "$MESSAGE" ]]; then
MESSAGE="chore(release): production build $(date '+%Y-%m-%d %H:%M')"
fi
step "Installiere Build-Abhängigkeiten"
cd "$BUILD_DIR"
if [[ "$DRY_RUN" == false ]]; then
npm ci --no-fund --no-audit
fi
step "Wechsle auf main und synchronisiere mit dev"
cd "$ROOT"
if [[ "$DRY_RUN" == true ]]; then
echo "[DryRun] git checkout main"
echo "[DryRun] git reset --hard dev"
else
git checkout main
git reset --hard dev
fi
step "Production-Build (Kommentare entfernen, JS obfuscaten)"
cd "$BUILD_DIR"
if [[ "$DRY_RUN" == true ]]; then
echo "[DryRun] npm run build:in-place"
else
npm run build:in-place
fi
step "Production-Build committen"
cd "$ROOT"
if [[ "$DRY_RUN" == true ]]; then
echo "[DryRun] git add -A"
echo "[DryRun] git commit -m \"$MESSAGE\""
else
git add -A
if git diff --cached --quiet; then
echo "WARNUNG: Keine Build-Änderungen nichts zu committen." >&2
else
git commit -m "$MESSAGE"
fi
fi
if [[ "$PUSH" == true ]]; then
step "Push nach origin/main"
if [[ "$DRY_RUN" == true ]]; then
echo "[DryRun] git push origin main"
else
git push origin main
fi
else
echo "Hinweis: Ohne --push wurde nur lokal auf main gebaut."
fi
step "Zurück auf ${ORIGINAL_BRANCH:-dev}"
if [[ "$DRY_RUN" == false ]]; then
if [[ -n "$ORIGINAL_BRANCH" ]]; then
git checkout "$ORIGINAL_BRANCH"
else
git checkout dev
fi
fi
trap - ERR
echo ""
echo "Production-Release abgeschlossen."
if [[ "$PUSH" == false && "$DRY_RUN" == false ]]; then
echo "Zum Veröffentlichen: git push origin main"
fi

View File

@@ -1,46 +0,0 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Erstellt ein Production-Bundle unter dist/ (ohne Branch-Wechsel).
#>
[CmdletBinding()]
param(
[switch]$InPlace
)
$ErrorActionPreference = "Stop"
$Root = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$BuildDir = Join-Path $Root "scripts\build"
function Resolve-NodeTool([string]$ToolName) {
$command = Get-Command $ToolName -ErrorAction SilentlyContinue
if ($command) { return $command.Source }
$candidates = @(
(Join-Path $env:ProgramFiles "nodejs\$ToolName.cmd"),
(Join-Path ${env:ProgramFiles(x86)} "nodejs\$ToolName.cmd")
)
foreach ($candidate in $candidates) {
if (Test-Path $candidate) { return $candidate }
}
return $null
}
$npm = Resolve-NodeTool "npm"
if (-not $npm) {
throw "npm nicht gefunden. Bitte Node.js installieren."
}
Set-Location $BuildDir
& $npm ci --no-fund --no-audit
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
if ($InPlace) {
& $npm run build:in-place
} else {
& $npm run build
}
exit $LASTEXITCODE

View File

@@ -1,58 +0,0 @@
#!/usr/bin/env bash
#
# Erstellt ein Production-Bundle unter dist/ (ohne Branch-Wechsel).
#
# Nutzung:
# ./scripts/run-build.sh
# ./scripts/run-build.sh --in-place
#
set -euo pipefail
IN_PLACE=false
usage() {
cat <<'EOF'
Usage: run-build.sh [OPTIONS]
Options:
--in-place Build direkt im Repository (statt dist/)
-h, --help Hilfe anzeigen
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--in-place)
IN_PLACE=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unbekannte Option: $1" >&2
usage >&2
exit 1
;;
esac
done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BUILD_DIR="$ROOT/scripts/build"
if ! command -v npm >/dev/null 2>&1; then
echo "FEHLER: npm nicht gefunden. Bitte Node.js installieren." >&2
exit 1
fi
cd "$BUILD_DIR"
npm ci --no-fund --no-audit
if [[ "$IN_PLACE" == true ]]; then
npm run build:in-place
else
npm run build
fi

View File

@@ -1,48 +0,0 @@
<?php
/**
* HexaHost.de E-Mail Test (nur CLI oder lokale Entwicklung)
*/
if (PHP_SAPI !== 'cli') {
$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '';
$isLocal = in_array($remoteAddr, ['127.0.0.1', '::1'], true)
|| filter_var($remoteAddr, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false;
if (!$isLocal) {
http_response_code(403);
exit('Forbidden');
}
}
require_once __DIR__ . '/../backend/config/mail-config.php';
function testEmail() {
$config = getHexaHostConfig();
$subject = '[HexaHost.de] Test-E-Mail';
$message = "Test-E-Mail von HexaHost.de\n\n";
$message .= "Zeitstempel: " . date('d.m.Y H:i:s') . "\n";
$headers = [
'From: ' . $config['from_name'] . ' <' . $config['from_email'] . '>',
'MIME-Version: 1.0',
'Content-Type: text/plain; charset=UTF-8',
'X-Mailer: HexaHost Test Email',
];
return mail($config['to_email'], $subject, $message, implode("\r\n", $headers));
}
if (PHP_SAPI === 'cli') {
echo testEmail() ? "Test-E-Mail gesendet.\n" : "Fehler beim Senden.\n";
exit;
}
if (isset($_GET['test'])) {
echo testEmail()
? 'Test-E-Mail wurde gesendet.'
: 'Fehler beim Senden der Test-E-Mail.';
} else {
echo '<h1>HexaHost.de E-Mail Test</h1>';
echo '<p><a href="?test=1">Test-E-Mail senden</a></p>';
}