diff --git a/README.md b/README.md index a06ce7b..368e9db 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,9 @@ des pages HTML **servies localement** par l'application elle-même : - **Statistiques** affiche les pomodoros du jour / semaine, la série de jours consécutifs, le total et l'historique des 7 derniers jours. - **Réglages** présente un formulaire complet (durées, objectif, son, langue, - profil actif, rappels santé) : l'enregistrement est appliqué immédiatement - par l'application. + rappels santé) avec un **éditeur de périodes** : créez, modifiez ou supprimez + vos propres profils (nom, travail, pauses, cycles) et choisissez la période + active. L'enregistrement est appliqué immédiatement par l'application. L'application lance un petit serveur sur `127.0.0.1` (premier port libre à partir de `38943`), uniquement accessible en local. Aucune donnée ne quitte diff --git a/src/webserver.nim b/src/webserver.nim index 33a7135..ff26dfe 100644 --- a/src/webserver.nim +++ b/src/webserver.nim @@ -256,6 +256,16 @@ input[type=number]:focus,select:focus{outline:none;border-color:#14b8a6;box-shad .mini:hover{background:#f0fdfa;border-color:#5eead4} .mini.danger{color:#b91c1c} .mini.danger:hover{background:#fef2f2;border-color:#fca5a5} +.proflist{display:flex;flex-direction:column;gap:.8rem} +.profilrow{background:#fff;border:1px solid #e2e8f0;border-radius:14px;padding:.9rem 1rem;box-shadow:0 2px 8px rgba(15,118,110,.05)} +.profilrow.active{border-color:#5eead4;box-shadow:0 0 0 2px rgba(20,184,166,.15)} +.phead{display:flex;align-items:center;gap:.7rem;margin-bottom:.6rem} +.pname{flex:1;min-width:0;padding:.45rem .6rem;border:1.5px solid #cbd5e1;border-radius:9px;font-size:.98rem;font-family:inherit;color:#1e293b;background:#fff} +.pfields{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:.6rem} +.pcell{display:flex;flex-direction:column;gap:.25rem;font-size:.85rem;font-weight:600;color:#64748b} +.pcell input{width:100%;padding:.4rem .5rem;border:1.5px solid #cbd5e1;border-radius:9px;font-size:.95rem;font-family:inherit;color:#1e293b;background:#fff} +.pcell input:focus,.pname:focus{outline:none;border-color:#14b8a6;box-shadow:0 0 0 3px rgba(20,184,166,.18)} +.activepick{display:flex;align-items:center;gap:.35rem;font-weight:700;color:#0f766e;cursor:pointer;white-space:nowrap} .saved{text-align:center;padding:2.5rem 1.5rem} .savedemoji{font-size:3rem;margin-bottom:.4rem} footer{margin-top:2.8rem;padding-top:1.2rem;border-top:1px solid #e2e8f0;color:#94a3b8;font-size:.9rem;text-align:center} @@ -281,6 +291,9 @@ footer{margin-top:2.8rem;padding-top:1.2rem;border-top:1px solid #e2e8f0;color:# .progress{background:#1e293b} .empty{color:#94a3b8;border-color:#334155} .remrow.off{opacity:.55} + .profilrow{background:#0f172a;border-color:#1e293b} + .pname,.pcell input{background:#0b1220;color:#e2e8f0;border-color:#334155} + .activepick{color:#5eead4} } @@ -333,17 +346,19 @@ proc renderHelp*(cfg: Config): string = b.add "

⏱️ " & t(lang, "Les périodes", "The periods") & "

" b.add "

" & t(lang, - "Un cycle classique : travail (25 min), pause courte (5 min) puis, après plusieurs cycles, une pause longue (15 min). Tout est configurable via les profils :", - "A classic cycle: work (25 min), short break (5 min) then, after several cycles, a long break (15 min). Everything is configurable via the profiles:") & "

" - b.add "" - b.add "" - b.add "" - b.add "
👤 " & t(lang, "Profil", "Profile") & "💼 " & t(lang, "Travail", "Work") & - "☕ " & t(lang, "Pause courte", "Short break") & "🛋️ " & t(lang, "Pause longue", "Long break") & - "🔁 " & t(lang, "Cycles", "Cycles") & "
" & t(lang, "Classique", "Classic") & "25 min5 min15 min4
Deep Work50 min10 min20 min4
Sprint15 min3 min10 min6
" + "Un cycle enchaîne travail, pause courte puis, après plusieurs cycles, une pause longue. Créez et modifiez vos propres périodes depuis la page ⚙️ Réglages :", + "A cycle chains work, short break then, after several cycles, a long break. Create and edit your own profiles from the ⚙️ Settings page:") & "

" + b.add "" + for p in cfg.profiles: + let star = if p.name == cfg.activeProfile: "⭐" else: "" + b.add "" + b.add "
⭐ " & t(lang, "Active", "Active") & "👤 " & t(lang, "Période", "Profile") & + "💼 " & t(lang, "Travail", "Work") & "☕ " & t(lang, "Pause courte", "Short break") & + "🛋️ " & t(lang, "Pause longue", "Long break") & "🔁 " & t(lang, "Cycles", "Cycles") & "
" & star & "" & htmlEscape(p.name) & "" & $p.workMin & + "" & $p.shortBreakMin & "" & $p.longBreakMin & "" & $p.cycles & "
" b.add "

" & t(lang, - "Le profil actif se choisit dans le menu de l'icône (« Profils »).", - "The active profile is chosen from the icon menu (“Profiles”).") & "

" + "La période active est choisie dans le menu de l'icône (« Profils ») ou dans les réglages.", + "The active profile is chosen from the icon menu (“Profiles”) or in settings.") & "

" b.add "

☕ " & t(lang, "Pendant une pause", "During a break") & "

" b.add "