From 89bd555dc1552f757cc85764f296643288d01f51 Mon Sep 17 00:00:00 2001 From: Viktor Miller Date: Sat, 7 Feb 2026 23:46:36 +0900 Subject: [PATCH 1/4] feat: modernize wizard UX with smart rows, steppers, transitions, and edit links - Hide montage toggles and dim furniture rows when quantity is 0 - Animate running totals bar with CSS transform instead of display toggle - Add directional slide transitions (forward/backward) between steps - Add +/- stepper buttons around quantity inputs for better affordance - Increase mobile tap targets to 44px and show active step label - Add "Edit" links to summary section headings for quick navigation - Add "Step X of Y" counter below progress bar - Add summaryEdit, stepLabel, stepOf l10n strings to both entry points Co-Authored-By: Claude Opus 4.6 --- assets/css/form.css | 136 ++++++++++++++++++++++++++++--- assets/js/form.js | 76 +++++++++++++---- includes/class-form-renderer.php | 7 +- includes/class-shortcode.php | 3 + templates/form-page.php | 3 + 5 files changed, 193 insertions(+), 32 deletions(-) diff --git a/assets/css/form.css b/assets/css/form.css index ba48d77..97c94d8 100644 --- a/assets/css/form.css +++ b/assets/css/form.css @@ -167,6 +167,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; @@ -181,11 +189,14 @@ font-size: 0.95rem; font-weight: 500; box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); - display: none; + transform: translateY(100%); + transition: transform 0.3s; + pointer-events: none; } .running-totals.visible { - display: block; + transform: translateY(0); + pointer-events: auto; } .running-totals-label { @@ -219,6 +230,24 @@ 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; @@ -394,27 +423,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); @@ -630,6 +710,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 +823,8 @@ flex-basis: calc(100% - 80px); } - .quantity-input { + .quantity-input, + .quantity-stepper { order: 2; } @@ -769,18 +863,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; } } diff --git a/assets/js/form.js b/assets/js/form.js index 687990f..2232214 100644 --- a/assets/js/form.js +++ b/assets/js/form.js @@ -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 '

' + escHtml(text) + ' ' + editLabel + '

'; + } + function generateSummary() { var container = qs('#wizard-summary'); if (!container) return; @@ -279,7 +296,7 @@ // Customer info html += '
'; - html += '

' + escHtml(l10n.summaryMovingDate || 'Moving Date') + '

'; + html += summaryHeading(l10n.summaryMovingDate || 'Moving Date', 1); var day = getFieldVal('day'); var month = getFieldVal('month'); var year = getFieldVal('year'); @@ -288,7 +305,7 @@ // Loading address html += '
'; - html += '

' + escHtml(l10n.summaryLoading || 'Loading Address') + '

'; + html += summaryHeading(l10n.summaryLoading || 'Loading Address', 1); html += summaryRow('Name', getFieldVal('bName')); html += summaryRow('Street', getFieldVal('bStrasse')); html += summaryRow('ZIP/City', getFieldVal('bort')); @@ -305,7 +322,7 @@ // Unloading address html += '
'; - html += '

' + escHtml(l10n.summaryUnloading || 'Unloading Address') + '

'; + html += summaryHeading(l10n.summaryUnloading || 'Unloading Address', 1); html += summaryRow('Name', getFieldVal('eName')); html += summaryRow('Street', getFieldVal('eStrasse')); html += summaryRow('ZIP/City', getFieldVal('eort')); @@ -322,13 +339,13 @@ // 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,7 +354,7 @@ var total = calculateRoomTotal(room.key); html += '
'; - html += '

' + escHtml(getRoomDisplayName(room.key)) + '

'; + html += summaryHeading(getRoomDisplayName(room.key), room.step); roomItems.forEach(function(item) { html += '
'; html += '' + escHtml(item.name) + ''; @@ -368,7 +385,7 @@ var additionalHtml = getAdditionalWorkSummary(); if (additionalHtml) { html += '
'; - html += '

' + escHtml(l10n.summaryAdditional || 'Additional Work') + '

'; + html += summaryHeading(l10n.summaryAdditional || 'Additional Work', 8); html += additionalHtml; html += '
'; } @@ -377,7 +394,7 @@ var sonstiges = getFieldVal('sonstiges'); if (sonstiges) { html += '
'; - html += '

' + escHtml(l10n.summaryOther || 'Other') + '

'; + html += summaryHeading(l10n.summaryOther || 'Other', 8); html += '

' + escHtml(sonstiges) + '

'; html += '
'; } @@ -526,15 +543,38 @@ 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); } }); + // 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')) { diff --git a/includes/class-form-renderer.php b/includes/class-form-renderer.php index 2639d93..34505fe 100644 --- a/includes/class-form-renderer.php +++ b/includes/class-form-renderer.php @@ -134,6 +134,7 @@ class Umzugsliste_Form_Renderer {
+
- +
+ + + +
diff --git a/includes/class-shortcode.php b/includes/class-shortcode.php index c51eed1..f4e34b0 100644 --- a/includes/class-shortcode.php +++ b/includes/class-shortcode.php @@ -123,6 +123,9 @@ class Umzugsliste_Shortcode { 'grandTotalLabel' => __( 'Grand Total', 'siegel-umzugsliste' ), 'quantityLabel' => __( 'Qty', 'siegel-umzugsliste' ), 'cbmLabel' => __( 'cbm', 'siegel-umzugsliste' ), + 'summaryEdit' => __( 'Edit', 'siegel-umzugsliste' ), + 'stepLabel' => __( 'Step', 'siegel-umzugsliste' ), + 'stepOf' => __( 'of', 'siegel-umzugsliste' ), ) ); } } diff --git a/templates/form-page.php b/templates/form-page.php index 8624ab8..c4e8832 100644 --- a/templates/form-page.php +++ b/templates/form-page.php @@ -40,6 +40,9 @@ $l10n_data = array( 'grandTotalLabel' => __( 'Grand Total', 'siegel-umzugsliste' ), 'quantityLabel' => __( 'Qty', 'siegel-umzugsliste' ), 'cbmLabel' => __( 'cbm', 'siegel-umzugsliste' ), + 'summaryEdit' => __( 'Edit', 'siegel-umzugsliste' ), + 'stepLabel' => __( 'Step', 'siegel-umzugsliste' ), + 'stepOf' => __( 'of', 'siegel-umzugsliste' ), 'nonce' => wp_create_nonce( 'umzugsliste_submit' ), ); ?> -- 2.49.1 From 2ca1f4ff5428109e604158e74ba5007ddc25ab3d Mon Sep 17 00:00:00 2001 From: Viktor Miller Date: Thu, 12 Feb 2026 22:47:39 +0900 Subject: [PATCH 2/4] feat: redesign Step 8 with flat list layout matching room steps Replace bordered card sections with flat rows using hairline dividers, opacity dimming, and native radio controls to match the room step visual pattern. Also includes structural refactors (step-sections, address-sections) and running totals bar polish from the modernization branch. Co-Authored-By: Claude Opus 4.6 --- assets/css/form.css | 130 +++++++++++++++++- includes/class-form-renderer.php | 183 ++++++++++++++------------ languages/siegel-umzugsliste-de_DE.mo | Bin 16248 -> 16366 bytes languages/siegel-umzugsliste-de_DE.po | 19 +++ 4 files changed, 245 insertions(+), 87 deletions(-) diff --git a/assets/css/form.css b/assets/css/form.css index 97c94d8..950261f 100644 --- a/assets/css/form.css +++ b/assets/css/form.css @@ -183,19 +183,23 @@ 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); + box-shadow: var(--umzug-shadow-lg); transform: translateY(100%); - transition: transform 0.3s; + opacity: 0; + transition: transform 0.3s, opacity 0.3s; pointer-events: none; } .running-totals.visible { transform: translateY(0); + opacity: 1; pointer-events: auto; } @@ -251,7 +255,9 @@ .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); } @@ -274,6 +280,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; @@ -514,7 +546,7 @@ .item-cbm { width: 52px; text-align: right; - font-size: 0.85rem; + font-size: 13px; color: var(--umzug-text-secondary); flex-shrink: 0; } @@ -526,7 +558,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 ===== */ @@ -627,6 +666,76 @@ 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; +} + /* ===== Sonstiges ===== */ .sonstiges-textarea { width: 100%; @@ -839,6 +948,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; diff --git a/includes/class-form-renderer.php b/includes/class-form-renderer.php index 34505fe..c4f43b9 100644 --- a/includes/class-form-renderer.php +++ b/includes/class-form-renderer.php @@ -144,9 +144,8 @@ class Umzugsliste_Form_Renderer { private static function render_step_1() { ?>
-

-
+

' . esc_html__( 'Privacy Policy', 'siegel-umzugsliste' ) . '' ); ?>

-
- -
-
-

- -
-
-

- +
+
+

+ +
+
+

+ +
+

-

+ + + +
-

+

-

&

-
-

+

&

+
+

· 0,00
+
-
- -
-

-
- -
- : - 0 - · - 0,00 +
+

+
+ +
+ : + 0 + · + 0,00 +
@@ -289,27 +305,29 @@ class Umzugsliste_Form_Renderer { $sections = Umzugsliste_Furniture_Data::get_additional_work(); ?>
-

- - $section_data ) : ?> -
-

-
- -
-
- -
-

- - +

+ + $section_data ) : ?> +
+

+
+ +
+
+ + +
+

+ + +
-

-
- is_enabled() ) { - echo '
'; - echo $captcha->render_widget(); - echo '
'; - } - ?> +
+

+
+ is_enabled() ) { + echo '
'; + echo $captcha->render_widget(); + echo '
'; + } + ?> +
@@ -402,6 +422,7 @@ class Umzugsliste_Form_Renderer {
+
diff --git a/languages/siegel-umzugsliste-de_DE.mo b/languages/siegel-umzugsliste-de_DE.mo index 4482dd3bc0c3c71d38773a2eaf3dc33a940ea4a5..256d197732db9045862d12e687e6c9562e502662 100644 GIT binary patch delta 5622 zcmXxo34Bdg0>|-_!m#J`vToWNUxq$Bf{Y?wf%jn2YMji>QvR z#UR{>k+=grv~RwoqMnwcZaiI- z*CQh~J5lX@jFGf&j!@}>mDm9zmA+cQ@8?k{W{dhx1(lm4~F7l z)W|QOI#!9g?=~{2rq-U1h+_V`bE0LG+wfS_jhUziO-GGn5voIrQ6pN7{FqJr()D}o z`2(oUdJ5IyN>oR0p*Ec#)2QbJqRvM}GynP^i4$70G*piVScjt?I04nrEYyQ@F&6W2 z1ipp52<9HDfgrZJW-c0aUklXp6HpCzwdV&qRP?|MRKsJeS*QzVqn2bTYUC?Xdtw7> zDvzS}#8uQ3->}Cus5SR}$X%KysHJL+>QEA@Jtu{V9@N*K7=xPnEL6wxP@8QjszYy} zMz+hIFGcpPDM!uZRr~oZ)cw`yi?#OHmkq~$G=WG59g|>Bq*{lgdYFy6aSm$g=AjF^!`W0^6kZm9;nwZ6LrCA)QzR6 zsojU#jOC~qIDtBU2GxN|)J*(>Y;Y6S!o98&s^clB>-(Ute_Y43Z>Cbwn&x6Vdrf2p#R(GW)@C)b2fv zn!3xVDXv0ovTD=_YfvK$ZD}_X>ithabzmT>U$55&PRO0s z{irGX+Fp18Q#t+#yJ9=mXBa+(nz3Tk5}rqGR{wan1JS6x6OS557u0i8Q8U&rp7~d0 z2q!eMQP>@4VH&=R-kCu4xC(W>59^=~H^9yqgWfeo&A?PtL%FCK%}3q03i*mK>rn0O zaj0mjjw7>b&Y~VrgS;`Oega<_*p^>yaTw}*U;%3B3NRKoqwYU|y!z%UYDWC{)d@Qw zeK+G#19}0~VP_Q;P0?2L;BNH8GVF!>urAi1*4#rcG=k=+>(bE|``}g|rWDn|>#U15 zVGY*7M(vI1h7qV4&Ookn%rYwaLUnp*HJpvw6FK(t0(-n3{q+97Po*Ij>_Ihf&>o*ct=&b`RNX{11IxqyxEi%L&R`wA|Cgw!$Jfvwt5KWnJ~qU_MAv4hh7wRy zn2x~U9AgXyRdKVgq&pk`#LJ^ylN=3kp{D<|~8{n!|f zpgK~4>fm)$kA1qhBML`-9)nuC_Nb0@M>WtJHFE<|&&@!+o}+ORE(lJ#kD~4yj_UY$RL5po7b0(@DZmgcMRoKLYRQ}vRMgXp zsF7Ypt$ht@Bq3eh&!bQsYJr;CL{vuxphhy>ex8kLXg;b#FQL}_O$@~?sCGU?I_j8X zR5Y^lsF7Sj-B5*U@Gdq-{VPLj8H=qk4fRbo5jDk&P+vsLQTG*~I{2DBE<%mG7&U-0 z?=kCtl8QR;9X7#BsE$-)0@k7$OyKK_eP=R|4Q?FkPJ8|$s)1m3Xc$JK29jt^M$Jen zY9NC#oc2v772S}Bx?we{=Y{tCX6py2ksigz@LTMN%~Rcfhzvok{d1@pSb-YATGZcs zK1B`m9O^lj(a|QjK}934u@^K-bH5M5Q5QDDP;6yQLya^8)zC<5CTak)?C0|^g5!l4 ziG`>R?!ZR4H;whz?k?wqdRAdSs6TES>e1IY@Zn%Db|B&82l6k{hN!R$%^%1K9Z)_YpORBLu%+7i8`OH7 zCLfdM$v?(cMXjVGTHA|H`kq?V{?TYm4Y@iz+`Pdbu4L_6a_ z(e4Ve2mA3Ga+oY7TgX`Q9GOr0lC`7{QPHu(jRphs%CsCb71S<~$>bc-8?UmA{7R0J zUx>;9a$I*gzxN)yzcS%E=|&zQzC7V+97Lv*mE>j8o~$Feq&0bn6qAcY|Fx-dpOldz za)h)XDx1h^GJ~XO_VcI=B?pO06bba!+<$(Kr2ZoL5BV#ZLY^dlAzzaVL?wZIPVSPI zh{`N7ge)O;o~gOzs+S1&;892=apZOKZOPKGGEYfbvu%E!NmH|Wmt2Y|^7zauc|LAN wfbYyHB{$ma3-Em;t7KDBsK-CYd&REg6#szCX>+FMiU0rr delta 5527 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 nrbn$0^d)&$czmTzUJCN1wb&QrtJXHy@nzqXZ}r diff --git a/languages/siegel-umzugsliste-de_DE.po b/languages/siegel-umzugsliste-de_DE.po index 0109a46..4374dcb 100644 --- a/languages/siegel-umzugsliste-de_DE.po +++ b/languages/siegel-umzugsliste-de_DE.po @@ -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?" -- 2.49.1 From f1f5c760c2e5a188ad5c4f6a503bdad63a0b641f Mon Sep 17 00:00:00 2001 From: Viktor Miller Date: Thu, 12 Feb 2026 23:02:55 +0900 Subject: [PATCH 3/4] feat: add 3 switchable color palettes with Slate Blue & Amber as default Replace generic Google blue with 3 professional palettes (Deep Teal, Slate Blue & Amber, Rich Olive & Copper) using CSS token overrides. Palette B (Slate Blue + amber Next button) is the default. Includes WP_DEBUG-only purple switcher button to cycle between palettes. Co-Authored-By: Claude Opus 4.6 --- assets/css/form.css | 139 +++++++++++++++++++++++++++++++ includes/class-form-renderer.php | 16 +++- 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/assets/css/form.css b/assets/css/form.css index 950261f..4b1b556 100644 --- a/assets/css/form.css +++ b/assets/css/form.css @@ -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; @@ -736,6 +853,28 @@ 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%; diff --git a/includes/class-form-renderer.php b/includes/class-form-renderer.php index c4f43b9..5189cbe 100644 --- a/includes/class-form-renderer.php +++ b/includes/class-form-renderer.php @@ -46,7 +46,7 @@ class Umzugsliste_Form_Renderer { ob_start(); ?> -
+
@@ -82,6 +82,20 @@ class Umzugsliste_Form_Renderer {
+ + + +
Date: Thu, 12 Feb 2026 23:31:25 +0900 Subject: [PATCH 4/4] fix: polish form UX and step 9 summary translations - Add spacing below Datenschutzerklaerung text - Fix missing Umzugstermin on step 9 (wrong field names in JS) - Remove number-to-checkmark animation flicker on progress dots - Add cbm unit label to furniture item values and summary - Translate all summary field labels via l10n (Name, Strasse, etc.) - Fix room names showing lowercase keys instead of proper titles - Auto-check checkbox when quantity is entered on step 8 - Remove redundant Sonstiges textarea placeholder Co-Authored-By: Claude Opus 4.6 --- assets/css/form.css | 8 ++-- assets/js/form.js | 63 ++++++++++++++++++++------------ includes/class-form-renderer.php | 4 +- includes/class-shortcode.php | 9 +++++ templates/form-page.php | 9 +++++ 5 files changed, 63 insertions(+), 30 deletions(-) diff --git a/assets/css/form.css b/assets/css/form.css index 4b1b556..1a37180 100644 --- a/assets/css/form.css +++ b/assets/css/form.css @@ -249,7 +249,7 @@ body.umzugsliste-standalone:has(.palette-c) { 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 { @@ -465,7 +465,7 @@ body.umzugsliste-standalone:has(.palette-c) { font-size: 0.8rem; color: var(--umzug-text-secondary); margin-top: 12px; - margin-bottom: 0; + margin-bottom: 16px; } .privacy-note a { @@ -661,7 +661,7 @@ body.umzugsliste-standalone:has(.palette-c) { } .item-cbm { - width: 52px; + width: 75px; text-align: right; font-size: 13px; color: var(--umzug-text-secondary); @@ -947,7 +947,7 @@ body.umzugsliste-standalone:has(.palette-c) { } #wizard-summary .summary-item-cbm { - width: 60px; + width: 80px; text-align: right; color: var(--umzug-text-secondary); } diff --git a/assets/js/form.js b/assets/js/form.js index 2232214..ffe8e82 100644 --- a/assets/js/form.js +++ b/assets/js/form.js @@ -297,44 +297,44 @@ // Customer info html += '
'; html += summaryHeading(l10n.summaryMovingDate || 'Moving Date', 1); - var day = getFieldVal('day'); - var month = getFieldVal('month'); - var year = getFieldVal('year'); + 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 += '
'; // Loading address html += '
'; html += summaryHeading(l10n.summaryLoading || 'Loading Address', 1); - html += summaryRow('Name', getFieldVal('bName')); - html += summaryRow('Street', getFieldVal('bStrasse')); - html += summaryRow('ZIP/City', getFieldVal('bort')); + 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 += '
'; // Unloading address html += '
'; html += summaryHeading(l10n.summaryUnloading || 'Unloading Address', 1); - html += summaryRow('Name', getFieldVal('eName')); - html += summaryRow('Street', getFieldVal('eStrasse')); - html += summaryRow('ZIP/City', getFieldVal('eort')); + 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 += '
'; // Room summaries @@ -359,7 +359,7 @@ html += '
'; html += '' + escHtml(item.name) + ''; html += '' + item.qty + ''; - html += '' + formatGermanDecimal(item.cbm) + ''; + html += '' + formatGermanDecimal(item.cbm) + ' ' + escHtml(l10n.summaryCbm || 'cbm') + ''; if (item.montage !== null) { html += '' + escHtml(item.montage === 'ja' ? (l10n.summaryYes || 'Yes') : (l10n.summaryNo || 'No')) + ''; } @@ -419,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; @@ -556,6 +562,15 @@ } }); + // 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'); diff --git a/includes/class-form-renderer.php b/includes/class-form-renderer.php index 5189cbe..18fed1f 100644 --- a/includes/class-form-renderer.php +++ b/includes/class-form-renderer.php @@ -340,7 +340,7 @@ class Umzugsliste_Form_Renderer {

- +
@@ -432,7 +432,7 @@ class Umzugsliste_Form_Renderer {
- +
diff --git a/includes/class-shortcode.php b/includes/class-shortcode.php index f4e34b0..29dad23 100644 --- a/includes/class-shortcode.php +++ b/includes/class-shortcode.php @@ -124,6 +124,15 @@ class Umzugsliste_Shortcode { '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' ), ) ); diff --git a/templates/form-page.php b/templates/form-page.php index c4e8832..89e6163 100644 --- a/templates/form-page.php +++ b/templates/form-page.php @@ -41,6 +41,15 @@ $l10n_data = array( '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' ), -- 2.49.1