20-02-2026
This commit is contained in:
parent
854ce02bf6
commit
4d6b4930b2
128 changed files with 18247 additions and 2093 deletions
126
public/_cabinet/offers/config.json
Normal file
126
public/_cabinet/offers/config.json
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"location": "CABINET Bielefeld",
|
||||
"updated": "2026-02-05"
|
||||
},
|
||||
"settings": {
|
||||
"loop": true,
|
||||
"transition": {
|
||||
"type": "fade",
|
||||
"duration": 600
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"whatsapp": "0521 ...",
|
||||
"phone": "0521 ...",
|
||||
"storeUrl": "https://cabinet-bielefeld.de"
|
||||
},
|
||||
"slides": [
|
||||
{
|
||||
"id": "intro",
|
||||
"file": "slide-0-intro.html",
|
||||
"duration": 8000,
|
||||
"type": "intro",
|
||||
"content": {
|
||||
"headerLeft": "CABINET Bielefeld",
|
||||
"headerRight": [
|
||||
"Planung • Beratung",
|
||||
"Lieferung & Montage"
|
||||
],
|
||||
"heroBadge": "Einzelstücke & Ausstellungsdeals – nur solange verfügbar",
|
||||
"eyebrow": "Heute im Fokus",
|
||||
"title": "Kuratiert. Hochwertig. Sofort.",
|
||||
"subline": "Scannen Sie den QR-Code für Kontakt & Store-Infos.",
|
||||
"footer": "CABINET Bielefeld – im Store ansprechen oder direkt reservieren",
|
||||
"disclaimer": "Zwischenverkauf vorbehalten",
|
||||
"qr": {
|
||||
"title": "Kontakt & Store-Infos",
|
||||
"subtitle": "QR scannen",
|
||||
"url": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "goya-hero",
|
||||
"file": "slide-1-goya-hero.html",
|
||||
"duration": 10000,
|
||||
"type": "product-hero",
|
||||
"content": {
|
||||
"headerLeft": "CABINET",
|
||||
"headerRight": [
|
||||
"Ausstellungsware",
|
||||
"Einzelstück"
|
||||
],
|
||||
"heroImage": "assets/goya-hero.jpg",
|
||||
"eyebrow": "Ausstellungsware",
|
||||
"title": "GOYA Sideboard",
|
||||
"subline": "Marke: Sudbrock",
|
||||
"price": "489 €",
|
||||
"priceNote": "brutto",
|
||||
"uvp": "UVP neu: 4.744 €*",
|
||||
"disclaimer": "*UVP nur, sofern belegbar. Zwischenverkauf vorbehalten.",
|
||||
"qr": {
|
||||
"title": "Infos & Reservierung",
|
||||
"subtitle": "QR scannen",
|
||||
"url": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "goya-details",
|
||||
"file": "slide-2-goya-details.html",
|
||||
"duration": 12000,
|
||||
"type": "product-details",
|
||||
"content": {
|
||||
"headerLeft": "CABINET",
|
||||
"headerRight": [
|
||||
"GOYA",
|
||||
"Konditionen"
|
||||
],
|
||||
"heroImage": "assets/goya-detail.jpg",
|
||||
"eyebrow": "GOYA | Konditionen",
|
||||
"title": "Details auf einen Blick",
|
||||
"bullets": [
|
||||
"Eingelagertes Einzelstück",
|
||||
"Abholung: Lager Rheda-Wiedenbrück",
|
||||
"Lieferung/Montage optional",
|
||||
"Preis gilt ohne Lieferung/Montage",
|
||||
"Deckel: Weiß matt (erneuert)"
|
||||
],
|
||||
"cta": "Details & Reservierung",
|
||||
"qr": {
|
||||
"title": "Details: QR scannen",
|
||||
"subtitle": "Reservierung & Kontakt",
|
||||
"url": ""
|
||||
},
|
||||
"disclaimer": "Zwischenverkauf vorbehalten"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tando",
|
||||
"file": "slide-3-tando.html",
|
||||
"duration": 10000,
|
||||
"type": "product-impulse",
|
||||
"content": {
|
||||
"headerLeft": "CABINET",
|
||||
"headerRight": [
|
||||
"Nur 1× im Store",
|
||||
"Sofort"
|
||||
],
|
||||
"heroImage": "assets/tando-store.jpg",
|
||||
"eyebrow": "Nur 1× im Store",
|
||||
"title": "TANDO Spiegel",
|
||||
"subline": "Ansehen & mitnehmen – heute",
|
||||
"price": "199 €",
|
||||
"priceNote": "brutto",
|
||||
"impulseTag": "Jetzt sichern",
|
||||
"qr": {
|
||||
"title": "Jetzt sichern",
|
||||
"subtitle": "QR scannen oder Team ansprechen",
|
||||
"url": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
408
public/_cabinet/offers/player.html
Normal file
408
public/_cabinet/offers/player.html
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CABINET – Angebote Display</title>
|
||||
<style>
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
|
||||
/* Container für 9:16 Aspect Ratio */
|
||||
.player-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.player-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 1080px;
|
||||
max-height: 1920px;
|
||||
aspect-ratio: 9 / 16;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (min-aspect-ratio: 9/16) {
|
||||
.player-frame {
|
||||
width: auto;
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 9/16) {
|
||||
.player-frame {
|
||||
width: 100vw;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* iFrames für Slides */
|
||||
.slide-frame {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.6s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.slide-frame.active {
|
||||
opacity: 1;
|
||||
z-index: 2;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.slide-frame.preload {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Progress Indicator */
|
||||
.progress-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background: #009FE3;
|
||||
transition: width linear;
|
||||
}
|
||||
|
||||
/* Slide Indicators */
|
||||
.slide-indicators {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 100;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.indicator.active {
|
||||
background: #009FE3;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
/* Loading State */
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.loading-overlay.hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-family: 'IBM Plex Sans', sans-serif;
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* Debug Info (optional, ausblendbar) */
|
||||
.debug-info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0,0,0,0.7);
|
||||
color: #fff;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-info.visible {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="player-container">
|
||||
<div class="player-frame" id="player">
|
||||
<!-- Loading Overlay -->
|
||||
<div class="loading-overlay" id="loading">
|
||||
<span class="loading-text">Lädt Angebote...</span>
|
||||
</div>
|
||||
|
||||
<!-- Slides werden hier dynamisch eingefügt -->
|
||||
|
||||
<!-- Progress Bar -->
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="progress"></div>
|
||||
</div>
|
||||
|
||||
<!-- Slide Indicators (optional) -->
|
||||
<div class="slide-indicators" id="indicators"></div>
|
||||
|
||||
<!-- Debug Info -->
|
||||
<div class="debug-info" id="debug">
|
||||
Slide: <span id="debug-slide">0</span> / <span id="debug-total">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* CABINET Offer Slide Player
|
||||
* Lädt und rotiert durch Slides basierend auf config.json
|
||||
*/
|
||||
|
||||
const CONFIG_URL = 'config.json';
|
||||
const DEBUG_MODE = false; // Auf true setzen für Debug-Infos
|
||||
|
||||
class SlidePlayer {
|
||||
constructor() {
|
||||
this.config = null;
|
||||
this.slides = [];
|
||||
this.currentIndex = 0;
|
||||
this.frames = [];
|
||||
this.timer = null;
|
||||
this.isPlaying = false;
|
||||
|
||||
// DOM Elements
|
||||
this.player = document.getElementById('player');
|
||||
this.loading = document.getElementById('loading');
|
||||
this.progress = document.getElementById('progress');
|
||||
this.indicators = document.getElementById('indicators');
|
||||
this.debug = document.getElementById('debug');
|
||||
this.debugSlide = document.getElementById('debug-slide');
|
||||
this.debugTotal = document.getElementById('debug-total');
|
||||
|
||||
if (DEBUG_MODE) {
|
||||
this.debug.classList.add('visible');
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
try {
|
||||
console.log('[Player] Initializing...');
|
||||
|
||||
// Lade Konfiguration
|
||||
await this.loadConfig();
|
||||
|
||||
// Erstelle iFrames für alle Slides
|
||||
this.createFrames();
|
||||
|
||||
// Erstelle Indikatoren
|
||||
this.createIndicators();
|
||||
|
||||
// Warte bis erster Slide geladen ist
|
||||
await this.preloadSlide(0);
|
||||
|
||||
// Verstecke Loading
|
||||
this.loading.classList.add('hidden');
|
||||
|
||||
// Starte Rotation
|
||||
this.play();
|
||||
|
||||
console.log('[Player] Ready!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Player] Init error:', error);
|
||||
this.showError('Fehler beim Laden der Angebote');
|
||||
}
|
||||
}
|
||||
|
||||
async loadConfig() {
|
||||
const response = await fetch(CONFIG_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Config load failed: ${response.status}`);
|
||||
}
|
||||
this.config = await response.json();
|
||||
this.slides = this.config.slides || [];
|
||||
|
||||
console.log(`[Player] Loaded ${this.slides.length} slides`);
|
||||
this.debugTotal.textContent = this.slides.length;
|
||||
}
|
||||
|
||||
createFrames() {
|
||||
this.slides.forEach((slide, index) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.className = 'slide-frame';
|
||||
iframe.id = `frame-${index}`;
|
||||
iframe.setAttribute('loading', 'lazy');
|
||||
iframe.setAttribute('data-src', slide.file);
|
||||
|
||||
// Füge vor Progress Bar ein
|
||||
this.player.insertBefore(iframe, this.player.querySelector('.progress-bar'));
|
||||
this.frames.push(iframe);
|
||||
});
|
||||
}
|
||||
|
||||
createIndicators() {
|
||||
this.slides.forEach((_, index) => {
|
||||
const dot = document.createElement('div');
|
||||
dot.className = 'indicator';
|
||||
dot.dataset.index = index;
|
||||
this.indicators.appendChild(dot);
|
||||
});
|
||||
}
|
||||
|
||||
async preloadSlide(index) {
|
||||
const frame = this.frames[index];
|
||||
if (!frame) return;
|
||||
|
||||
// Wenn noch nicht geladen, lade jetzt
|
||||
if (!frame.src) {
|
||||
const src = frame.getAttribute('data-src');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
frame.onload = () => {
|
||||
console.log(`[Player] Slide ${index} loaded`);
|
||||
resolve();
|
||||
};
|
||||
frame.onerror = () => {
|
||||
console.error(`[Player] Slide ${index} failed to load`);
|
||||
resolve(); // Trotzdem weiter
|
||||
};
|
||||
frame.src = src;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
showSlide(index) {
|
||||
// Deaktiviere alle Frames
|
||||
this.frames.forEach((frame, i) => {
|
||||
frame.classList.remove('active', 'preload');
|
||||
});
|
||||
|
||||
// Aktiviere aktuellen Frame
|
||||
const currentFrame = this.frames[index];
|
||||
if (currentFrame) {
|
||||
currentFrame.classList.add('active');
|
||||
}
|
||||
|
||||
// Update Indikatoren
|
||||
const dots = this.indicators.querySelectorAll('.indicator');
|
||||
dots.forEach((dot, i) => {
|
||||
dot.classList.toggle('active', i === index);
|
||||
});
|
||||
|
||||
// Update Debug
|
||||
this.debugSlide.textContent = index + 1;
|
||||
|
||||
// Preload nächsten Slide
|
||||
const nextIndex = (index + 1) % this.slides.length;
|
||||
this.preloadSlide(nextIndex);
|
||||
|
||||
console.log(`[Player] Showing slide ${index}: ${this.slides[index].id}`);
|
||||
}
|
||||
|
||||
startProgress(duration) {
|
||||
// Reset progress
|
||||
this.progress.style.transition = 'none';
|
||||
this.progress.style.width = '0%';
|
||||
|
||||
// Force reflow
|
||||
void this.progress.offsetWidth;
|
||||
|
||||
// Animate
|
||||
this.progress.style.transition = `width ${duration}ms linear`;
|
||||
this.progress.style.width = '100%';
|
||||
}
|
||||
|
||||
play() {
|
||||
if (this.isPlaying) return;
|
||||
this.isPlaying = true;
|
||||
|
||||
this.showCurrentSlide();
|
||||
}
|
||||
|
||||
showCurrentSlide() {
|
||||
const slide = this.slides[this.currentIndex];
|
||||
const duration = slide.duration || 8000;
|
||||
|
||||
// Zeige Slide
|
||||
this.showSlide(this.currentIndex);
|
||||
|
||||
// Starte Progress
|
||||
this.startProgress(duration);
|
||||
|
||||
// Timer für nächsten Slide
|
||||
clearTimeout(this.timer);
|
||||
this.timer = setTimeout(() => {
|
||||
this.nextSlide();
|
||||
}, duration);
|
||||
}
|
||||
|
||||
nextSlide() {
|
||||
this.currentIndex = (this.currentIndex + 1) % this.slides.length;
|
||||
this.showCurrentSlide();
|
||||
}
|
||||
|
||||
prevSlide() {
|
||||
this.currentIndex = (this.currentIndex - 1 + this.slides.length) % this.slides.length;
|
||||
this.showCurrentSlide();
|
||||
}
|
||||
|
||||
pause() {
|
||||
this.isPlaying = false;
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
this.loading.innerHTML = `<span class="loading-text" style="color: #c00;">${message}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Player
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const player = new SlidePlayer();
|
||||
player.init();
|
||||
|
||||
// Optional: Keyboard Controls (für Testing)
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'ArrowRight') player.nextSlide();
|
||||
if (e.key === 'ArrowLeft') player.prevSlide();
|
||||
if (e.key === ' ') player.isPlaying ? player.pause() : player.play();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
493
public/_cabinet/offers/shared-styles.css
Normal file
493
public/_cabinet/offers/shared-styles.css
Normal file
|
|
@ -0,0 +1,493 @@
|
|||
/**
|
||||
* CABINET Display - Shared Styles
|
||||
* Format: 9:16 (1080×1920px)
|
||||
* Safe-Area: 64px
|
||||
*/
|
||||
|
||||
:root {
|
||||
/* Colors */
|
||||
--bg: #ffffff;
|
||||
--fg: #1a1a1a;
|
||||
--fg-strong: #000000;
|
||||
--muted: #737373;
|
||||
--muted-light: #999999;
|
||||
--line: #e8e8e8;
|
||||
--card: #f5f5f5;
|
||||
--accent: #009FE3; /* Cabinet Blau */
|
||||
|
||||
/* Spacing */
|
||||
--safe-area: 64px;
|
||||
--radius: 24px;
|
||||
--radius-sm: 16px;
|
||||
|
||||
/* Typography Scale (modular) */
|
||||
--text-xs: 16px;
|
||||
--text-sm: 18px;
|
||||
--text-base: 20px;
|
||||
--text-lg: 24px;
|
||||
--text-xl: 28px;
|
||||
--text-2xl: 32px;
|
||||
--text-3xl: 42px;
|
||||
--text-4xl: 54px;
|
||||
--text-5xl: 64px;
|
||||
--text-6xl: 84px;
|
||||
|
||||
/* Font */
|
||||
--font-main: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, sans-serif;
|
||||
|
||||
/* Dimensions */
|
||||
--max-width: 1080px;
|
||||
--max-height: 1920px;
|
||||
}
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-main);
|
||||
background: #0a0a0a;
|
||||
color: var(--fg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
/* Text Rendering */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
SCREEN CONTAINER (9:16 Frame)
|
||||
======================================== */
|
||||
|
||||
.screen {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: var(--max-width);
|
||||
max-height: var(--max-height);
|
||||
aspect-ratio: 9 / 16;
|
||||
background: var(--bg);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Maintain aspect ratio */
|
||||
@media (min-aspect-ratio: 9/16) {
|
||||
.screen {
|
||||
width: auto;
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 9/16) {
|
||||
.screen {
|
||||
width: 100vw;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
SLIDE LAYOUT
|
||||
======================================== */
|
||||
|
||||
.slide {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
padding: var(--safe-area);
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
gap: 32px;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
HEADER
|
||||
======================================== */
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 24px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
height: 82px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.brand-text {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--fg-strong);
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--muted);
|
||||
text-align: right;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
HERO SECTION
|
||||
======================================== */
|
||||
|
||||
.hero {
|
||||
border-radius: var(--radius);
|
||||
background: linear-gradient(145deg, #f5f5f5, #fafafa);
|
||||
border: 1px solid var(--line);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.hero.has-image {
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
color: var(--fg);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 100px;
|
||||
padding: 14px 24px;
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
letter-spacing: 0.01em;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* Placeholder für Entwicklung */
|
||||
.hero-placeholder {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
color: var(--muted);
|
||||
background:
|
||||
radial-gradient(circle at 30% 30%, rgba(0,0,0,0.03), transparent 50%),
|
||||
linear-gradient(145deg, #f2f2f2, #fafafa);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
BOTTOM SECTION (Info + QR)
|
||||
======================================== */
|
||||
|
||||
.bottom {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 300px;
|
||||
gap: 24px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
/* Info Box */
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background: linear-gradient(180deg, #ffffff, #fafafa);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
padding: 28px;
|
||||
min-height: 340px;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: var(--text-4xl);
|
||||
line-height: 1.08;
|
||||
font-weight: 700;
|
||||
margin-bottom: 14px;
|
||||
color: var(--fg-strong);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.title.large {
|
||||
font-size: var(--text-5xl);
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.title.medium {
|
||||
font-size: var(--text-3xl);
|
||||
letter-spacing: -0.015em;
|
||||
}
|
||||
|
||||
.subline {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--muted);
|
||||
line-height: 1.35;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* Price Display */
|
||||
.price-block {
|
||||
margin-top: auto;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.price-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: var(--text-6xl);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.03em;
|
||||
color: var(--fg-strong);
|
||||
line-height: 1;
|
||||
font-feature-settings: 'tnum' 1; /* Tabular numbers */
|
||||
}
|
||||
|
||||
.price-note {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--muted);
|
||||
text-align: right;
|
||||
line-height: 1.35;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* Bullets List */
|
||||
.bullets {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.bullets li {
|
||||
font-size: var(--text-xl);
|
||||
line-height: 1.35;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
color: var(--fg);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.bullets .dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
margin-top: 13px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Footer Text (within info box) */
|
||||
.info-footer {
|
||||
margin-top: auto;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
font-size: var(--text-base);
|
||||
color: var(--muted);
|
||||
line-height: 1.45;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.footer-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
QR BOX
|
||||
======================================== */
|
||||
|
||||
.qr-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
padding: 20px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.qr-header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.qr-title {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600;
|
||||
color: var(--fg-strong);
|
||||
margin-bottom: 6px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.qr-subtitle {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.qr-code-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px dashed #ddd;
|
||||
padding: 16px;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.qr-code-wrapper img {
|
||||
width: 100%;
|
||||
max-width: 180px;
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
/* QR Placeholder */
|
||||
.qr-placeholder {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
background:
|
||||
repeating-linear-gradient(
|
||||
0deg,
|
||||
#e0e0e0,
|
||||
#e0e0e0 12px,
|
||||
transparent 12px,
|
||||
transparent 16px
|
||||
),
|
||||
repeating-linear-gradient(
|
||||
90deg,
|
||||
#e0e0e0,
|
||||
#e0e0e0 12px,
|
||||
transparent 12px,
|
||||
transparent 16px
|
||||
);
|
||||
opacity: 0.5;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.qr-contact {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
DISCLAIMER
|
||||
======================================== */
|
||||
|
||||
.disclaimer {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--muted-light);
|
||||
margin-top: 12px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
ANIMATIONS (for player integration)
|
||||
======================================== */
|
||||
|
||||
.slide.fade-in {
|
||||
animation: fadeIn 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
.slide.fade-out {
|
||||
animation: fadeOut 0.6s ease-in forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
UTILITY CLASSES
|
||||
======================================== */
|
||||
|
||||
.text-accent {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mt-auto {
|
||||
margin-top: auto;
|
||||
}
|
||||
100
public/_cabinet/offers/slide-0-intro.html
Normal file
100
public/_cabinet/offers/slide-0-intro.html
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CABINET – Intro</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./shared-styles.css">
|
||||
<style>
|
||||
/* Slide-spezifische Anpassungen */
|
||||
.hero {
|
||||
background:
|
||||
radial-gradient(ellipse at 30% 40%, rgba(0, 159, 227, 0.05), transparent 60%),
|
||||
linear-gradient(165deg, #f8f8f8, #ffffff);
|
||||
}
|
||||
.hero.has-image {
|
||||
background: url('../assets/cabinet-intro.jpg') center/cover no-repeat;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 500;
|
||||
padding: 16px 28px;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="screen">
|
||||
<article class="slide" data-duration="8000">
|
||||
|
||||
<!-- HEADER -->
|
||||
<header class="header">
|
||||
<div class="brand">
|
||||
<img src="./logo-cabinet-300.png" alt="CABINET" class="brand-logo">
|
||||
<span class="brand-text">Bielefeld</span>
|
||||
</div>
|
||||
<div class="tagline">
|
||||
Planung • Beratung<br>
|
||||
Lieferung & Montage
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="hero has-image">
|
||||
<span class="hero-badge">Ausstellungsdeals – solange verfügbar</span>
|
||||
</section>
|
||||
|
||||
<!-- BOTTOM: Info + QR -->
|
||||
<section class="bottom">
|
||||
<div class="info">
|
||||
<div class="info-content">
|
||||
<p class="eyebrow">Heute im Fokus</p>
|
||||
<h1 class="title large">Kuratiert.<br>Hochwertig.<br>Sofort.</h1>
|
||||
</div>
|
||||
|
||||
<div class="info-footer">
|
||||
<span class="footer-text disclaimer">Zwischenverkauf vorbehalten</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="qr-box">
|
||||
<div class="qr-header">
|
||||
<p class="qr-title">Kontakt</p>
|
||||
<p class="qr-subtitle">QR scannen</p>
|
||||
</div>
|
||||
<div class="qr-code-wrapper">
|
||||
<img id="qr-code" src="" alt="QR Code">
|
||||
</div>
|
||||
<p class="qr-contact">0521 98620100<br>Tel. oder WhatsApp</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// QR-Code Konfiguration
|
||||
const QR_URL = 'https://cabinet-bielefeld.de'; // Ziel-URL anpassen
|
||||
|
||||
// QR-Code generieren
|
||||
function generateQR(targetUrl) {
|
||||
const size = '300x300';
|
||||
const color = '000000';
|
||||
const bg = 'ffffff';
|
||||
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${size}&color=${color}&bgcolor=${bg}&margin=8&data=${encodeURIComponent(targetUrl)}`;
|
||||
|
||||
const qrImg = document.getElementById('qr-code');
|
||||
if (qrImg) {
|
||||
qrImg.src = qrApiUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Bei Seitenaufruf QR generieren
|
||||
document.addEventListener('DOMContentLoaded', () => generateQR(QR_URL));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
105
public/_cabinet/offers/slide-1-goya-hero.html
Normal file
105
public/_cabinet/offers/slide-1-goya-hero.html
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CABINET – GOYA Sideboard</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./shared-styles.css">
|
||||
<style>
|
||||
/* Slide-spezifische Anpassungen */
|
||||
.hero {
|
||||
background:
|
||||
radial-gradient(ellipse at 30% 40%, rgba(0, 159, 227, 0.05), transparent 60%),
|
||||
linear-gradient(165deg, #f8f8f8, #ffffff);
|
||||
}
|
||||
.hero.has-image {
|
||||
background: url('../assets/goya1.jpg') center/cover no-repeat;
|
||||
}
|
||||
|
||||
.price {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.uvp-strike {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
padding: 16px 28px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="screen">
|
||||
<article class="slide" data-duration="10000">
|
||||
|
||||
<!-- HEADER -->
|
||||
<header class="header">
|
||||
<div class="brand">
|
||||
<img src="./logo-cabinet-300.png" alt="CABINET" class="brand-logo">
|
||||
</div>
|
||||
|
||||
</header>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="hero has-image">
|
||||
<span class="hero-badge">Einzelstück</span>
|
||||
</section>
|
||||
|
||||
<!-- BOTTOM: Info + QR -->
|
||||
<section class="bottom">
|
||||
<div class="info">
|
||||
<div class="info-content">
|
||||
<p class="eyebrow">Hersteller: Sudbrock</p>
|
||||
<h1 class="title large">GOYA Sideboard</h1>
|
||||
</div>
|
||||
|
||||
<div class="price-block">
|
||||
<div class="price-row">
|
||||
<span class="price">489 €</span>
|
||||
<div class="price-note">
|
||||
statt 4.744 €
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="qr-box">
|
||||
<div class="qr-header">
|
||||
<p class="qr-title">Reservieren</p>
|
||||
<p class="qr-subtitle">QR scannen</p>
|
||||
</div>
|
||||
<div class="qr-code-wrapper">
|
||||
<img id="qr-code" src="" alt="QR Code">
|
||||
</div>
|
||||
<p class="qr-contact">0521 98620100<br>Tel. oder WhatsApp</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// QR-Code Konfiguration – GOYA Produkt-/Reservierungsseite
|
||||
const QR_URL = 'https://cabinet-bielefeld.de';
|
||||
|
||||
function generateQR(targetUrl) {
|
||||
const size = '300x300';
|
||||
const color = '000000';
|
||||
const bg = 'ffffff';
|
||||
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${size}&color=${color}&bgcolor=${bg}&margin=8&data=${encodeURIComponent(targetUrl)}`;
|
||||
|
||||
const qrImg = document.getElementById('qr-code');
|
||||
if (qrImg) qrImg.src = qrApiUrl;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => generateQR(QR_URL));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
135
public/_cabinet/offers/slide-2-goya-details.html
Normal file
135
public/_cabinet/offers/slide-2-goya-details.html
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CABINET – GOYA Konditionen</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./shared-styles.css">
|
||||
<style>
|
||||
/* Slide-spezifische Anpassungen */
|
||||
.hero {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(245,245,245,0.9) 0%, rgba(250,250,250,0.95) 100%);
|
||||
}
|
||||
.hero.has-image {
|
||||
background: url('../assets/goya2.jpg') center/cover no-repeat;
|
||||
}
|
||||
.bullets {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.bullets li {
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
|
||||
.cta-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid var(--line);
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.cta-text {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.cta-action {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600;
|
||||
color: var(--fg-strong);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
padding: 16px 28px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="screen">
|
||||
<article class="slide" data-duration="12000">
|
||||
|
||||
<!-- HEADER -->
|
||||
<header class="header">
|
||||
<div class="brand">
|
||||
<img src="./logo-cabinet-300.png" alt="CABINET" class="brand-logo">
|
||||
</div>
|
||||
|
||||
</header>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="hero has-image">
|
||||
<span class="hero-badge">Einzelstück</span>
|
||||
</section>
|
||||
|
||||
<!-- BOTTOM: Info + QR -->
|
||||
<section class="bottom">
|
||||
<div class="info">
|
||||
<div class="info-content">
|
||||
<p class="eyebrow">Auf einen Blick<</p>
|
||||
<h1 class="title medium">GOYA Sideboard</h1>
|
||||
|
||||
<ul class="bullets">
|
||||
<li>
|
||||
<span class="dot"></span>
|
||||
<span>Eingelagertes Einzelstück</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dot"></span>
|
||||
<span>Abholung in Rheda-Wiedenbrück</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dot"></span>
|
||||
<span>Lieferung optional</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dot"></span>
|
||||
<span>Deckel weiß matt (neu)</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<aside class="qr-box">
|
||||
<div class="qr-header">
|
||||
<p class="qr-title">Reservieren</p>
|
||||
<p class="qr-subtitle">QR scannen</p>
|
||||
</div>
|
||||
<div class="qr-code-wrapper">
|
||||
<img id="qr-code" src="" alt="QR Code">
|
||||
</div>
|
||||
<p class="qr-contact">0521 98620100<br>Tel. oder WhatsApp</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// QR-Code Konfiguration – GOYA Details (gleiche URL wie Slide 1)
|
||||
const QR_URL = 'https://cabinet-bielefeld.de';
|
||||
|
||||
function generateQR(targetUrl) {
|
||||
const size = '300x300';
|
||||
const color = '000000';
|
||||
const bg = 'ffffff';
|
||||
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${size}&color=${color}&bgcolor=${bg}&margin=8&data=${encodeURIComponent(targetUrl)}`;
|
||||
|
||||
const qrImg = document.getElementById('qr-code');
|
||||
if (qrImg) qrImg.src = qrApiUrl;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => generateQR(QR_URL));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
109
public/_cabinet/offers/slide-3-tando.html
Normal file
109
public/_cabinet/offers/slide-3-tando.html
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CABINET – TANDO Spiegel</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./shared-styles.css">
|
||||
<style>
|
||||
/* Slide-spezifische Anpassungen */
|
||||
.hero {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(245,245,245,0.9) 0%, rgba(250,250,250,0.95) 100%);
|
||||
}
|
||||
|
||||
.hero.has-image {
|
||||
background: url('../assets/tango.jpg') center/cover no-repeat;
|
||||
}
|
||||
.impulse-tag {
|
||||
display: inline-block;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 600;
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
margin-top: 12px;
|
||||
letter-spacing: 0.03em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
padding: 16px 28px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="screen">
|
||||
<article class="slide" data-duration="10000">
|
||||
|
||||
<!-- HEADER -->
|
||||
<header class="header">
|
||||
<div class="brand">
|
||||
<img src="./logo-cabinet-300.png" alt="CABINET" class="brand-logo">
|
||||
</div>
|
||||
|
||||
</header>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="hero has-image">
|
||||
<span class="hero-badge">Ausstellungsstück</span>
|
||||
</section>
|
||||
|
||||
<!-- BOTTOM: Info + QR -->
|
||||
<section class="bottom">
|
||||
<div class="info">
|
||||
<div class="info-content">
|
||||
<p class="eyebrow">Nur 1×</p>
|
||||
<h1 class="title large">TANDO Spiegel</h1>
|
||||
<p class="subline">Heute mitnehmen</p>
|
||||
</div>
|
||||
|
||||
<div class="price-block">
|
||||
<div class="price-row">
|
||||
<span class="price">199 €</span>
|
||||
<div class="price-note">
|
||||
<span class="impulse-tag">Im Store verfügbar</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="qr-box">
|
||||
<div class="qr-header">
|
||||
<p class="qr-title">Sichern</p>
|
||||
<p class="qr-subtitle">QR scannen</p>
|
||||
</div>
|
||||
<div class="qr-code-wrapper">
|
||||
<img id="qr-code" src="" alt="QR Code">
|
||||
</div>
|
||||
<p class="qr-contact">0521 98620100<br>Tel. oder WhatsApp</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// QR-Code Konfiguration – TANDO Produkt
|
||||
const QR_URL = 'https://cabinet-bielefeld.de';
|
||||
|
||||
function generateQR(targetUrl) {
|
||||
const size = '300x300';
|
||||
const color = '000000';
|
||||
const bg = 'ffffff';
|
||||
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${size}&color=${color}&bgcolor=${bg}&margin=8&data=${encodeURIComponent(targetUrl)}`;
|
||||
|
||||
const qrImg = document.getElementById('qr-code');
|
||||
if (qrImg) qrImg.src = qrApiUrl;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => generateQR(QR_URL));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue