feat: stepper ±5 min sans rechargement (amélioration progressive)Unverified
Petit script inline sur l'étape 2 : les boutons −/+ modifient le champ en place (bornes 5..1440) et mettent à jour la durée en clair ; sans JS les liens href continuent de recharger le formulaire pré-rempli. Retour à type=number (le CSS servi était obsolète côté Firefox).
8aa0894 parent: b161f6f modified
templates/add_step2.html +29 -5 | @@ -13,20 +13,44 @@ | ||
| 13 | 13 | <p class="mini-label">Durée</p> |
| 14 | 14 | <div class="duration-row"> |
| 15 | 15 | <div class="stepper"> |
| 16 | - <a class="stepper-btn" href="{{ minus_href }}" aria-label="Cinq minutes de moins"> | |
| 16 | + <a class="stepper-btn" href="{{ minus_href }}" data-step="-5" aria-label="Cinq minutes de moins"> | |
| 17 | 17 | <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M5 12h14"></path></svg> |
| 18 | 18 | </a> |
| 19 | - <input class="input minutes-input" name="minutes" type="text" inputmode="numeric" | |
| 20 | - pattern="[0-9]*" required value="{{ minutes }}"> | |
| 21 | - <a class="stepper-btn" href="{{ plus_href }}" aria-label="Cinq minutes de plus"> | |
| 19 | + <input class="input minutes-input" id="minutes" name="minutes" type="number" inputmode="numeric" | |
| 20 | + min="1" max="1440" required value="{{ minutes }}"> | |
| 21 | + <a class="stepper-btn" href="{{ plus_href }}" data-step="5" aria-label="Cinq minutes de plus"> | |
| 22 | 22 | <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg> |
| 23 | 23 | </a> |
| 24 | 24 | </div> |
| 25 | 25 | <div> |
| 26 | 26 | <div class="unit">minutes</div> |
| 27 | - <div class="pretty">{{ minutes_pretty }}</div> | |
| 27 | + <div class="pretty" id="minutes-pretty">{{ minutes_pretty }}</div> | |
| 28 | 28 | </div> |
| 29 | 29 | </div> |
| 30 | + <script> | |
| 31 | + // Amélioration progressive : ±5 min sans recharger la page. | |
| 32 | + // Sans JS, les liens href rechargent le formulaire pré-rempli. | |
| 33 | + (function () { | |
| 34 | + var input = document.getElementById('minutes'); | |
| 35 | + var pretty = document.getElementById('minutes-pretty'); | |
| 36 | + function dur(m) { | |
| 37 | + if (!m || m < 1) return '0 min'; | |
| 38 | + var h = Math.floor(m / 60), r = m % 60; | |
| 39 | + if (!h) return r + ' min'; | |
| 40 | + return r ? h + ' h ' + (r < 10 ? '0' + r : r) : h + ' h'; | |
| 41 | + } | |
| 42 | + function refresh() { pretty.textContent = dur(Math.round(+input.value) || 0); } | |
| 43 | + document.querySelectorAll('.stepper-btn[data-step]').forEach(function (btn) { | |
| 44 | + btn.addEventListener('click', function (e) { | |
| 45 | + e.preventDefault(); | |
| 46 | + var v = Math.round(+input.value) || 0; | |
| 47 | + input.value = Math.min(1440, Math.max(5, v + (+btn.dataset.step))); | |
| 48 | + refresh(); | |
| 49 | + }); | |
| 50 | + }); | |
| 51 | + input.addEventListener('input', refresh); | |
| 52 | + })(); | |
| 53 | + </script> | |
| 30 | 54 | <div class="presets"> |
| 31 | 55 | {% for p in presets %} |
| 32 | 56 | <a class="preset" href="{{ p.href }}" {% if p.selected %}aria-current="true"{% endif %}>{{ p.label }}</a> |
| @@ -13,20 +13,44 @@ | |||
| 13 | <p class="mini-label">Durée</p> | 13 | <p class="mini-label">Durée</p> |
| 14 | <div class="duration-row"> | 14 | <div class="duration-row"> |
| 15 | <div class="stepper"> | 15 | <div class="stepper"> |
| 16 | - <a class="stepper-btn" href="{{ minus_href }}" aria-label="Cinq minutes de moins"> | 16 | + <a class="stepper-btn" href="{{ minus_href }}" data-step="-5" aria-label="Cinq minutes de moins"> |
| 17 | <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M5 12h14"></path></svg> | 17 | <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M5 12h14"></path></svg> |
| 18 | </a> | 18 | </a> |
| 19 | - <input class="input minutes-input" name="minutes" type="text" inputmode="numeric" | 19 | + <input class="input minutes-input" id="minutes" name="minutes" type="number" inputmode="numeric" |
| 20 | - pattern="[0-9]*" required value="{{ minutes }}"> | 20 | + min="1" max="1440" required value="{{ minutes }}"> |
| 21 | - <a class="stepper-btn" href="{{ plus_href }}" aria-label="Cinq minutes de plus"> | 21 | + <a class="stepper-btn" href="{{ plus_href }}" data-step="5" aria-label="Cinq minutes de plus"> |
| 22 | <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg> | 22 | <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg> |
| 23 | </a> | 23 | </a> |
| 24 | </div> | 24 | </div> |
| 25 | <div> | 25 | <div> |
| 26 | <div class="unit">minutes</div> | 26 | <div class="unit">minutes</div> |
| 27 | - <div class="pretty">{{ minutes_pretty }}</div> | 27 | + <div class="pretty" id="minutes-pretty">{{ minutes_pretty }}</div> |
| 28 | </div> | 28 | </div> |
| 29 | </div> | 29 | </div> |
| 30 | + <script> | ||
| 31 | + // Amélioration progressive : ±5 min sans recharger la page. | ||
| 32 | + // Sans JS, les liens href rechargent le formulaire pré-rempli. | ||
| 33 | + (function () { | ||
| 34 | + var input = document.getElementById('minutes'); | ||
| 35 | + var pretty = document.getElementById('minutes-pretty'); | ||
| 36 | + function dur(m) { | ||
| 37 | + if (!m || m < 1) return '0 min'; | ||
| 38 | + var h = Math.floor(m / 60), r = m % 60; | ||
| 39 | + if (!h) return r + ' min'; | ||
| 40 | + return r ? h + ' h ' + (r < 10 ? '0' + r : r) : h + ' h'; | ||
| 41 | + } | ||
| 42 | + function refresh() { pretty.textContent = dur(Math.round(+input.value) || 0); } | ||
| 43 | + document.querySelectorAll('.stepper-btn[data-step]').forEach(function (btn) { | ||
| 44 | + btn.addEventListener('click', function (e) { | ||
| 45 | + e.preventDefault(); | ||
| 46 | + var v = Math.round(+input.value) || 0; | ||
| 47 | + input.value = Math.min(1440, Math.max(5, v + (+btn.dataset.step))); | ||
| 48 | + refresh(); | ||
| 49 | + }); | ||
| 50 | + }); | ||
| 51 | + input.addEventListener('input', refresh); | ||
| 52 | + })(); | ||
| 53 | + </script> | ||
| 30 | <div class="presets"> | 54 | <div class="presets"> |
| 31 | {% for p in presets %} | 55 | {% for p in presets %} |
| 32 | <a class="preset" href="{{ p.href }}" {% if p.selected %}aria-current="true"{% endif %}>{{ p.label }}</a> | 56 | <a class="preset" href="{{ p.href }}" {% if p.selected %}aria-current="true"{% endif %}>{{ p.label }}</a> |