feat: add section content editing, animation selection and HTML5 drag & drop in live editor
All checks were successful
Production Build & Deploy / build-and-deploy (push) Successful in 1m0s
All checks were successful
Production Build & Deploy / build-and-deploy (push) Successful in 1m0s
This commit is contained in:
@@ -83,16 +83,16 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sektionen Re-Order -->
|
||||
<!-- Sektionen Re-Order mit HTML5 Drag & Drop -->
|
||||
<div class="glass-panel rounded-xl p-4 space-y-3">
|
||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider flex items-center justify-between">
|
||||
<span>Sektionen Reihenfolge (Layout)</span>
|
||||
<span class="text-[10px] text-slate-500 font-mono">Drag & Drop</span>
|
||||
<span class="text-[10px] text-slate-400 font-mono">Drag & Drop</span>
|
||||
</h3>
|
||||
|
||||
<div id="sections-list" class="space-y-2">
|
||||
{siteConfig.sectionsOrder.map((sec, idx) => (
|
||||
<div data-section={sec} draggable="true" class="section-item flex items-center justify-between p-3 rounded-lg bg-slate-900/60 border border-white/5 hover:border-white/20 transition-all group cursor-grab">
|
||||
<div data-section={sec} draggable="true" class="section-item flex items-center justify-between p-3 rounded-lg bg-slate-900/60 border border-white/5 hover:border-sky-400/40 transition-all group cursor-grab active:cursor-grabbing">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-slate-500 font-mono text-xs">#{idx + 1}</span>
|
||||
<span class="text-xs font-semibold capitalize text-white">{sec}</span>
|
||||
@@ -107,6 +107,63 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sektions-Inhalte & Animationen Bearbeiten -->
|
||||
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||
Hero Sektion: Inhalt & Animation
|
||||
</h3>
|
||||
<div class="space-y-3 text-xs">
|
||||
<div>
|
||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Hero Title</label>
|
||||
<input type="text" id="hero-title-input" value={siteConfig.hero.title} 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">Hero Subtitle</label>
|
||||
<textarea id="hero-subtitle-input" 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.hero.subtitle}</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Hero Badge Text</label>
|
||||
<input type="text" id="hero-badge-input" value={siteConfig.hero.badge} 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">Hero Sektion Animation</label>
|
||||
<select id="hero-anim-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="" selected={!siteConfig.hero.animation}>Keine Animation</option>
|
||||
<option value="spring-fade" selected={siteConfig.hero.animation === 'spring-fade'}>Spring Fade (Federleicht)</option>
|
||||
<option value="slide-up" selected={siteConfig.hero.animation === 'slide-up'}>Slide Up (Eingleiten)</option>
|
||||
<option value="zoom-in" selected={siteConfig.hero.animation === 'zoom-in'}>Zoom In (Heranzoomen)</option>
|
||||
<option value="pulse-glow" selected={siteConfig.hero.animation === 'pulse-glow'}>Pulse Glow (Leuchten)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bento Grid: Inhalt & Animation -->
|
||||
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||
Bento Grid: Inhalt & Animation
|
||||
</h3>
|
||||
<div class="space-y-3 text-xs">
|
||||
<div>
|
||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Sektions-Titel</label>
|
||||
<input type="text" id="bento-title-input" value={siteConfig.bento.sectionTitle} 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">Sektions-Untertitel</label>
|
||||
<input type="text" id="bento-subtitle-input" value={siteConfig.bento.sectionSubtitle} 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">Bento Grid Animation</label>
|
||||
<select id="bento-anim-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="" selected={!siteConfig.bento.animation}>Keine Animation</option>
|
||||
<option value="slide-up" selected={siteConfig.bento.animation === 'slide-up'}>Slide Up</option>
|
||||
<option value="spring-fade" selected={siteConfig.bento.animation === 'spring-fade'}>Spring Fade</option>
|
||||
<option value="zoom-in" selected={siteConfig.bento.animation === 'zoom-in'}>Zoom In</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dynamische UIKomponente Hinzufuegen per Sektion -->
|
||||
<div class="glass-panel rounded-xl p-4 space-y-4">
|
||||
<h3 class="text-xs font-bold text-sky-400 uppercase tracking-wider">
|
||||
@@ -150,6 +207,18 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Element Animation</label>
|
||||
<select id="new-el-anim" 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="">Keine Animation</option>
|
||||
<option value="spring-fade">Spring Fade</option>
|
||||
<option value="hover-bounce">Hover Bounce</option>
|
||||
<option value="pulse-glow">Pulse Glow</option>
|
||||
<option value="slide-up">Slide Up</option>
|
||||
<option value="zoom-in">Zoom In</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-[10px] font-bold text-slate-400 uppercase mb-1">Inhalt / Label</label>
|
||||
<input type="text" id="new-el-content" placeholder="z.B. Jetzt Anfragen" class="w-full glass-panel bg-slate-900 rounded-lg p-2 text-xs text-white focus:outline-none focus:border-sky-400" />
|
||||
@@ -180,7 +249,7 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
|
||||
<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 data-id={el.id} draggable="true" class="element-item p-3 rounded-lg bg-slate-900/70 border border-white/10 space-y-2 text-xs group cursor-grab active:cursor-grabbing">
|
||||
<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>
|
||||
@@ -404,11 +473,48 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
renderSectionsList();
|
||||
};
|
||||
|
||||
// --- Drag & Drop for Section Items ---
|
||||
let draggedSecIndex = -1;
|
||||
|
||||
function initSectionDragAndDrop() {
|
||||
const listContainer = document.getElementById('sections-list');
|
||||
if (!listContainer) return;
|
||||
|
||||
const items = listContainer.querySelectorAll('.section-item');
|
||||
items.forEach((item, index) => {
|
||||
item.addEventListener('dragstart', (e) => {
|
||||
draggedSecIndex = index;
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
item.classList.add('opacity-40');
|
||||
});
|
||||
|
||||
item.addEventListener('dragend', () => {
|
||||
item.classList.remove('opacity-40');
|
||||
draggedSecIndex = -1;
|
||||
});
|
||||
|
||||
item.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
});
|
||||
|
||||
item.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
if (draggedSecIndex !== -1 && draggedSecIndex !== index) {
|
||||
const arr = siteConfigState.sectionsOrder;
|
||||
const movedItem = arr.splice(draggedSecIndex, 1)[0];
|
||||
arr.splice(index, 0, movedItem);
|
||||
renderSectionsList();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderSectionsList() {
|
||||
const listContainer = document.getElementById('sections-list');
|
||||
if (!listContainer) return;
|
||||
listContainer.innerHTML = siteConfigState.sectionsOrder.map((sec, idx) => (
|
||||
'<div data-section="' + sec + '" draggable="true" class="section-item flex items-center justify-between p-3 rounded-lg bg-slate-900/60 border border-white/5 hover:border-white/20 transition-all group cursor-grab">' +
|
||||
'<div data-section="' + sec + '" draggable="true" class="section-item flex items-center justify-between p-3 rounded-lg bg-slate-900/60 border border-white/5 hover:border-sky-400/40 transition-all group cursor-grab active:cursor-grabbing">' +
|
||||
'<div class="flex items-center gap-2">' +
|
||||
'<span class="text-slate-500 font-mono text-xs">#' + (idx + 1) + '</span>' +
|
||||
'<span class="text-xs font-semibold capitalize text-white">' + sec + '</span>' +
|
||||
@@ -420,8 +526,13 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
'</div>' +
|
||||
'</div>'
|
||||
)).join('');
|
||||
|
||||
initSectionDragAndDrop();
|
||||
}
|
||||
|
||||
// Initial call for drag and drop setup
|
||||
initSectionDragAndDrop();
|
||||
|
||||
function updateSectionSelectors() {
|
||||
const newElSec = document.getElementById('new-el-section');
|
||||
const filterSec = document.getElementById('filter-section-select');
|
||||
@@ -443,6 +554,7 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
const section = document.getElementById('new-el-section').value;
|
||||
const slotId = document.getElementById('new-el-slot').value;
|
||||
const type = document.getElementById('new-el-type').value;
|
||||
const anim = document.getElementById('new-el-anim').value;
|
||||
const content = document.getElementById('new-el-content').value || 'Neues Element';
|
||||
|
||||
const newComp = {
|
||||
@@ -450,6 +562,7 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
slotId: section + '-' + slotId,
|
||||
type,
|
||||
content,
|
||||
animation0: anim || undefined,
|
||||
style: 'primary'
|
||||
};
|
||||
|
||||
@@ -509,7 +622,7 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
if (countEl) countEl.textContent = els.length;
|
||||
|
||||
container.innerHTML = els.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 data-id="' + el.id + '" draggable="true" class="element-item p-3 rounded-lg bg-slate-900/70 border border-white/10 space-y-2 text-xs group cursor-grab active:cursor-grabbing">' +
|
||||
'<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>' +
|
||||
@@ -544,6 +657,28 @@ const { siteConfig, themeConfig } = loadWaasConfigs(Astro.request.headers.get('u
|
||||
saveBtn.disabled = true;
|
||||
saveBtn.textContent = 'Wird gespeichert...';
|
||||
|
||||
// Collect Hero Section Inputs & Animation
|
||||
const heroTitle = document.getElementById('hero-title-input')?.value;
|
||||
const heroSubtitle = document.getElementById('hero-subtitle-input')?.value;
|
||||
const heroBadge = document.getElementById('hero-badge-input')?.value;
|
||||
const heroAnim = document.getElementById('hero-anim-select')?.value;
|
||||
|
||||
if (!siteConfigState.hero) siteConfigState.hero = {};
|
||||
if (heroTitle !== undefined) siteConfigState.hero.title = heroTitle;
|
||||
if (heroSubtitle !== undefined) siteConfigState.hero.subtitle = heroSubtitle;
|
||||
if (heroBadge !== undefined) siteConfigState.hero.badge = heroBadge;
|
||||
siteConfigState.hero.animation = heroAnim || undefined;
|
||||
|
||||
// Collect Bento Section Inputs & Animation
|
||||
const bentoTitle = document.getElementById('bento-title-input')?.value;
|
||||
const bentoSubtitle = document.getElementById('bento-subtitle-input')?.value;
|
||||
const bentoAnim = document.getElementById('bento-anim-select')?.value;
|
||||
|
||||
if (!siteConfigState.bento) siteConfigState.bento = {};
|
||||
if (bentoTitle !== undefined) siteConfigState.bento.sectionTitle = bentoTitle;
|
||||
if (bentoSubtitle !== undefined) siteConfigState.bento.sectionSubtitle = bentoSubtitle;
|
||||
siteConfigState.bento.animation = bentoAnim || undefined;
|
||||
|
||||
// Collect Header Inputs
|
||||
const brandName = document.getElementById('header-brand-name')?.value;
|
||||
const brandHighlight = document.getElementById('header-brand-highlight')?.value;
|
||||
|
||||
Reference in New Issue
Block a user