feature/ui-ux-modernization #1

Merged
vmiller merged 4 commits from feature/ui-ux-modernization into main 2026-02-12 14:35:22 +00:00
7 changed files with 653 additions and 148 deletions

View File

@@ -27,6 +27,123 @@
--umzug-transition: 0.2s ease;
}
/* ===== Color Palettes ===== */
/* Palette A: Deep Teal — Grounded Confidence */
.palette-a.umzugsliste-wizard {
--umzug-primary: #1F7A7A;
--umzug-primary-light: rgba(31, 122, 122, 0.2);
--umzug-primary-dark: #155858;
--umzug-success: #4A7C59;
--umzug-success-light: rgba(74, 124, 89, 0.1);
--umzug-error: #C14E3A;
--umzug-error-light: #FCEAE6;
--umzug-bg: #FAF8F5;
--umzug-surface: #FFFFFF;
--umzug-border: #D4CEC4;
--umzug-text: #3E2E28;
--umzug-text-secondary: #6B5D56;
}
.palette-a .room-totals {
background: #F5F2ED;
}
.palette-a .wizard-btn-back:hover {
background: #F2EFEA;
color: var(--umzug-text);
}
.palette-a .wizard-btn-submit:hover {
background: #3D6A4A;
}
body.umzugsliste-standalone:has(.palette-a) {
background: #FAF8F5;
}
/* Palette B: Slate Blue & Amber — Modern Logistics */
.palette-b.umzugsliste-wizard {
--umzug-primary: #4A6FA5;
--umzug-primary-light: rgba(74, 111, 165, 0.2);
--umzug-primary-dark: #2F4668;
--umzug-success: #52A07B;
--umzug-success-light: rgba(82, 160, 123, 0.1);
--umzug-error: #D15847;
--umzug-error-light: #FDEAE8;
--umzug-bg: #F5F7FA;
--umzug-surface: #FFFFFF;
--umzug-border: #D8DFE8;
--umzug-text: #1A2332;
--umzug-text-secondary: #5F6B7A;
}
.palette-b .room-totals {
background: #EDF0F5;
}
.palette-b .wizard-btn-back:hover {
background: #ECEFF4;
color: var(--umzug-text);
}
.palette-b .wizard-btn-submit:hover {
background: #448A69;
}
.palette-b .wizard-btn-next {
background: #E8A63C;
}
.palette-b .wizard-btn-next:hover {
background: #D69529;
}
body.umzugsliste-standalone:has(.palette-b) {
background: #F5F7FA;
}
/* Palette C: Rich Olive & Copper — Heritage & Motion */
.palette-c.umzugsliste-wizard {
--umzug-primary: #5C6E54;
--umzug-primary-light: rgba(92, 110, 84, 0.2);
--umzug-primary-dark: #3D4738;
--umzug-success: #6B9F6F;
--umzug-success-light: rgba(107, 159, 111, 0.1);
--umzug-error: #B85A3D;
--umzug-error-light: #F8EDE8;
--umzug-bg: #F8F6F1;
--umzug-surface: #FEFDFB;
--umzug-border: #D9D3C8;
--umzug-text: #2F3126;
--umzug-text-secondary: #6B6E64;
}
.palette-c .room-totals {
background: #F0EDE6;
}
.palette-c .wizard-btn-back:hover {
background: #F0EDE6;
color: var(--umzug-text);
}
.palette-c .wizard-btn-submit:hover {
background: #5A8A5E;
}
.palette-c .wizard-btn-next {
background: #C17E5D;
}
.palette-c .wizard-btn-next:hover {
background: #A96A4B;
}
body.umzugsliste-standalone:has(.palette-c) {
background: #F8F6F1;
}
/* ===== Reset & Base ===== */
.umzugsliste-standalone {
margin: 0;
@@ -132,7 +249,7 @@
font-size: 0.8rem;
font-weight: 600;
color: var(--umzug-text-secondary);
transition: all var(--umzug-transition);
transition: background var(--umzug-transition), border-color var(--umzug-transition), color var(--umzug-transition);
}
.dot-label {
@@ -167,6 +284,14 @@
font-size: 0;
}
/* ===== Step Counter ===== */
.progress-counter {
text-align: center;
font-size: 0.8rem;
color: var(--umzug-text-secondary);
margin-bottom: 16px;
}
/* ===== Running Totals Bar ===== */
.running-totals {
position: sticky;
@@ -175,17 +300,24 @@
right: 0;
z-index: 100;
background: var(--umzug-surface);
border-top: 3px solid var(--umzug-primary);
border: 1px solid var(--umzug-border);
border-radius: var(--umzug-radius);
padding: 12px 20px;
margin-bottom: 12px;
text-align: center;
font-size: 0.95rem;
font-weight: 500;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
display: none;
box-shadow: var(--umzug-shadow-lg);
transform: translateY(100%);
opacity: 0;
transition: transform 0.3s, opacity 0.3s;
pointer-events: none;
}
.running-totals.visible {
display: block;
transform: translateY(0);
opacity: 1;
pointer-events: auto;
}
.running-totals-label {
@@ -219,10 +351,30 @@
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideInForward {
from { opacity: 0; transform: translateX(30px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes slideInBackward {
from { opacity: 0; transform: translateX(-30px); }
to { opacity: 1; transform: translateX(0); }
}
.wizard-step.active.forward {
animation: slideInForward 0.3s ease;
}
.wizard-step.active.backward {
animation: slideInBackward 0.3s ease;
}
.step-title {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 20px;
margin: 0 0 16px;
padding-bottom: 12px;
border-bottom: 1px solid var(--umzug-border);
color: var(--umzug-text);
}
@@ -245,6 +397,32 @@
border-bottom: 1px solid var(--umzug-border);
}
/* ===== Step Sections (inner dividers within a step-card) ===== */
.step-section {
padding-top: 16px;
margin-top: 16px;
border-top: 1px solid var(--umzug-border);
}
.step-section:first-of-type {
border-top: none;
padding-top: 0;
margin-top: 0;
}
/* ===== Address Sections (grid items within step-card) ===== */
.address-section {
background: var(--umzug-surface);
border: 1px solid var(--umzug-border);
border-radius: var(--umzug-radius);
padding: 16px 20px;
}
/* Summary sections inside step-card: lighter treatment */
.step-card #wizard-summary .summary-section {
box-shadow: none;
}
/* ===== Date Selector ===== */
.date-selector {
display: flex;
@@ -287,7 +465,7 @@
font-size: 0.8rem;
color: var(--umzug-text-secondary);
margin-top: 12px;
margin-bottom: 0;
margin-bottom: 16px;
}
.privacy-note a {
@@ -394,27 +572,78 @@
gap: 12px;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
opacity: 0.55;
transition: opacity 0.2s;
}
.furniture-item.has-quantity,
.furniture-item:hover,
.furniture-item:focus-within {
opacity: 1;
}
.furniture-item .montage-toggle {
display: none;
}
.furniture-item.has-quantity .montage-toggle {
display: flex;
}
.furniture-item:last-of-type {
border-bottom: none;
}
.quantity-input {
width: 56px;
height: 36px;
padding: 0 8px;
.quantity-stepper {
display: inline-flex;
align-items: center;
border: 1px solid var(--umzug-border);
border-radius: var(--umzug-radius-sm);
border-radius: var(--umzug-radius);
overflow: hidden;
flex-shrink: 0;
}
.qty-btn {
width: 36px;
height: 36px;
border: none;
background: var(--umzug-bg);
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background var(--umzug-transition);
color: var(--umzug-text);
padding: 0;
line-height: 1;
}
.qty-btn:hover {
background: var(--umzug-border);
}
.qty-btn:active {
background: var(--umzug-primary-light);
}
.quantity-stepper .quantity-input {
border: none;
border-left: 1px solid var(--umzug-border);
border-right: 1px solid var(--umzug-border);
border-radius: 0;
width: 48px;
height: 36px;
padding: 0 4px;
font-size: 0.95rem;
text-align: center;
flex-shrink: 0;
color: var(--umzug-text);
background: var(--umzug-surface);
transition: border-color var(--umzug-transition), box-shadow var(--umzug-transition);
}
.quantity-input:focus {
.quantity-stepper .quantity-input:focus {
outline: none;
border-color: var(--umzug-primary);
box-shadow: 0 0 0 3px var(--umzug-primary-light);
@@ -432,9 +661,9 @@
}
.item-cbm {
width: 52px;
width: 75px;
text-align: right;
font-size: 0.85rem;
font-size: 13px;
color: var(--umzug-text-secondary);
flex-shrink: 0;
}
@@ -446,7 +675,14 @@
}
.montage-toggle .radio-label {
font-size: 0.8rem;
font-size: 13px;
}
.montage-label {
font-size: 13px;
font-weight: 600;
color: var(--umzug-text-secondary);
white-space: nowrap;
}
/* ===== Room Totals ===== */
@@ -547,6 +783,98 @@
box-shadow: 0 0 0 3px var(--umzug-primary-light);
}
/* ===== Step 8 Design ===== */
.additional-field input[type="checkbox"] {
accent-color: var(--umzug-primary);
}
.wizard-step[data-step="8"] .additional-field {
padding: 8px 0;
background: transparent;
border: none;
border-bottom: 1px solid #f0f0f0;
border-radius: 0;
opacity: 0.55;
transition: opacity 0.2s;
}
.wizard-step[data-step="8"] .additional-field:last-child {
border-bottom: none;
}
.wizard-step[data-step="8"] .additional-field:hover,
.wizard-step[data-step="8"] .additional-field:focus-within,
.wizard-step[data-step="8"] .additional-field:has(input:checked),
.wizard-step[data-step="8"] .additional-field:has(.qty-small:not(:placeholder-shown)) {
opacity: 1;
}
.wizard-step[data-step="8"] .additional-field-abbau .radio-group {
display: inline-flex;
gap: 16px;
background: transparent;
border: none;
border-radius: 0;
padding: 0;
}
.wizard-step[data-step="8"] .additional-field-abbau .radio-label {
padding: 0;
font-size: 0.9rem;
}
.wizard-step[data-step="8"] .additional-field-abbau .radio-label input[type="radio"] {
position: static;
opacity: 1;
width: auto;
height: auto;
margin: 0;
}
/* ===== Dev Auto-Fill ===== */
.dev-autofill-btn {
position: fixed;
bottom: 60px;
right: 16px;
z-index: 300;
background: #ff6b35;
color: #fff;
border: none;
border-radius: 20px;
padding: 6px 14px;
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
opacity: 0.6;
transition: opacity var(--umzug-transition);
}
.dev-autofill-btn:hover {
opacity: 1;
}
/* ===== Palette Switcher (WP_DEBUG) ===== */
.dev-palette-btn {
position: fixed;
bottom: 90px;
right: 16px;
z-index: 300;
background: #7c3aed;
color: #fff;
border: none;
border-radius: 20px;
padding: 6px 14px;
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
opacity: 0.6;
transition: opacity var(--umzug-transition);
}
.dev-palette-btn:hover {
opacity: 1;
}
/* ===== Sonstiges ===== */
.sonstiges-textarea {
width: 100%;
@@ -619,7 +947,7 @@
}
#wizard-summary .summary-item-cbm {
width: 60px;
width: 80px;
text-align: right;
color: var(--umzug-text-secondary);
}
@@ -630,6 +958,19 @@
font-size: 0.8rem;
}
.summary-edit {
float: right;
font-size: 0.8rem;
font-weight: 500;
color: var(--umzug-primary);
cursor: pointer;
text-decoration: none;
}
.summary-edit:hover {
text-decoration: underline;
}
#wizard-summary .summary-grand-total {
background: var(--umzug-primary);
color: #fff;
@@ -730,7 +1071,8 @@
flex-basis: calc(100% - 80px);
}
.quantity-input {
.quantity-input,
.quantity-stepper {
order: 2;
}
@@ -745,6 +1087,15 @@
padding-left: 0;
}
.montage-label {
flex-basis: 100%;
margin-bottom: -4px;
}
.wizard-step[data-step="8"] .additional-field {
padding: 6px 0;
}
.additional-field-abbau {
flex-direction: column;
align-items: flex-start;
@@ -769,18 +1120,34 @@
font-size: 0.95rem;
}
.progress-dot {
min-width: 44px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
}
.dot-label {
display: none;
}
.progress-dot.active .dot-label {
display: block;
font-size: 0.6rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.dot-number {
width: 28px;
height: 28px;
width: 36px;
height: 36px;
font-size: 0.7rem;
}
.progress-track {
top: 14px;
top: 18px;
}
}

View File

@@ -48,14 +48,20 @@
function showStep(n) {
if (n < 1 || n > TOTAL_STEPS) return;
// Hide all steps
// Determine direction
var direction = n > currentStep ? 'forward' : 'backward';
// Hide all steps and remove direction classes
qsa('.wizard-step').forEach(function(el) {
el.classList.remove('active');
el.classList.remove('active', 'forward', 'backward');
});
// Show target step
// Show target step with direction
var target = qs('.wizard-step[data-step="' + n + '"]');
if (target) target.classList.add('active');
if (target) {
target.classList.add(direction);
target.classList.add('active');
}
currentStep = n;
if (n > highestStep) highestStep = n;
@@ -103,6 +109,12 @@
var pct = ((highestStep - 1) / (TOTAL_STEPS - 1)) * 100;
fill.style.width = pct + '%';
}
// Update step counter
var counter = qs('#progress-counter');
if (counter) {
counter.textContent = (l10n.stepLabel || 'Step') + ' ' + currentStep + ' ' + (l10n.stepOf || 'of') + ' ' + TOTAL_STEPS;
}
}
function updateNavButtons() {
@@ -271,6 +283,11 @@
// ===== Summary Generation =====
function summaryHeading(text, gotoStep) {
var editLabel = escHtml(l10n.summaryEdit || 'Edit');
return '<h3>' + escHtml(text) + ' <a class="summary-edit" data-goto="' + gotoStep + '" role="button">' + editLabel + '</a></h3>';
}
function generateSummary() {
var container = qs('#wizard-summary');
if (!container) return;
@@ -279,56 +296,56 @@
// Customer info
html += '<div class="summary-section">';
html += '<h3>' + escHtml(l10n.summaryMovingDate || 'Moving Date') + '</h3>';
var day = getFieldVal('day');
var month = getFieldVal('month');
var year = getFieldVal('year');
html += summaryHeading(l10n.summaryMovingDate || 'Moving Date', 1);
var day = getFieldVal('umzug_day');
var month = getFieldVal('umzug_month');
var year = getFieldVal('umzug_year');
html += summaryRow(l10n.summaryMovingDate || 'Moving Date', day + '.' + month + '.' + year);
html += '</div>';
// Loading address
html += '<div class="summary-section">';
html += '<h3>' + escHtml(l10n.summaryLoading || 'Loading Address') + '</h3>';
html += summaryRow('Name', getFieldVal('bName'));
html += summaryRow('Street', getFieldVal('bStrasse'));
html += summaryRow('ZIP/City', getFieldVal('bort'));
html += summaryHeading(l10n.summaryLoading || 'Loading Address', 1);
html += summaryRow(l10n.summaryName || 'Name', getFieldVal('bName'));
html += summaryRow(l10n.summaryStreet || 'Street', getFieldVal('bStrasse'));
html += summaryRow(l10n.summaryZipCity || 'ZIP/City', getFieldVal('bort'));
var bGeschoss = getFieldVal('info[bGeschoss]');
if (bGeschoss) html += summaryRow('Floor', bGeschoss);
html += summaryRow('Elevator', getRadioVal('info[bLift]'));
html += summaryRow('Phone', getFieldVal('bTelefon'));
if (bGeschoss) html += summaryRow(l10n.summaryFloor || 'Floor', bGeschoss);
html += summaryRow(l10n.summaryElevator || 'Elevator', getRadioVal('info[bLift]'));
html += summaryRow(l10n.summaryPhone || 'Phone', getFieldVal('bTelefon'));
var bFax = getFieldVal('info[bTelefax]');
if (bFax) html += summaryRow('Fax', bFax);
if (bFax) html += summaryRow(l10n.summaryFax || 'Fax', bFax);
var bMobil = getFieldVal('info[bMobil]');
if (bMobil) html += summaryRow('Mobile', bMobil);
html += summaryRow('Email', getFieldVal('info[eE-Mail]'));
if (bMobil) html += summaryRow(l10n.summaryMobile || 'Mobile', bMobil);
html += summaryRow(l10n.summaryEmail || 'Email', getFieldVal('info[eE-Mail]'));
html += '</div>';
// Unloading address
html += '<div class="summary-section">';
html += '<h3>' + escHtml(l10n.summaryUnloading || 'Unloading Address') + '</h3>';
html += summaryRow('Name', getFieldVal('eName'));
html += summaryRow('Street', getFieldVal('eStrasse'));
html += summaryRow('ZIP/City', getFieldVal('eort'));
html += summaryHeading(l10n.summaryUnloading || 'Unloading Address', 1);
html += summaryRow(l10n.summaryName || 'Name', getFieldVal('eName'));
html += summaryRow(l10n.summaryStreet || 'Street', getFieldVal('eStrasse'));
html += summaryRow(l10n.summaryZipCity || 'ZIP/City', getFieldVal('eort'));
var eGeschoss = getFieldVal('info[eGeschoss]');
if (eGeschoss) html += summaryRow('Floor', eGeschoss);
html += summaryRow('Elevator', getRadioVal('info[eLift]'));
if (eGeschoss) html += summaryRow(l10n.summaryFloor || 'Floor', eGeschoss);
html += summaryRow(l10n.summaryElevator || 'Elevator', getRadioVal('info[eLift]'));
var eTel = getFieldVal('eTelefon');
if (eTel) html += summaryRow('Phone', eTel);
if (eTel) html += summaryRow(l10n.summaryPhone || 'Phone', eTel);
var eFax = getFieldVal('info[eTelefax]');
if (eFax) html += summaryRow('Fax', eFax);
if (eFax) html += summaryRow(l10n.summaryFax || 'Fax', eFax);
var eMobil = getFieldVal('info[eMobil]');
if (eMobil) html += summaryRow('Mobile', eMobil);
if (eMobil) html += summaryRow(l10n.summaryMobile || 'Mobile', eMobil);
html += '</div>';
// Room summaries
var roomMap = [
{ key: 'wohnzimmer', name: 'Wohnzimmer' },
{ key: 'schlafzimmer', name: 'Schlafzimmer' },
{ key: 'arbeitszimmer', name: 'Arbeitszimmer' },
{ key: 'bad', name: 'Bad' },
{ key: 'kueche_esszimmer', name: 'Kueche_Esszimmer' },
{ key: 'kinderzimmer', name: 'Kinderzimmer' },
{ key: 'keller', name: 'Keller' }
{ key: 'wohnzimmer', name: 'Wohnzimmer', step: 2 },
{ key: 'schlafzimmer', name: 'Schlafzimmer', step: 3 },
{ key: 'arbeitszimmer', name: 'Arbeitszimmer', step: 4 },
{ key: 'bad', name: 'Bad', step: 5 },
{ key: 'kueche_esszimmer', name: 'Kueche_Esszimmer', step: 5 },
{ key: 'kinderzimmer', name: 'Kinderzimmer', step: 6 },
{ key: 'keller', name: 'Keller', step: 7 }
];
roomMap.forEach(function(room) {
@@ -337,12 +354,12 @@
var total = calculateRoomTotal(room.key);
html += '<div class="summary-section">';
html += '<h3>' + escHtml(getRoomDisplayName(room.key)) + '</h3>';
html += summaryHeading(getRoomDisplayName(room.key), room.step);
roomItems.forEach(function(item) {
html += '<div class="summary-item">';
html += '<span class="summary-item-name">' + escHtml(item.name) + '</span>';
html += '<span class="summary-item-qty">' + item.qty + '</span>';
html += '<span class="summary-item-cbm">' + formatGermanDecimal(item.cbm) + '</span>';
html += '<span class="summary-item-cbm">' + formatGermanDecimal(item.cbm) + ' ' + escHtml(l10n.summaryCbm || 'cbm') + '</span>';
if (item.montage !== null) {
html += '<span class="summary-item-montage">' + escHtml(item.montage === 'ja' ? (l10n.summaryYes || 'Yes') : (l10n.summaryNo || 'No')) + '</span>';
}
@@ -368,7 +385,7 @@
var additionalHtml = getAdditionalWorkSummary();
if (additionalHtml) {
html += '<div class="summary-section">';
html += '<h3>' + escHtml(l10n.summaryAdditional || 'Additional Work') + '</h3>';
html += summaryHeading(l10n.summaryAdditional || 'Additional Work', 8);
html += additionalHtml;
html += '</div>';
}
@@ -377,7 +394,7 @@
var sonstiges = getFieldVal('sonstiges');
if (sonstiges) {
html += '<div class="summary-section">';
html += '<h3>' + escHtml(l10n.summaryOther || 'Other') + '</h3>';
html += summaryHeading(l10n.summaryOther || 'Other', 8);
html += '<p>' + escHtml(sonstiges) + '</p>';
html += '</div>';
}
@@ -402,13 +419,19 @@
}
function getRoomDisplayName(roomKey) {
// Read from the step title or the furniture list heading
var list = qs('.furniture-list[data-room="' + roomKey + '"]');
if (list) {
var card = list.closest('.step-card');
if (card) {
var h3 = qs('h3', card);
if (h3) return h3.textContent;
// For combined steps (step 5), use the h3 section heading
var section = list.closest('.step-section');
if (section) {
var h3 = qs('h3', section);
if (h3) return h3.textContent;
}
// For single-room steps, use the h2 step title
var h2 = qs('h2.step-title', card);
if (h2) return h2.textContent;
}
}
return roomKey;
@@ -526,15 +549,47 @@
document.addEventListener('input', function(e) {
if (e.target.classList.contains('quantity-input')) {
handleQuantityChange();
var hasQty = parseGermanDecimal(e.target.value) > 0;
// Toggle has-value class
if (parseGermanDecimal(e.target.value) > 0) {
if (hasQty) {
e.target.classList.add('has-value');
} else {
e.target.classList.remove('has-value');
}
// Toggle has-quantity on parent row for dimming/montage visibility
var row = e.target.closest('.furniture-item');
if (row) row.classList.toggle('has-quantity', hasQty);
}
});
// Auto-check checkbox when qty-small gets a value
document.addEventListener('input', function(e) {
if (!e.target.classList.contains('qty-small')) return;
var field = e.target.closest('.additional-field');
if (!field) return;
var cb = qs('input[type="checkbox"]', field);
if (cb) cb.checked = e.target.value.trim() !== '';
});
// Stepper button click handlers
document.addEventListener('click', function(e) {
var btn = e.target.closest('.qty-btn');
if (!btn) return;
var input = btn.parentNode.querySelector('.quantity-input');
if (!input) return;
var val = parseGermanDecimal(input.value);
if (btn.classList.contains('qty-plus')) val++;
else if (btn.classList.contains('qty-minus') && val > 0) val--;
input.value = val > 0 ? val : '';
input.dispatchEvent(new Event('input', { bubbles: true }));
});
// Summary edit link click handler
document.addEventListener('click', function(e) {
var el = e.target.closest('.summary-edit');
if (el) showStep(parseInt(el.dataset.goto, 10));
});
// Clear field errors on input
document.addEventListener('input', function(e) {
if (e.target.classList.contains('field-error')) {

View File

@@ -46,7 +46,7 @@ class Umzugsliste_Form_Renderer {
ob_start();
?>
<div class="umzugsliste-wizard">
<div class="umzugsliste-wizard palette-b">
<?php self::render_validation_errors(); ?>
<?php self::render_progress_bar( $steps ); ?>
<div class="running-totals" id="running-totals">
@@ -82,6 +82,20 @@ class Umzugsliste_Form_Renderer {
<button type="submit" class="wizard-btn wizard-btn-submit" id="wizard-submit" style="display:none;"><?php echo esc_html__( 'Submit Request', 'siegel-umzugsliste' ); ?></button>
</div>
</form>
<?php if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) : ?>
<button type="button" id="dev-palette-switch" class="dev-palette-btn">&#127912; B</button>
<script>
document.getElementById('dev-palette-switch').addEventListener('click', function() {
var w = document.querySelector('.umzugsliste-wizard');
var p = ['palette-a', 'palette-b', 'palette-c'];
var c = p.findIndex(function(x) { return w.classList.contains(x); });
var n = (c + 1) % p.length;
w.classList.remove(p[c]);
w.classList.add(p[n]);
this.textContent = '\u{1F3A8} ' + p[n].split('-')[1].toUpperCase();
});
</script>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
@@ -134,6 +148,7 @@ class Umzugsliste_Form_Renderer {
<?php endforeach; ?>
</div>
</div>
<div class="progress-counter" id="progress-counter"></div>
<?php
}
@@ -143,9 +158,8 @@ class Umzugsliste_Form_Renderer {
private static function render_step_1() {
?>
<div class="wizard-step active" data-step="1">
<h2 class="step-title"><?php echo esc_html__( 'Moving Date & Addresses', 'siegel-umzugsliste' ); ?></h2>
<div class="step-card">
<h2 class="step-title"><?php echo esc_html__( 'Moving Date & Addresses', 'siegel-umzugsliste' ); ?></h2>
<h3><?php echo esc_html__( 'Expected Moving Date', 'siegel-umzugsliste' ); ?></h3>
<div class="date-selector">
<?php
@@ -160,38 +174,55 @@ class Umzugsliste_Form_Renderer {
'<a href="http://siegel-umzug.de/datenschutz.html" target="_blank" rel="noopener">' . esc_html__( 'Privacy Policy', 'siegel-umzugsliste' ) . '</a>'
);
?></p>
</div>
<div class="address-grid">
<div class="step-card">
<h3><?php echo esc_html__( 'Loading Address', 'siegel-umzugsliste' ); ?></h3>
<?php
self::render_address_field( __( 'Name', 'siegel-umzugsliste' ), 'bName', true );
self::render_address_field( __( 'Street', 'siegel-umzugsliste' ), 'bStrasse', true );
self::render_address_field( __( 'ZIP/City', 'siegel-umzugsliste' ), 'bort', true );
self::render_address_field( __( 'Floor', 'siegel-umzugsliste' ), 'info[bGeschoss]' );
self::render_lift_field( 'info[bLift]' );
self::render_address_field( __( 'Phone', 'siegel-umzugsliste' ), 'bTelefon', true );
self::render_address_field( __( 'Fax', 'siegel-umzugsliste' ), 'info[bTelefax]' );
self::render_address_field( __( 'Mobile', 'siegel-umzugsliste' ), 'info[bMobil]' );
self::render_address_field( __( 'Email', 'siegel-umzugsliste' ), 'info[eE-Mail]', true, 'email' );
?>
</div>
<div class="step-card">
<h3><?php echo esc_html__( 'Unloading Address', 'siegel-umzugsliste' ); ?></h3>
<?php
self::render_address_field( __( 'Name', 'siegel-umzugsliste' ), 'eName', true );
self::render_address_field( __( 'Street', 'siegel-umzugsliste' ), 'eStrasse', true );
self::render_address_field( __( 'ZIP/City', 'siegel-umzugsliste' ), 'eort', true );
self::render_address_field( __( 'Floor', 'siegel-umzugsliste' ), 'info[eGeschoss]' );
self::render_lift_field( 'info[eLift]' );
self::render_address_field( __( 'Phone', 'siegel-umzugsliste' ), 'eTelefon' );
self::render_address_field( __( 'Fax', 'siegel-umzugsliste' ), 'info[eTelefax]' );
self::render_address_field( __( 'Mobile', 'siegel-umzugsliste' ), 'info[eMobil]' );
?>
<div class="address-grid">
<div class="address-section">
<h3><?php echo esc_html__( 'Loading Address', 'siegel-umzugsliste' ); ?></h3>
<?php
self::render_address_field( __( 'Name', 'siegel-umzugsliste' ), 'bName', true );
self::render_address_field( __( 'Street', 'siegel-umzugsliste' ), 'bStrasse', true );
self::render_address_field( __( 'ZIP/City', 'siegel-umzugsliste' ), 'bort', true );
self::render_address_field( __( 'Floor', 'siegel-umzugsliste' ), 'info[bGeschoss]' );
self::render_lift_field( 'info[bLift]' );
self::render_address_field( __( 'Phone', 'siegel-umzugsliste' ), 'bTelefon', true );
self::render_address_field( __( 'Fax', 'siegel-umzugsliste' ), 'info[bTelefax]' );
self::render_address_field( __( 'Mobile', 'siegel-umzugsliste' ), 'info[bMobil]' );
self::render_address_field( __( 'Email', 'siegel-umzugsliste' ), 'info[eE-Mail]', true, 'email' );
?>
</div>
<div class="address-section">
<h3><?php echo esc_html__( 'Unloading Address', 'siegel-umzugsliste' ); ?></h3>
<?php
self::render_address_field( __( 'Name', 'siegel-umzugsliste' ), 'eName', true );
self::render_address_field( __( 'Street', 'siegel-umzugsliste' ), 'eStrasse', true );
self::render_address_field( __( 'ZIP/City', 'siegel-umzugsliste' ), 'eort', true );
self::render_address_field( __( 'Floor', 'siegel-umzugsliste' ), 'info[eGeschoss]' );
self::render_lift_field( 'info[eLift]' );
self::render_address_field( __( 'Phone', 'siegel-umzugsliste' ), 'eTelefon' );
self::render_address_field( __( 'Fax', 'siegel-umzugsliste' ), 'info[eTelefax]' );
self::render_address_field( __( 'Mobile', 'siegel-umzugsliste' ), 'info[eMobil]' );
?>
</div>
</div>
<p class="required-note"><?php echo esc_html__( '* Required fields', 'siegel-umzugsliste' ); ?></p>
</div>
<p class="required-note"><?php echo esc_html__( '* Required fields', 'siegel-umzugsliste' ); ?></p>
<?php if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) : ?>
<button type="button" id="dev-autofill" class="dev-autofill-btn">&#9881; Fill</button>
<script>
document.getElementById('dev-autofill').addEventListener('click', function() {
var fields = {
'bName':'Max Mustermann','bStrasse':'Musterstr. 12',
'bort':'10115 Berlin','bTelefon':'030 12345678',
'eName':'Erika Musterfrau','eStrasse':'Zielweg 5',
'eort':'80331 München','info[eE-Mail]':'test@example.com'
};
for (var n in fields) {
var el = document.querySelector('[name="'+n+'"]');
if (el) { el.value = fields[n]; el.dispatchEvent(new Event('input',{bubbles:true})); }
}
document.getElementById('wizard-next').click();
});
</script>
<?php endif; ?>
</div>
<?php
}
@@ -213,8 +244,8 @@ class Umzugsliste_Form_Renderer {
}
?>
<div class="wizard-step" data-step="<?php echo esc_attr( $step_num ); ?>">
<h2 class="step-title"><?php echo esc_html( $room_label ); ?></h2>
<div class="step-card">
<h2 class="step-title"><?php echo esc_html( $room_label ); ?></h2>
<div class="furniture-list" data-room="<?php echo esc_attr( $room_key ); ?>">
<?php
foreach ( $items as $item ) {
@@ -240,10 +271,10 @@ class Umzugsliste_Form_Renderer {
$rooms = Umzugsliste_Furniture_Data::get_rooms();
?>
<div class="wizard-step" data-step="5">
<h2 class="step-title"><?php echo esc_html( $rooms['bad'] ); ?> &amp; <?php echo esc_html( $rooms['kueche_esszimmer'] ); ?></h2>
<div class="step-card">
<h3><?php echo esc_html( $rooms['bad'] ); ?></h3>
<h2 class="step-title"><?php echo esc_html( $rooms['bad'] ); ?> &amp; <?php echo esc_html( $rooms['kueche_esszimmer'] ); ?></h2>
<div class="step-section">
<h3><?php echo esc_html( $rooms['bad'] ); ?></h3>
<div class="furniture-list" data-room="bad">
<?php
$bad_items = Umzugsliste_Furniture_Data::get_furniture_items( 'bad' );
@@ -257,23 +288,23 @@ class Umzugsliste_Form_Renderer {
<span class="room-totals-sep">&middot;</span>
<span class="room-total-cbm">0,00</span> <?php echo esc_html__( 'cbm', 'siegel-umzugsliste' ); ?>
</div>
</div>
</div>
</div>
<div class="step-card">
<h3><?php echo esc_html( $rooms['kueche_esszimmer'] ); ?></h3>
<div class="furniture-list" data-room="kueche_esszimmer">
<?php
$kueche_items = Umzugsliste_Furniture_Data::get_furniture_items( 'kueche_esszimmer' );
foreach ( $kueche_items as $item ) {
self::render_furniture_item( 'Kueche_Esszimmer', 'kueche_esszimmer', $item );
}
?>
<div class="room-totals" data-room="kueche_esszimmer">
<span class="room-total-label"><?php echo esc_html__( 'Total', 'siegel-umzugsliste' ) . ' ' . esc_html( $rooms['kueche_esszimmer'] ); ?>:</span>
<span class="room-total-quantity">0</span> <?php echo esc_html__( 'Items', 'siegel-umzugsliste' ); ?>
<span class="room-totals-sep">&middot;</span>
<span class="room-total-cbm">0,00</span> <?php echo esc_html__( 'cbm', 'siegel-umzugsliste' ); ?>
<div class="step-section">
<h3><?php echo esc_html( $rooms['kueche_esszimmer'] ); ?></h3>
<div class="furniture-list" data-room="kueche_esszimmer">
<?php
$kueche_items = Umzugsliste_Furniture_Data::get_furniture_items( 'kueche_esszimmer' );
foreach ( $kueche_items as $item ) {
self::render_furniture_item( 'Kueche_Esszimmer', 'kueche_esszimmer', $item );
}
?>
<div class="room-totals" data-room="kueche_esszimmer">
<span class="room-total-label"><?php echo esc_html__( 'Total', 'siegel-umzugsliste' ) . ' ' . esc_html( $rooms['kueche_esszimmer'] ); ?>:</span>
<span class="room-total-quantity">0</span> <?php echo esc_html__( 'Items', 'siegel-umzugsliste' ); ?>
<span class="room-totals-sep">&middot;</span>
<span class="room-total-cbm">0,00</span> <?php echo esc_html__( 'cbm', 'siegel-umzugsliste' ); ?>
</div>
</div>
</div>
</div>
@@ -288,27 +319,29 @@ class Umzugsliste_Form_Renderer {
$sections = Umzugsliste_Furniture_Data::get_additional_work();
?>
<div class="wizard-step" data-step="8">
<h2 class="step-title"><?php echo esc_html__( 'Additional Work', 'siegel-umzugsliste' ); ?></h2>
<?php foreach ( $sections as $section_key => $section_data ) : ?>
<div class="step-card">
<h3><?php echo esc_html( $section_data['label'] ); ?></h3>
<div class="additional-work-section" data-section="<?php echo esc_attr( $section_key ); ?>">
<?php
foreach ( $section_data['fields'] as $field ) {
$field_key = self::get_field_key( $field );
$field_name = 'additional_work[' . $section_key . '][' . $field_key . ']';
self::render_additional_field( $field, $field_name, $field_key );
}
?>
</div>
</div>
<?php endforeach; ?>
<div class="step-card">
<h3><?php echo esc_html__( 'Other', 'siegel-umzugsliste' ); ?></h3>
<label for="sonstiges"><?php echo esc_html__( 'Additional notes or requests:', 'siegel-umzugsliste' ); ?></label>
<textarea name="sonstiges" id="sonstiges" rows="5" class="sonstiges-textarea" placeholder="<?php echo esc_attr__( 'Additional notes or requests...', 'siegel-umzugsliste' ); ?>"></textarea>
<h2 class="step-title"><?php echo esc_html__( 'Additional Work', 'siegel-umzugsliste' ); ?></h2>
<?php foreach ( $sections as $section_key => $section_data ) : ?>
<div class="step-section">
<h3><?php echo esc_html( $section_data['label'] ); ?></h3>
<div class="additional-work-section" data-section="<?php echo esc_attr( $section_key ); ?>">
<?php
foreach ( $section_data['fields'] as $field ) {
$field_key = self::get_field_key( $field );
$field_name = 'additional_work[' . $section_key . '][' . $field_key . ']';
self::render_additional_field( $field, $field_name, $field_key );
}
?>
</div>
</div>
<?php endforeach; ?>
<div class="step-section">
<h3><?php echo esc_html__( 'Other', 'siegel-umzugsliste' ); ?></h3>
<label for="sonstiges"><?php echo esc_html__( 'Additional notes or requests:', 'siegel-umzugsliste' ); ?></label>
<textarea name="sonstiges" id="sonstiges" rows="5" class="sonstiges-textarea"></textarea>
</div>
</div>
</div>
<?php
@@ -323,15 +356,17 @@ class Umzugsliste_Form_Renderer {
$captcha = Umzugsliste_Captcha::get_instance();
?>
<div class="wizard-step" data-step="9">
<h2 class="step-title"><?php echo esc_html__( 'Summary', 'siegel-umzugsliste' ); ?></h2>
<div id="wizard-summary"></div>
<?php
if ( $captcha->is_enabled() ) {
echo '<div class="step-card">';
echo $captcha->render_widget();
echo '</div>';
}
?>
<div class="step-card">
<h2 class="step-title"><?php echo esc_html__( 'Summary', 'siegel-umzugsliste' ); ?></h2>
<div id="wizard-summary"></div>
<?php
if ( $captcha->is_enabled() ) {
echo '<div class="captcha-section">';
echo $captcha->render_widget();
echo '</div>';
}
?>
</div>
<?php wp_nonce_field( 'umzugsliste_submit', 'umzugsliste_nonce' ); ?>
<input type="hidden" name="umzugsliste_submit" value="1">
<input type="hidden" name="umzugsliste_form_id" value="<?php echo esc_attr( $form_id ); ?>">
@@ -391,12 +426,17 @@ class Umzugsliste_Form_Renderer {
$montage_name = $room_name . '[m' . $item_name . ']';
?>
<div class="furniture-item" data-room="<?php echo esc_attr( $room_key ); ?>" data-cbm="<?php echo esc_attr( $cbm ); ?>">
<input type="text" name="<?php echo esc_attr( $quantity_name ); ?>" class="quantity-input" inputmode="decimal" placeholder="0" maxlength="3">
<div class="quantity-stepper">
<button type="button" class="qty-btn qty-minus" aria-label="<?php echo esc_attr__( 'Decrease', 'siegel-umzugsliste' ); ?>">-</button>
<input type="text" name="<?php echo esc_attr( $quantity_name ); ?>" class="quantity-input" inputmode="numeric" placeholder="0" maxlength="3">
<button type="button" class="qty-btn qty-plus" aria-label="<?php echo esc_attr__( 'Increase', 'siegel-umzugsliste' ); ?>">+</button>
</div>
<span class="item-name"><?php echo esc_html( $item_name ); ?></span>
<span class="item-cbm"><?php echo esc_html( str_replace( '.', ',', (string) $cbm ) ); ?></span>
<span class="item-cbm"><?php echo esc_html( str_replace( '.', ',', (string) $cbm ) ); ?> <?php echo esc_html__( 'cbm', 'siegel-umzugsliste' ); ?></span>
<input type="hidden" name="<?php echo esc_attr( $cbm_name ); ?>" value="<?php echo esc_attr( $cbm ); ?>">
<?php if ( $has_montage ) : ?>
<div class="montage-toggle">
<span class="montage-label"><?php echo esc_html__( 'Montage?', 'siegel-umzugsliste' ); ?></span>
<label class="radio-label"><input type="radio" name="<?php echo esc_attr( $montage_name ); ?>" value="nein" checked> <?php echo esc_html__( 'No', 'siegel-umzugsliste' ); ?></label>
<label class="radio-label"><input type="radio" name="<?php echo esc_attr( $montage_name ); ?>" value="ja"> <?php echo esc_html__( 'Yes', 'siegel-umzugsliste' ); ?></label>
</div>

View File

@@ -123,6 +123,18 @@ class Umzugsliste_Shortcode {
'grandTotalLabel' => __( 'Grand Total', 'siegel-umzugsliste' ),
'quantityLabel' => __( 'Qty', 'siegel-umzugsliste' ),
'cbmLabel' => __( 'cbm', 'siegel-umzugsliste' ),
'summaryEdit' => __( 'Edit', 'siegel-umzugsliste' ),
'summaryName' => __( 'Name', 'siegel-umzugsliste' ),
'summaryStreet' => __( 'Street', 'siegel-umzugsliste' ),
'summaryZipCity' => __( 'ZIP/City', 'siegel-umzugsliste' ),
'summaryFloor' => __( 'Floor', 'siegel-umzugsliste' ),
'summaryElevator' => __( 'Elevator', 'siegel-umzugsliste' ),
'summaryPhone' => __( 'Phone', 'siegel-umzugsliste' ),
'summaryFax' => __( 'Fax', 'siegel-umzugsliste' ),
'summaryMobile' => __( 'Mobile', 'siegel-umzugsliste' ),
'summaryEmail' => __( 'Email', 'siegel-umzugsliste' ),
'stepLabel' => __( 'Step', 'siegel-umzugsliste' ),
'stepOf' => __( 'of', 'siegel-umzugsliste' ),
) );
}
}

View File

@@ -1137,3 +1137,22 @@ msgstr "Mobil (Beladeadresse)"
#: includes/class-cpt.php
msgid "Mobile (Unloading)"
msgstr "Mobil (Entladeadresse)"
#: includes/class-shortcode.php
#: templates/form-page.php
msgid "Step"
msgstr "Schritt"
#: includes/class-shortcode.php
#: templates/form-page.php
msgid "of"
msgstr "von"
#: includes/class-shortcode.php
#: templates/form-page.php
msgid "Edit"
msgstr "Bearbeiten"
#: includes/class-form-renderer.php
msgid "Montage?"
msgstr "Montage?"

View File

@@ -40,6 +40,18 @@ $l10n_data = array(
'grandTotalLabel' => __( 'Grand Total', 'siegel-umzugsliste' ),
'quantityLabel' => __( 'Qty', 'siegel-umzugsliste' ),
'cbmLabel' => __( 'cbm', 'siegel-umzugsliste' ),
'summaryEdit' => __( 'Edit', 'siegel-umzugsliste' ),
'summaryName' => __( 'Name', 'siegel-umzugsliste' ),
'summaryStreet' => __( 'Street', 'siegel-umzugsliste' ),
'summaryZipCity' => __( 'ZIP/City', 'siegel-umzugsliste' ),
'summaryFloor' => __( 'Floor', 'siegel-umzugsliste' ),
'summaryElevator' => __( 'Elevator', 'siegel-umzugsliste' ),
'summaryPhone' => __( 'Phone', 'siegel-umzugsliste' ),
'summaryFax' => __( 'Fax', 'siegel-umzugsliste' ),
'summaryMobile' => __( 'Mobile', 'siegel-umzugsliste' ),
'summaryEmail' => __( 'Email', 'siegel-umzugsliste' ),
'stepLabel' => __( 'Step', 'siegel-umzugsliste' ),
'stepOf' => __( 'of', 'siegel-umzugsliste' ),
'nonce' => wp_create_nonce( 'umzugsliste_submit' ),
);
?>