judu/ex-egopublic Fork
⑂ 2dd9b43
Commits
⬇ Clone ▾
git clone https://git.rickub.com/judu/ex-ego.git
git clone ssh://git@rickub.com/judu/ex-ego.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

feat: stepper de durée ±5 min sur l'ajout (sync design)Unverified

Le champ minutes devient un stepper en pilule (− / champ step=5 / +),
libellés minutes + durée en clair à droite ; liens zéro-JS bornés
[5, 1440]. Spinners natifs retirés aussi sous Firefox.
Julien Durillon committed 2026-08-06T20:54:20+02:00 Browse files
2dd9b43 parent: bb1fbb6
modified assets/style.css +23 -7
@@ -16,6 +16,7 @@
1616 --color-neutral-900: #2e2b25;
1717
1818 --color-accent-100: #fff2eb;
19+ --color-accent-200: #ffe1d0;
1920 --color-accent-300: #ffc6a5;
2021 --color-accent-600: #b2622d;
2122 --color-accent-700: #8c491a;
@@ -59,7 +60,8 @@ a { color: var(--color-accent); text-underline-offset: 3px; }
5960 ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }
6061 button { font-family: inherit; }
6162 input[type=number]::-webkit-outer-spin-button,
62-input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
63+input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
64+input[type=number] { -moz-appearance: textfield; appearance: textfield; }
6365
6466 .text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
6567
@@ -179,13 +181,27 @@ input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin
179181 .picked { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-6); }
180182 .picked .pname { font-size: 20px; font-family: var(--font-heading); }
181183 .mini-label { font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }
182-.duration-row { display: flex; align-items: baseline; gap: 6px; margin-bottom: var(--space-3); }
183-.duration-row .minutes-input {
184- width: 130px; font-size: 34px; font-family: var(--font-heading);
185- min-height: 64px; text-align: center; padding: 0 10px;
184+.duration-row { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
185+.stepper {
186+ display: flex; align-items: center; gap: var(--space-1);
187+ background: var(--color-surface); border: 1px solid var(--color-divider);
188+ border-radius: 999px; padding: 5px 6px;
186189 }
187-.duration-row .unit { font-size: 16px; opacity: .6; }
188-.duration-row .pretty { margin-left: auto; font-size: 14px; opacity: .55; }
190+.stepper-btn {
191+ width: 40px; height: 40px; flex: none;
192+ display: flex; align-items: center; justify-content: center;
193+ border: none; border-radius: 999px; background: transparent;
194+ color: var(--color-text); cursor: pointer; text-decoration: none;
195+}
196+.stepper-btn:hover { background: var(--color-accent-200); }
197+.stepper-btn:active { background: var(--color-accent-300); }
198+.stepper .minutes-input {
199+ width: 92px; font-size: 32px; font-family: var(--font-heading);
200+ min-height: 44px; text-align: center; padding: 0;
201+ background: transparent; border-color: transparent;
202+}
203+.duration-row .unit { font-size: 15px; opacity: .7; }
204+.duration-row .pretty { font-size: 13px; opacity: .5; }
189205 .presets { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }
190206 .preset {
191207 padding: 9px 16px; border-radius: 999px; font-size: 14px;
@@ -16,6 +16,7 @@
16 --color-neutral-900: #2e2b25;16 --color-neutral-900: #2e2b25;
17 17
18 --color-accent-100: #fff2eb;18 --color-accent-100: #fff2eb;
19+ --color-accent-200: #ffe1d0;
19 --color-accent-300: #ffc6a5;20 --color-accent-300: #ffc6a5;
20 --color-accent-600: #b2622d;21 --color-accent-600: #b2622d;
21 --color-accent-700: #8c491a;22 --color-accent-700: #8c491a;
@@ -59,7 +60,8 @@ a { color: var(--color-accent); text-underline-offset: 3px; }
59 ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }60 ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }
60 button { font-family: inherit; }61 button { font-family: inherit; }
61 input[type=number]::-webkit-outer-spin-button,62 input[type=number]::-webkit-outer-spin-button,
62-input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }63+input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
64+input[type=number] { -moz-appearance: textfield; appearance: textfield; }
63 65
64 .text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }66 .text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
65 67
@@ -179,13 +181,27 @@ input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin
179 .picked { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-6); }181 .picked { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-6); }
180 .picked .pname { font-size: 20px; font-family: var(--font-heading); }182 .picked .pname { font-size: 20px; font-family: var(--font-heading); }
181 .mini-label { font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }183 .mini-label { font-size: 12px; opacity: .7; margin: 0 0 var(--space-2); }
182-.duration-row { display: flex; align-items: baseline; gap: 6px; margin-bottom: var(--space-3); }184+.duration-row { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
183-.duration-row .minutes-input {185+.stepper {
184- width: 130px; font-size: 34px; font-family: var(--font-heading);186+ display: flex; align-items: center; gap: var(--space-1);
185- min-height: 64px; text-align: center; padding: 0 10px;187+ background: var(--color-surface); border: 1px solid var(--color-divider);
188+ border-radius: 999px; padding: 5px 6px;
186 }189 }
187-.duration-row .unit { font-size: 16px; opacity: .6; }190+.stepper-btn {
188-.duration-row .pretty { margin-left: auto; font-size: 14px; opacity: .55; }191+ width: 40px; height: 40px; flex: none;
192+ display: flex; align-items: center; justify-content: center;
193+ border: none; border-radius: 999px; background: transparent;
194+ color: var(--color-text); cursor: pointer; text-decoration: none;
195+}
196+.stepper-btn:hover { background: var(--color-accent-200); }
197+.stepper-btn:active { background: var(--color-accent-300); }
198+.stepper .minutes-input {
199+ width: 92px; font-size: 32px; font-family: var(--font-heading);
200+ min-height: 44px; text-align: center; padding: 0;
201+ background: transparent; border-color: transparent;
202+}
203+.duration-row .unit { font-size: 15px; opacity: .7; }
204+.duration-row .pretty { font-size: 13px; opacity: .5; }
189 .presets { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }205 .presets { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-6); }
190 .preset {206 .preset {
191 padding: 9px 16px; border-radius: 999px; font-size: 14px;207 padding: 9px 16px; border-radius: 999px; font-size: 14px;
modified src/routes/entries.rs +6 -0
@@ -55,6 +55,9 @@ pub struct AddStep2Page {
5555 pub picked_name: String,
5656 pub minutes: i32,
5757 pub minutes_pretty: String,
58+ /// Steppers ± 5 minutes (liens, zéro JS).
59+ pub minus_href: String,
60+ pub plus_href: String,
5861 pub presets: Vec<Preset>,
5962 pub date: NaiveDate,
6063 pub date_label: String,
@@ -108,6 +111,9 @@ pub async fn entry_new(
108111 picked_name: picked.name.clone(),
109112 minutes,
110113 minutes_pretty: fmt_minutes(minutes as i64),
114+ // Comme la maquette : jamais sous 5 min via le stepper.
115+ minus_href: step2_href(picked.id, (minutes - 5).max(5), date),
116+ plus_href: step2_href(picked.id, (minutes + 5).min(1440), date),
111117 presets,
112118 date,
113119 date_label: day_label(date),
@@ -55,6 +55,9 @@ pub struct AddStep2Page {
55 pub picked_name: String,55 pub picked_name: String,
56 pub minutes: i32,56 pub minutes: i32,
57 pub minutes_pretty: String,57 pub minutes_pretty: String,
58+ /// Steppers ± 5 minutes (liens, zéro JS).
59+ pub minus_href: String,
60+ pub plus_href: String,
58 pub presets: Vec<Preset>,61 pub presets: Vec<Preset>,
59 pub date: NaiveDate,62 pub date: NaiveDate,
60 pub date_label: String,63 pub date_label: String,
@@ -108,6 +111,9 @@ pub async fn entry_new(
108 picked_name: picked.name.clone(),111 picked_name: picked.name.clone(),
109 minutes,112 minutes,
110 minutes_pretty: fmt_minutes(minutes as i64),113 minutes_pretty: fmt_minutes(minutes as i64),
114+ // Comme la maquette : jamais sous 5 min via le stepper.
115+ minus_href: step2_href(picked.id, (minutes - 5).max(5), date),
116+ plus_href: step2_href(picked.id, (minutes + 5).min(1440), date),
111 presets,117 presets,
112 date,118 date,
113 date_label: day_label(date),119 date_label: day_label(date),
modified templates/add_step2.html +14 -4
@@ -12,10 +12,20 @@
1212
1313 <p class="mini-label">Durée</p>
1414 <div class="duration-row">
15- <input class="input minutes-input" name="minutes" type="number" inputmode="numeric"
16- min="1" max="1440" required value="{{ minutes }}">
17- <span class="unit">minutes</span>
18- <span class="pretty">{{ minutes_pretty }}</span>
15+ <div class="stepper">
16+ <a class="stepper-btn" href="{{ minus_href }}" 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>
18+ </a>
19+ <input class="input minutes-input" name="minutes" type="number" inputmode="numeric"
20+ min="1" max="1440" step="5" required value="{{ minutes }}">
21+ <a class="stepper-btn" href="{{ plus_href }}" 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>
23+ </a>
24+ </div>
25+ <div>
26+ <div class="unit">minutes</div>
27+ <div class="pretty">{{ minutes_pretty }}</div>
28+ </div>
1929 </div>
2030 <div class="presets">
2131 {% for p in presets %}
@@ -12,10 +12,20 @@
12 12
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- <input class="input minutes-input" name="minutes" type="number" inputmode="numeric"15+ <div class="stepper">
16- min="1" max="1440" required value="{{ minutes }}">16+ <a class="stepper-btn" href="{{ minus_href }}" aria-label="Cinq minutes de moins">
17- <span class="unit">minutes</span>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- <span class="pretty">{{ minutes_pretty }}</span>18+ </a>
19+ <input class="input minutes-input" name="minutes" type="number" inputmode="numeric"
20+ min="1" max="1440" step="5" required value="{{ minutes }}">
21+ <a class="stepper-btn" href="{{ plus_href }}" 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>
23+ </a>
24+ </div>
25+ <div>
26+ <div class="unit">minutes</div>
27+ <div class="pretty">{{ minutes_pretty }}</div>
28+ </div>
19 </div>29 </div>
20 <div class="presets">30 <div class="presets">
21 {% for p in presets %}31 {% for p in presets %}