halbe Breite 115px). pt schafft Luft fuer die Skalierung.
+ { perspective: '1200px', paddingLeft: 'calc(50% - 115px)', paddingRight: 'calc(50% - 115px)', paddingTop: '10px' }
+ : undefined
}
>
{packages.map((pkg) => {
@@ -369,7 +417,7 @@ export default function ModelPage() {
pkg={pkg}
tier={tier}
tierT={tierT}
- isStripLayout={isStripLayout}
+ layout={layout}
bullets={bulletsOf(pkg)}
formatPrice={formatPrice}
contactUrl={contactUrl}
diff --git a/hifi/api/database/migration_package_price_text.sql b/hifi/api/database/migration_package_price_text.sql
new file mode 100644
index 0000000..d9794e5
--- /dev/null
+++ b/hifi/api/database/migration_package_price_text.sql
@@ -0,0 +1,7 @@
+-- Optionaler Freitext, der auf der Paket-Kachel den Preis ersetzt (z. B. "Coming soon").
+-- Additiv, nichts wird geloescht.
+-- Hinweis: Auf der Live-Seite reicht stattdessen ein Klick auf "Datenbankstruktur aktualisieren"
+-- unter Admin-Panel -> Einstellungen -> Datenbank.
+
+ALTER TABLE packages
+ ADD COLUMN IF NOT EXISTS price_text VARCHAR(100) NULL;
diff --git a/hifi/api/database/schema.sql b/hifi/api/database/schema.sql
index a738f21..f597009 100644
--- a/hifi/api/database/schema.sql
+++ b/hifi/api/database/schema.sql
@@ -151,6 +151,7 @@ CREATE TABLE packages (
markup_value DECIMAL(10,2) NOT NULL DEFAULT 0,
icon_name VARCHAR(100) NULL,
tagline VARCHAR(150) NULL,
+ price_text VARCHAR(100) NULL,
is_featured TINYINT(1) NOT NULL DEFAULT 0,
sort_order INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
diff --git a/hifi/api/src/Controllers/ModelController.php b/hifi/api/src/Controllers/ModelController.php
index 26569ab..946a5a7 100644
--- a/hifi/api/src/Controllers/ModelController.php
+++ b/hifi/api/src/Controllers/ModelController.php
@@ -90,7 +90,7 @@ class ModelController
}
$pkgStmt = $db->prepare(
- 'SELECT id, name, slug, description, markup_type, markup_value, icon_name, tagline, is_featured, sort_order
+ 'SELECT id, name, slug, description, markup_type, markup_value, icon_name, tagline, price_text, is_featured, sort_order
FROM packages WHERE car_model_id = ? ORDER BY sort_order, name'
);
$pkgStmt->execute([$model['id']]);
diff --git a/hifi/api/src/Controllers/PackageController.php b/hifi/api/src/Controllers/PackageController.php
index 19d08b6..eab0f24 100644
--- a/hifi/api/src/Controllers/PackageController.php
+++ b/hifi/api/src/Controllers/PackageController.php
@@ -23,7 +23,7 @@ class PackageController
{
$stmt = Database::connection()->query(
'SELECT p.id, p.name, p.slug, p.description, p.markup_type, p.markup_value, p.icon_name, p.tagline,
- p.is_featured, p.sort_order, p.car_model_id, m.name AS model_name, b.name AS brand_name
+ p.price_text, p.is_featured, p.sort_order, p.car_model_id, m.name AS model_name, b.name AS brand_name
FROM packages p
JOIN car_models m ON m.id = p.car_model_id
JOIN brands b ON b.id = m.brand_id
@@ -51,8 +51,8 @@ class PackageController
$db = Database::connection();
$stmt = $db->prepare(
- 'INSERT INTO packages (car_model_id, name, slug, description, markup_type, markup_value, icon_name, tagline, is_featured, sort_order)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
+ 'INSERT INTO packages (car_model_id, name, slug, description, markup_type, markup_value, icon_name, tagline, price_text, is_featured, sort_order)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
);
$stmt->execute([
$modelId,
@@ -63,6 +63,7 @@ class PackageController
$markupValue,
trim($body['icon_name'] ?? '') ?: null,
trim($body['tagline'] ?? '') ?: null,
+ trim($body['price_text'] ?? '') ?: null,
!empty($body['is_featured']) ? 1 : 0,
(int) ($body['sort_order'] ?? 0),
]);
@@ -84,7 +85,7 @@ class PackageController
[$markupType, $markupValue] = self::normalizeMarkup($body);
$stmt = Database::connection()->prepare(
- 'UPDATE packages SET car_model_id = ?, name = ?, slug = ?, description = ?, markup_type = ?, markup_value = ?, icon_name = ?, tagline = ?, is_featured = ?, sort_order = ? WHERE id = ?'
+ 'UPDATE packages SET car_model_id = ?, name = ?, slug = ?, description = ?, markup_type = ?, markup_value = ?, icon_name = ?, tagline = ?, price_text = ?, is_featured = ?, sort_order = ? WHERE id = ?'
);
$stmt->execute([
$modelId,
@@ -95,6 +96,7 @@ class PackageController
$markupValue,
trim($body['icon_name'] ?? '') ?: null,
trim($body['tagline'] ?? '') ?: null,
+ trim($body['price_text'] ?? '') ?: null,
!empty($body['is_featured']) ? 1 : 0,
(int) ($body['sort_order'] ?? 0),
$id,
diff --git a/hifi/api/src/Controllers/SettingsController.php b/hifi/api/src/Controllers/SettingsController.php
index f86bbf7..025baa7 100644
--- a/hifi/api/src/Controllers/SettingsController.php
+++ b/hifi/api/src/Controllers/SettingsController.php
@@ -16,7 +16,7 @@ class SettingsController
private const TABLE_COLUMNS = [
'brands' => ['id', 'name', 'slug', 'sort_order', 'created_at', 'updated_at'],
'car_models' => ['id', 'brand_id', 'name', 'slug', 'sort_order', 'created_at', 'updated_at'],
- 'packages' => ['id', 'car_model_id', 'name', 'slug', 'description', 'markup_type', 'markup_value', 'icon_name', 'tagline', 'is_featured', 'sort_order', 'created_at', 'updated_at'],
+ 'packages' => ['id', 'car_model_id', 'name', 'slug', 'description', 'markup_type', 'markup_value', 'icon_name', 'tagline', 'price_text', 'is_featured', 'sort_order', 'created_at', 'updated_at'],
'package_products' => ['id', 'package_id', 'source_url', 'name_override', 'scraped_name', 'scraped_price', 'scraped_currency', 'scraped_image_url', 'price_updated_at', 'scrape_status', 'scrape_error', 'sort_order', 'created_at', 'updated_at'],
'package_upgrades' => ['id', 'package_id', 'name', 'description', 'price', 'sort_order', 'created_at', 'updated_at'],
'services' => ['id', 'icon_name', 'title', 'description', 'image_path', 'cta_label', 'cta_url', 'sort_order', 'created_at', 'updated_at'],
diff --git a/hifi/api/src/Controllers/SiteSettingsController.php b/hifi/api/src/Controllers/SiteSettingsController.php
index 1b92c7a..b3fb9e8 100644
--- a/hifi/api/src/Controllers/SiteSettingsController.php
+++ b/hifi/api/src/Controllers/SiteSettingsController.php
@@ -40,7 +40,7 @@ class SiteSettingsController
}
private const PACKAGE_CARD_THEMES = ['graphite', 'deep-blue', 'warm-bronze'];
- private const PACKAGE_CARD_LAYOUTS = ['grid', 'strip'];
+ private const PACKAGE_CARD_LAYOUTS = ['grid', 'strip', 'coverflow'];
public static function update(): void
{
diff --git a/hifi/api/src/Support/Schema.php b/hifi/api/src/Support/Schema.php
index bd99f0d..9ee9f07 100644
--- a/hifi/api/src/Support/Schema.php
+++ b/hifi/api/src/Support/Schema.php
@@ -162,6 +162,7 @@ class Schema
markup_value DECIMAL(10,2) NOT NULL DEFAULT 0,
icon_name VARCHAR(100) NULL,
tagline VARCHAR(150) NULL,
+ price_text VARCHAR(100) NULL,
is_featured TINYINT(1) NOT NULL DEFAULT 0,
sort_order INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
@@ -364,6 +365,7 @@ class Schema
'markup_value' => 'DECIMAL(10,2) NOT NULL DEFAULT 0',
'icon_name' => 'VARCHAR(100) NULL',
'tagline' => 'VARCHAR(150) NULL',
+ 'price_text' => 'VARCHAR(100) NULL',
'is_featured' => 'TINYINT(1) NOT NULL DEFAULT 0',
'sort_order' => 'INT NOT NULL DEFAULT 0',
'created_at' => 'DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP',