Compare commits
3 Commits
c5165547b4
...
eb4bb601d7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb4bb601d7 | ||
|
|
92a75cf289 | ||
|
|
4c165d8107 |
@@ -1,5 +1,13 @@
|
|||||||
---
|
---
|
||||||
// src/components/Footer.astro
|
// src/components/Footer.astro
|
||||||
|
import { loadWaasConfigs } from '../utils/configLoader';
|
||||||
|
|
||||||
|
const { siteConfig } = loadWaasConfigs();
|
||||||
|
const footer = siteConfig.footer || {
|
||||||
|
brandDescription: 'Ihr Partner für professionelles Webdesign, Website-Entwicklung und lokale SEO für Kleinbetriebe & KMU.',
|
||||||
|
copyrightText: 'N&D i-t SOLUTIONS. Alle Rechte vorbehalten.',
|
||||||
|
showLegalLinks: true
|
||||||
|
};
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -10,10 +18,10 @@ const currentYear = new Date().getFullYear();
|
|||||||
<!-- Brand logo/name -->
|
<!-- Brand logo/name -->
|
||||||
<div>
|
<div>
|
||||||
<a href="#" class="text-lg font-bold tracking-wider text-slate-900 dark:text-white">
|
<a href="#" class="text-lg font-bold tracking-wider text-slate-900 dark:text-white">
|
||||||
N&D <span class="text-brand-arcticBlue">i-t SOLUTIONS</span>
|
{siteConfig.header?.brandName || 'N&D'} <span class="text-brand-arcticBlue">{siteConfig.header?.brandHighlight || 'i-t SOLUTIONS'}</span>
|
||||||
</a>
|
</a>
|
||||||
<p class="mt-2 text-xs text-slate-500 dark:text-gray-500 max-w-sm">
|
<p class="mt-2 text-xs text-slate-500 dark:text-gray-500 max-w-sm">
|
||||||
Ihr Partner für professionelles Webdesign, Website-Entwicklung und lokale SEO für Kleinbetriebe & KMU.
|
{footer.brandDescription}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -31,13 +39,15 @@ const currentYear = new Date().getFullYear();
|
|||||||
<!-- Bottom Copyright & Legal Links -->
|
<!-- Bottom Copyright & Legal Links -->
|
||||||
<div class="flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-slate-500 dark:text-gray-500">
|
<div class="flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-slate-500 dark:text-gray-500">
|
||||||
<div>
|
<div>
|
||||||
© {currentYear} N&D i-t SOLUTIONS. Alle Rechte vorbehalten.
|
© {currentYear} {footer.copyrightText}
|
||||||
</div>
|
|
||||||
<div class="flex gap-6">
|
|
||||||
<a href="/privacy" class="hover:text-slate-900 dark:hover:text-white transition-colors">Datenschutz</a>
|
|
||||||
<span class="text-slate-300 dark:text-white/10">|</span>
|
|
||||||
<a href="/privacy#impressum" class="hover:text-slate-900 dark:hover:text-white transition-colors">Impressum</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
{footer.showLegalLinks !== false && (
|
||||||
|
<div class="flex gap-6">
|
||||||
|
<a href="/privacy" class="hover:text-slate-900 dark:hover:text-white transition-colors">Datenschutz</a>
|
||||||
|
<span class="text-slate-300 dark:text-white/10">|</span>
|
||||||
|
<a href="/privacy#impressum" class="hover:text-slate-900 dark:hover:text-white transition-colors">Impressum</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
---
|
---
|
||||||
// src/components/Navbar.astro
|
// src/components/Navbar.astro
|
||||||
import { FaBars, FaTimes } from 'react-icons/fa';
|
import { FaBars, FaTimes } from 'react-icons/fa';
|
||||||
|
import { loadWaasConfigs } from '../utils/configLoader';
|
||||||
|
|
||||||
|
const { siteConfig } = loadWaasConfigs();
|
||||||
|
const header = siteConfig.header || {
|
||||||
|
brandName: 'N&D',
|
||||||
|
brandHighlight: 'i-t SOLUTIONS',
|
||||||
|
ctaText: 'Erstgespräch buchen',
|
||||||
|
ctaLink: '#contact',
|
||||||
|
showThemeToggle: true,
|
||||||
|
glassEffect: true
|
||||||
|
};
|
||||||
---
|
---
|
||||||
|
|
||||||
<header id="main-header" class="fixed top-0 left-0 w-full z-50 transition-all duration-300 py-3 bg-white/30 dark:bg-brand-darkBg/30 backdrop-blur-xl border-b border-slate-200 dark:border-brand-darkBorder">
|
<header id="main-header" class={`fixed top-0 left-0 w-full z-50 transition-all duration-300 py-3 ${header.glassEffect !== false ? 'bg-white/30 dark:bg-brand-darkBg/30 backdrop-blur-xl border-b border-slate-200 dark:border-brand-darkBorder' : 'bg-slate-900 border-b border-white/10'}`}>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex items-center justify-between h-14">
|
<div class="flex items-center justify-between h-14">
|
||||||
|
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<a href="#" class="flex items-center gap-2 group">
|
<a href="#" class="flex items-center gap-2 group">
|
||||||
<span class="text-lg sm:text-xl font-bold tracking-wider text-slate-900 dark:text-white select-none transition-colors duration-300">
|
<span class="text-lg sm:text-xl font-bold tracking-wider text-slate-900 dark:text-white select-none transition-colors duration-300">
|
||||||
N&D <span class="text-brand-arcticBlue">i-t SOLUTIONS</span>
|
{header.brandName || 'N&D'} <span class="text-brand-arcticBlue">{header.brandHighlight || 'i-t SOLUTIONS'}</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@@ -23,22 +34,26 @@ import { FaBars, FaTimes } from 'react-icons/fa';
|
|||||||
|
|
||||||
<!-- Right controls -->
|
<!-- Right controls -->
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<!-- Theme Toggle Button (44x44px target) -->
|
{header.showThemeToggle !== false && (
|
||||||
<button id="theme-toggle" class="w-11 h-11 flex items-center justify-center rounded-lg border border-slate-200 dark:border-brand-darkBorder bg-white/50 dark:bg-zinc-900/50 text-slate-700 dark:text-zinc-400 hover:text-brand-arcticBlue dark:hover:text-brand-arcticBlue transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-sky-500" aria-label="Farbschema wechseln">
|
<!-- Theme Toggle Button (44x44px target) -->
|
||||||
<!-- Moon Icon -->
|
<button id="theme-toggle" class="w-11 h-11 flex items-center justify-center rounded-lg border border-slate-200 dark:border-brand-darkBorder bg-white/50 dark:bg-zinc-900/50 text-slate-700 dark:text-zinc-400 hover:text-brand-arcticBlue dark:hover:text-brand-arcticBlue transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-sky-500" aria-label="Farbschema wechseln">
|
||||||
<svg id="theme-toggle-dark-icon" class="hidden w-4 h-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
<!-- Moon Icon -->
|
||||||
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
<svg id="theme-toggle-dark-icon" class="hidden w-4 h-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||||
</svg>
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
||||||
<!-- Sun Icon -->
|
</svg>
|
||||||
<svg id="theme-toggle-light-icon" class="hidden w-4 h-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
<!-- Sun Icon -->
|
||||||
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.46 5.05l-.707-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" fill-rule="evenodd" clip-rule="evenodd"></path>
|
<svg id="theme-toggle-light-icon" class="hidden w-4 h-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||||
</svg>
|
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.46 5.05l-.707-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" fill-rule="evenodd" clip-rule="evenodd"></path>
|
||||||
</button>
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<!-- CTA button -->
|
<!-- CTA button -->
|
||||||
<a href="#contact" class="hidden sm:inline-flex items-center justify-center px-4 py-2 text-xs font-semibold tracking-wider text-slate-700 dark:text-white border border-slate-200 dark:border-brand-darkBorder rounded bg-white/50 dark:bg-zinc-900/50 hover:border-brand-arcticBlue hover:text-brand-arcticBlue transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-sky-500" aria-label="Erstgespräch buchen">
|
{header.ctaText && (
|
||||||
Erstgespräch buchen
|
<a href={header.ctaLink || "#contact"} class="hidden sm:inline-flex items-center justify-center px-4 py-2 text-xs font-semibold tracking-wider text-slate-700 dark:text-white border border-slate-200 dark:border-brand-darkBorder rounded bg-white/50 dark:bg-zinc-900/50 hover:border-brand-arcticBlue hover:text-brand-arcticBlue transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-sky-500" aria-label={header.ctaText}>
|
||||||
</a>
|
{header.ctaText}
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
|
||||||
<!-- Mobile menu button (44x44px target) -->
|
<!-- Mobile menu button (44x44px target) -->
|
||||||
<button id="mobile-menu-btn" class="md:hidden w-11 h-11 flex items-center justify-center rounded bg-white dark:bg-zinc-900 text-slate-700 dark:text-white border border-slate-200 dark:border-brand-darkBorder hover:bg-slate-50 dark:hover:bg-zinc-800 transition-all focus:outline-none focus:ring-2 focus:ring-sky-500" aria-label="Menü öffnen">
|
<button id="mobile-menu-btn" class="md:hidden w-11 h-11 flex items-center justify-center rounded bg-white dark:bg-zinc-900 text-slate-700 dark:text-white border border-slate-200 dark:border-brand-darkBorder hover:bg-slate-50 dark:hover:bg-zinc-800 transition-all focus:outline-none focus:ring-2 focus:ring-sky-500" aria-label="Menü öffnen">
|
||||||
|
|||||||
@@ -107,19 +107,32 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dynamische UIKomponente Hinzufuegen -->
|
<!-- Dynamische UIKomponente Hinzufuegen per Sektion -->
|
||||||
<div class="glass-panel rounded-xl p-4 space-y-4">
|
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||||
UIKomponente Hinzufuegen
|
UI-Komponente Hinzufuegen & Verwaltungsverzeichnis
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Ziel-Sektion</label>
|
||||||
|
<select id="new-el-section" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400 capitalize">
|
||||||
|
{siteConfig.sectionsOrder.map(sec => (
|
||||||
|
<option value={sec}>{sec} Sektion</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Platz (Slot ID)</label>
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Platz (Slot ID)</label>
|
||||||
<select id="new-el-slot" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400">
|
<select id="new-el-slot" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400">
|
||||||
<option value="hero-badge-slot">Hero Badge Slot</option>
|
<option value="hero-badge-slot">Hero Badge Slot</option>
|
||||||
<option value="hero-actions-slot">Hero Buttons Slot</option>
|
<option value="hero-actions-slot">Hero Buttons Slot</option>
|
||||||
<option value="hero-custom-slot">Hero Custom Elements Slot</option>
|
<option value="hero-custom-slot">Hero Custom Elements Slot</option>
|
||||||
|
<option value="bento-header-slot">Bento Header Slot</option>
|
||||||
|
<option value="bento-grid-slot">Bento Grid Elements Slot</option>
|
||||||
|
<option value="contact-form-slot">Contact Form Slot</option>
|
||||||
|
<option value="section-custom-slot">Allgemeiner Sektions-Slot</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -143,35 +156,59 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" id="add-el-btn" class="w-full py-2.5 rounded-lg bg-sky-400/20 text-sky-400 border border-sky-400/30 font-bold text-xs uppercase tracking-wider hover:bg-sky-400 hover:text-slate-950 transition-all">
|
<button type="button" id="add-el-btn" class="w-full py-2.5 rounded-lg bg-sky-400/20 text-sky-400 border border-sky-400/30 font-bold text-xs uppercase tracking-wider hover:bg-sky-400 hover:text-slate-950 transition-all">
|
||||||
+ Komponente auf Platz platzieren
|
+ Komponente in Sektion platzieren
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Elements List in Active Config -->
|
<!-- Component Manager per Section (Positionieren, Bearbeiten, Loeschen) -->
|
||||||
<div class="glass-panel rounded-xl p-4 space-y-3">
|
<div class="glass-panel rounded-xl p-4 space-y-3">
|
||||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider flex items-center justify-between">
|
||||||
Element-Container (<span id="elements-count">{siteConfig.hero.elements?.length || 0}</span>)
|
<span>Sektions-Komponenten (<span id="elements-count">{(siteConfig.hero.elements || []).length}</span>)</span>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="elements-container" class="space-y-2 max-h-60 overflow-y-auto pr-1">
|
|
||||||
{((siteConfig.hero.elements || [])).map((el) => (
|
<!-- Dynamic Filter per Section -->
|
||||||
<div class="p-2.5 rounded-lg bg-slate-900/60 border border-white/5 flex items-center justify-between text-xs">
|
<div class="flex items-center gap-2 mb-2">
|
||||||
<div>
|
<label class="text-[10px] text-slate-400 uppercase font-bold">Filter:</label>
|
||||||
<span class="font-bold text-sky-400 uppercase text-[10px] block">{el.type} (Platz: {el.slotId})</span>
|
<select id="filter-section-select" class="flex-1 glass-panel bg-slate-900 rounded p-1 text-xs text-white capitalize">
|
||||||
<span class="text-slate-300">{el.content}</span>
|
<option value="all">Alle Sektionen</option>
|
||||||
|
{siteConfig.sectionsOrder.map(sec => (
|
||||||
|
<option value={sec}>{sec}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="elements-container" class="space-y-2 max-h-80 overflow-y-auto pr-1 custom-scroll">
|
||||||
|
{((siteConfig.hero.elements || [])).map((el, idx) => (
|
||||||
|
<div data-id={el.id} class="p-3 rounded-lg bg-slate-900/70 border border-white/10 space-y-2 text-xs group">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<span class="font-bold text-sky-400 uppercase text-[10px] block">{el.type} (Slot: {el.slotId})</span>
|
||||||
|
<span id={`el-label-${el.id}`} class="text-slate-200 font-semibold">{el.content}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<button type="button" onclick={`moveElement('${el.id}', -1)`} class="p-1 hover:text-sky-400 text-xs font-bold" title="Nach oben verschieben">Up</button>
|
||||||
|
<button type="button" onclick={`moveElement('${el.id}', 1)`} class="p-1 hover:text-sky-400 text-xs font-bold" title="Nach unten verschieben">Down</button>
|
||||||
|
<button type="button" onclick={`deleteElement('${el.id}')`} class="p-1 text-red-400/80 hover:text-red-400 text-xs font-bold ml-1" title="Komponente loeschen">Trash</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Inline Edit Form -->
|
||||||
|
<div class="pt-2 border-t border-white/5 flex gap-2">
|
||||||
|
<input type="text" id={`edit-input-${el.id}`} value={el.content} class="flex-1 glass-panel bg-slate-950 rounded px-2 py-1 text-xs text-white border border-white/10 focus:border-sky-400" />
|
||||||
|
<button type="button" onclick={`updateElementContent('${el.id}')`} class="px-2 py-1 rounded bg-sky-400/20 text-sky-400 border border-sky-400/30 text-[10px] font-bold hover:bg-sky-400 hover:text-slate-950 transition-all">Save</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-[9px] font-mono text-slate-500 bg-white/5 px-2 py-0.5 rounded">ID: {el.id}</span>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TAB 2: STIL (Layout, Typographie, Farbung & Glows) -->
|
<!-- TAB 2: STIL (Layout, Header, Footer & Glassmorphism) -->
|
||||||
<div id="tab-panel-style" class="hidden space-y-6">
|
<div id="tab-panel-style" class="hidden space-y-6">
|
||||||
|
<!-- Glassmorphism & Theme Styles -->
|
||||||
<div class="glass-panel rounded-xl p-4 space-y-4">
|
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||||
Globales Farbtheme & Styling
|
Glassmorphism & Theme Presets
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
@@ -184,16 +221,64 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Glass Backdrop Blur</label>
|
||||||
|
<select id="style-blur-select" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400">
|
||||||
|
<option value="blur-sm">Subtle (blur-sm 4px)</option>
|
||||||
|
<option value="blur-md">Medium (blur-md 8px)</option>
|
||||||
|
<option value="blur-xl" selected>Ultra Glass (blur-xl 20px)</option>
|
||||||
|
<option value="blur-3xl">Max Aurora (blur-3xl 60px)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Glass Border Radius</label>
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Glass Border Radius</label>
|
||||||
<select id="style-radius-select" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400">
|
<select id="style-radius-select" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400">
|
||||||
<option value="rounded-lg">Medium (12px)</option>
|
<option value="rounded-lg">Medium (12px)</option>
|
||||||
<option value="rounded-xl">Large (16px)</option>
|
<option value="rounded-xl" selected>Large (16px)</option>
|
||||||
<option value="rounded-2xl">Extra Large (24px)</option>
|
<option value="rounded-2xl">Extra Large (24px)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Header Bearbeiten -->
|
||||||
|
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||||
|
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||||
|
Header & Navigation Bearbeiten
|
||||||
|
</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Marken-Name / Logo</label>
|
||||||
|
<input type="text" id="header-brand-name" value={siteConfig.header?.brandName || 'N&D'} class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Marken Highlight</label>
|
||||||
|
<input type="text" id="header-brand-highlight" value={siteConfig.header?.brandHighlight || 'i-t SOLUTIONS'} class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">CTA Button Text</label>
|
||||||
|
<input type="text" id="header-cta-text" value={siteConfig.header?.ctaText || 'Erstgespräch buchen'} class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer Bearbeiten -->
|
||||||
|
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||||
|
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||||
|
Footer & Reconstitution Bearbeiten
|
||||||
|
</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Footer Beschreibung</label>
|
||||||
|
<textarea id="footer-description" class="w-full h-16 glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400">{siteConfig.footer?.brandDescription || 'Ihr Partner für professionelles Webdesign.'}</textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Copyright Text</label>
|
||||||
|
<input type="text" id="footer-copyright" value={siteConfig.footer?.copyrightText || 'N&D i-t SOLUTIONS. Alle Rechte vorbehalten.'} class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TAB 3: ERWEITERT (Animationen, Custom CSS & Z_index) -->
|
<!-- TAB 3: ERWEITERT (Animationen, Custom CSS & Z_index) -->
|
||||||
@@ -236,6 +321,8 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
let siteConfigState = JSON.parse(siteConfigJSON);
|
let siteConfigState = JSON.parse(siteConfigJSON);
|
||||||
let themeConfigState = JSON.parse(themeConfigJSON);
|
let themeConfigState = JSON.parse(themeConfigJSON);
|
||||||
|
|
||||||
|
if (!siteConfigState.hero.elements) siteConfigState.hero.elements = [];
|
||||||
|
|
||||||
function reloadIframe() {
|
function reloadIframe() {
|
||||||
const iframe = document.getElementById('preview-iframe');
|
const iframe = document.getElementById('preview-iframe');
|
||||||
if (iframe) iframe.src = iframe.src;
|
if (iframe) iframe.src = iframe.src;
|
||||||
@@ -290,6 +377,7 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
if (!siteConfigState.sectionsOrder.includes(newSec)) {
|
if (!siteConfigState.sectionsOrder.includes(newSec)) {
|
||||||
siteConfigState.sectionsOrder.push(newSec);
|
siteConfigState.sectionsOrder.push(newSec);
|
||||||
renderSectionsList();
|
renderSectionsList();
|
||||||
|
updateSectionSelectors();
|
||||||
} else {
|
} else {
|
||||||
alert('Sektion ist bereits im Layout enthalten!');
|
alert('Sektion ist bereits im Layout enthalten!');
|
||||||
}
|
}
|
||||||
@@ -299,6 +387,7 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
window.deleteSection = function(secName) {
|
window.deleteSection = function(secName) {
|
||||||
siteConfigState.sectionsOrder = siteConfigState.sectionsOrder.filter(s => s !== secName);
|
siteConfigState.sectionsOrder = siteConfigState.sectionsOrder.filter(s => s !== secName);
|
||||||
renderSectionsList();
|
renderSectionsList();
|
||||||
|
updateSectionSelectors();
|
||||||
};
|
};
|
||||||
|
|
||||||
window.moveSection = function(secName, dir) {
|
window.moveSection = function(secName, dir) {
|
||||||
@@ -333,43 +422,109 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
)).join('');
|
)).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSectionSelectors() {
|
||||||
|
const newElSec = document.getElementById('new-el-section');
|
||||||
|
const filterSec = document.getElementById('filter-section-select');
|
||||||
|
if (newElSec) {
|
||||||
|
newElSec.innerHTML = siteConfigState.sectionsOrder.map(s => '<option value="' + s + '">' + s + ' Sektion</option>').join('');
|
||||||
|
}
|
||||||
|
if (filterSec) {
|
||||||
|
const current = filterSec.value;
|
||||||
|
filterSec.innerHTML = '<option value="all">Alle Sektionen</option>' + siteConfigState.sectionsOrder.map(s => '<option value="' + s + '">' + s + '</option>').join('');
|
||||||
|
filterSec.value = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- UIComponent Management: Add, Edit, Delete, Position ---
|
||||||
|
|
||||||
const addBtn = document.getElementById('add-el-btn');
|
const addBtn = document.getElementById('add-el-btn');
|
||||||
if (addBtn) {
|
if (addBtn) {
|
||||||
addBtn.addEventListener('click', () => {
|
addBtn.addEventListener('click', () => {
|
||||||
|
const section = document.getElementById('new-el-section').value;
|
||||||
const slotId = document.getElementById('new-el-slot').value;
|
const slotId = document.getElementById('new-el-slot').value;
|
||||||
const type = document.getElementById('new-el-type').value;
|
const type = document.getElementById('new-el-type').value;
|
||||||
const content = document.getElementById('new-el-content').value || 'Neues Element';
|
const content = document.getElementById('new-el-content').value || 'Neues Element';
|
||||||
|
|
||||||
if (!siteConfigState.hero.elements) {
|
const newComp = {
|
||||||
siteConfigState.hero.elements = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
siteConfigState.hero.elements.push({
|
|
||||||
id: 'el-' + Date.now(),
|
id: 'el-' + Date.now(),
|
||||||
slotId,
|
slotId: section + '-' + slotId,
|
||||||
type,
|
type,
|
||||||
content,
|
content,
|
||||||
style: 'primary'
|
style: 'primary'
|
||||||
});
|
};
|
||||||
|
|
||||||
|
siteConfigState.hero.elements.push(newComp);
|
||||||
document.getElementById('new-el-content').value = '';
|
document.getElementById('new-el-content').value = '';
|
||||||
renderElementsContainer();
|
renderElementsContainer();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.deleteElement = function(elId) {
|
||||||
|
siteConfigState.hero.elements = siteConfigState.hero.elements.filter(e => e.id !== elId);
|
||||||
|
renderElementsContainer();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.moveElement = function(elId, dir) {
|
||||||
|
const arr = siteConfigState.hero.elements;
|
||||||
|
const idx = arr.findIndex(e => e.id === elId);
|
||||||
|
if (idx === -1) return;
|
||||||
|
const targetIdx = idx + dir;
|
||||||
|
if (targetIdx < 0 || targetIdx >= arr.length) return;
|
||||||
|
|
||||||
|
const temp = arr[idx];
|
||||||
|
arr[idx] = arr[targetIdx];
|
||||||
|
arr[targetIdx] = temp;
|
||||||
|
|
||||||
|
renderElementsContainer();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.updateElementContent = function(elId) {
|
||||||
|
const input = document.getElementById('edit-input-' + elId);
|
||||||
|
if (!input) return;
|
||||||
|
const el = siteConfigState.hero.elements.find(e => e.id === elId);
|
||||||
|
if (el) {
|
||||||
|
el.content = input.value;
|
||||||
|
const label = document.getElementById('el-label-' + elId);
|
||||||
|
if (label) label.textContent = input.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterSecSelect = document.getElementById('filter-section-select');
|
||||||
|
if (filterSecSelect) {
|
||||||
|
filterSecSelect.addEventListener('change', renderElementsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
function renderElementsContainer() {
|
function renderElementsContainer() {
|
||||||
const container = document.getElementById('elements-container');
|
const container = document.getElementById('elements-container');
|
||||||
const countEl = document.getElementById('elements-count');
|
const countEl = document.getElementById('elements-count');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
const els = siteConfigState.hero.elements || [];
|
|
||||||
|
const filterSec = filterSecSelect ? filterSecSelect.value : 'all';
|
||||||
|
let els = siteConfigState.hero.elements || [];
|
||||||
|
|
||||||
|
if (filterSec !== 'all') {
|
||||||
|
els = els.filter(e => e.slotId && e.slotId.startsWith(filterSec));
|
||||||
|
}
|
||||||
|
|
||||||
if (countEl) countEl.textContent = els.length;
|
if (countEl) countEl.textContent = els.length;
|
||||||
container.innerHTML = els.map(el => (
|
|
||||||
'<div class="p-2.5 rounded-lg bg-slate-900/60 border border-white/5 flex items-center justify-between text-xs">' +
|
container.innerHTML = els.map((el, idx) => (
|
||||||
'<div>' +
|
'<div data-id="' + el.id + '" class="p-3 rounded-lg bg-slate-900/70 border border-white/10 space-y-2 text-xs group">' +
|
||||||
'<span class="font-bold text-sky-400 uppercase text-[10px] block">' + el.type + ' (Platz: ' + el.slotId + ')</span>' +
|
'<div class="flex items-center justify-between">' +
|
||||||
'<span class="text-slate-300">' + el.content + '</span>' +
|
'<div>' +
|
||||||
|
'<span class="font-bold text-sky-400 uppercase text-[10px] block">' + el.type + ' (Slot: ' + el.slotId + ')</span>' +
|
||||||
|
'<span id="el-label-' + el.id + '" class="text-slate-200 font-semibold">' + el.content + '</span>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="flex items-center gap-1">' +
|
||||||
|
'<button type="button" onclick="moveElement(\'' + el.id + '\', -1)" class="p-1 hover:text-sky-400 text-xs font-bold" title="Nach oben">Up</button>' +
|
||||||
|
'<button type="button" onclick="moveElement(\'' + el.id + '\', 1)" class="p-1 hover:text-sky-400 text-xs font-bold" title="Nach unten">Down</button>' +
|
||||||
|
'<button type="button" onclick="deleteElement(\'' + el.id + '\')" class="p-1 text-red-400/80 hover:text-red-400 text-xs font-bold ml-1" title="Loeschen">Trash</button>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="pt-2 border-t border-white/5 flex gap-2">' +
|
||||||
|
'<input type="text" id="edit-input-' + el.id + '" value="' + el.content.replace(/"/g, '"') + '" class="flex-1 glass-panel bg-slate-950 rounded px-2 py-1 text-xs text-white border border-white/10 focus:border-sky-400" />' +
|
||||||
|
'<button type="button" onclick="updateElementContent(\'' + el.id + '\')" class="px-2 py-1 rounded bg-sky-400/20 text-sky-400 border border-sky-400/30 text-[10px] font-bold hover:bg-sky-400 hover:text-slate-950 transition-all">Save</button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<span class="text-[9px] font-mono text-slate-500 bg-white/5 px-2 py-0.5 rounded">' + 'ID: ' + el.id + '</span>' +
|
|
||||||
'</div>'
|
'</div>'
|
||||||
)).join('');
|
)).join('');
|
||||||
}
|
}
|
||||||
@@ -389,6 +544,24 @@ const { siteConfig, themeConfig } = loadWaasConfigs();
|
|||||||
saveBtn.disabled = true;
|
saveBtn.disabled = true;
|
||||||
saveBtn.textContent = 'Wird gespeichert...';
|
saveBtn.textContent = 'Wird gespeichert...';
|
||||||
|
|
||||||
|
// Collect Header Inputs
|
||||||
|
const brandName = document.getElementById('header-brand-name')?.value;
|
||||||
|
const brandHighlight = document.getElementById('header-brand-highlight')?.value;
|
||||||
|
const ctaText = document.getElementById('header-cta-text')?.value;
|
||||||
|
|
||||||
|
if (!siteConfigState.header) siteConfigState.header = {};
|
||||||
|
if (brandName !== undefined) siteConfigState.header.brandName = brandName;
|
||||||
|
if (brandHighlight !== undefined) siteConfigState.header.brandHighlight = brandHighlight;
|
||||||
|
if (ctaText !== undefined) siteConfigState.header.ctaText = ctaText;
|
||||||
|
|
||||||
|
// Collect Footer Inputs
|
||||||
|
const footerDesc = document.getElementById('footer-description')?.value;
|
||||||
|
const footerCopy = document.getElementById('footer-copyright')?.value;
|
||||||
|
|
||||||
|
if (!siteConfigState.footer) siteConfigState.footer = {};
|
||||||
|
if (footerDesc !== undefined) siteConfigState.footer.brandDescription = footerDesc;
|
||||||
|
if (footerCopy !== undefined) siteConfigState.footer.copyrightText = footerCopy;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fetch('/api/update-config', {
|
await fetch('/api/update-config', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -24,6 +24,19 @@ export interface SectionConfig {
|
|||||||
export interface SiteConfig {
|
export interface SiteConfig {
|
||||||
siteName: string;
|
siteName: string;
|
||||||
metaDescription: string;
|
metaDescription: string;
|
||||||
|
header?: {
|
||||||
|
brandName?: string;
|
||||||
|
brandHighlight?: string;
|
||||||
|
ctaText?: string;
|
||||||
|
ctaLink?: string;
|
||||||
|
showThemeToggle?: boolean;
|
||||||
|
glassEffect?: boolean;
|
||||||
|
};
|
||||||
|
footer?: {
|
||||||
|
brandDescription?: string;
|
||||||
|
copyrightText?: string;
|
||||||
|
showLegalLinks?: boolean;
|
||||||
|
};
|
||||||
hero: {
|
hero: {
|
||||||
badge: string;
|
badge: string;
|
||||||
title: string;
|
title: string;
|
||||||
@@ -59,6 +72,9 @@ export interface SiteConfig {
|
|||||||
|
|
||||||
export interface ThemeConfig {
|
export interface ThemeConfig {
|
||||||
activePreset: string;
|
activePreset: string;
|
||||||
|
glassBlur?: string; // 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
|
||||||
|
glassOpacity?: number; // 0.1 to 0.9
|
||||||
|
glassBorderRadius?: string; // 'rounded-lg' | 'rounded-xl' | 'rounded-2xl'
|
||||||
customColors?: {
|
customColors?: {
|
||||||
bg?: string;
|
bg?: string;
|
||||||
accent?: string;
|
accent?: string;
|
||||||
@@ -79,6 +95,19 @@ export interface SmtpConfig {
|
|||||||
export const FALLBACK_SITE_CONFIG: SiteConfig = {
|
export const FALLBACK_SITE_CONFIG: SiteConfig = {
|
||||||
siteName: 'N&D IT Solutions',
|
siteName: 'N&D IT Solutions',
|
||||||
metaDescription: 'High-Performance Webdesign & Digital Solutions - 100% DSGVO-konform.',
|
metaDescription: 'High-Performance Webdesign & Digital Solutions - 100% DSGVO-konform.',
|
||||||
|
header: {
|
||||||
|
brandName: 'N&D',
|
||||||
|
brandHighlight: 'i-t SOLUTIONS',
|
||||||
|
ctaText: 'Erstgespräch buchen',
|
||||||
|
ctaLink: '#contact',
|
||||||
|
showThemeToggle: true,
|
||||||
|
glassEffect: true
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
brandDescription: 'Ihr Partner für professionelles Webdesign, Website-Entwicklung und lokale SEO für Kleinbetriebe & KMU.',
|
||||||
|
copyrightText: 'N&D i-t SOLUTIONS. Alle Rechte vorbehalten.',
|
||||||
|
showLegalLinks: true
|
||||||
|
},
|
||||||
hero: {
|
hero: {
|
||||||
badge: ' Waas Enterprise Baukastensystem',
|
badge: ' Waas Enterprise Baukastensystem',
|
||||||
title: 'Maßgeschneiderte Webseiten. Digital im Griff.',
|
title: 'Maßgeschneiderte Webseiten. Digital im Griff.',
|
||||||
@@ -88,8 +117,8 @@ export const FALLBACK_SITE_CONFIG: SiteConfig = {
|
|||||||
ctaSecondaryText: 'Mehr erfahren',
|
ctaSecondaryText: 'Mehr erfahren',
|
||||||
ctaSecondaryLink: '#services',
|
ctaSecondaryLink: '#services',
|
||||||
elements: [
|
elements: [
|
||||||
{ id: 'el-1', type: 'badge', content: ' WaaS Engine' },
|
{ id: 'el-1', slotId: 'hero-badge-slot', type: 'badge', content: 'WaaS Engine' },
|
||||||
{ id: 'el-2', type: 'button', content: 'Neuer Button', link: '#contact', animation0: 'spring-fade', style: 'primary' }
|
{ id: 'el-2', slotId: 'hero-actions-slot', type: 'button', content: 'Neuer Button', link: '#contact', animation0: 'spring-fade', style: 'primary' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
bento: {
|
bento: {
|
||||||
@@ -115,7 +144,7 @@ export const FALLBACK_SITE_CONFIG: SiteConfig = {
|
|||||||
{
|
{
|
||||||
id: 'card-3',
|
id: 'card-3',
|
||||||
title: 'Liquid Glass UI',
|
title: 'Liquid Glass UI',
|
||||||
description: 'Moderne <EFBFBD> sthetik mit matte Boxen, Aurora Glows und physikalischen Kanten-Effekten.',
|
description: 'Moderne Ästhetik mit matte Boxen, Aurora Glows und physikalischen Kanten-Effekten.',
|
||||||
colSpan: 1,
|
colSpan: 1,
|
||||||
badge: 'Design',
|
badge: 'Design',
|
||||||
icon: 'layers'
|
icon: 'layers'
|
||||||
@@ -132,14 +161,14 @@ export const FALLBACK_SITE_CONFIG: SiteConfig = {
|
|||||||
},
|
},
|
||||||
contact: {
|
contact: {
|
||||||
title: 'Bereit für Ihr Projekt?',
|
title: 'Bereit für Ihr Projekt?',
|
||||||
subtitle: 'Schreiben Sie uns direkt. Wir antworten innerhalb von 24 Stunden persúnlich.',
|
subtitle: 'Schreiben Sie uns direkt. Wir antworten innerhalb von 24 Stunden persönlich.',
|
||||||
recipientEmail: 'kontakt@ndsolutions.de',
|
recipientEmail: 'kontakt@ndsolutions.de',
|
||||||
phone: '+49 (0) 123 456789',
|
phone: '+49 (0) 123 456789',
|
||||||
address: 'Deutschland'
|
address: 'Deutschland'
|
||||||
},
|
},
|
||||||
sectionsOrder: ['hero', 'bento', 'contact'],
|
sectionsOrder: ['hero', 'bento', 'contact'],
|
||||||
sectionsDetails: [
|
sectionsDetails: [
|
||||||
{ id: 'hero', type: 'hero', title: 'Hero Sektion', elements: [ {id: 'el-1', type: 'badge', content: ' WaaS Engine' } ] },
|
{ id: 'hero', type: 'hero', title: 'Hero Sektion', elements: [ { id: 'el-1', slotId: 'hero-badge-slot', type: 'badge', content: 'WaaS Engine' } ] },
|
||||||
{ id: 'bento', type: 'bento', title: 'Bento Grid', elements: [] },
|
{ id: 'bento', type: 'bento', title: 'Bento Grid', elements: [] },
|
||||||
{ id: 'contact', type: 'contact', title: 'Contact Section', elements: [] }
|
{ id: 'contact', type: 'contact', title: 'Contact Section', elements: [] }
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user