v0.6.2 : carte de saisie correctement posee en bas sur iPhone (PWA) + listes deroulantes lisibles en sombre

Coque en 100vh au lieu de 100dvh : mesure faite sur iPhone en PWA, la vue web
couvre 956 pt mais la fenetre de mise en page n'en fait que 894, calee en haut.
100dvh (comme height:100%) vaut 894 -> il restait une bande morte de 62 pt sous
la carte de saisie, qui se recalait au premier defilement. 100vh se refere au
grand viewport et vaut bien 956.

La marge de zone sure passe du <body> a la carte elle-meme : geometrie
identique, mais l'arrondi bas reste detache du fond.

Listes deroulantes : la liste ouverte d'un <select> n'herite pas du fond de son
select ; nos selects transparents a texte clair donnaient du texte clair sur
fond blanc en theme sombre (signale sur Cache KV, en fait toutes les listes).
Les <option>/<optgroup> portent desormais les couleurs du theme.
This commit is contained in:
nathaninline committed 2026-07-29 00:04:31 +02:00
1 parent a7e3f0782c
commit a3a9c36367
6 files changed
+92 -22

No files matched your search

Binary file not shown.
Binary file not shown.
+3 -3
View File
@@ -3,13 +3,13 @@
"FileVersion": {
"Major": 0,
"Minor": 6,
"Patch": 1,
"Patch": 2,
"Build": 0
},
"ProductVersion": {
"Major": 0,
"Minor": 6,
"Patch": 1,
"Patch": 2,
"Build": 0
},
"FileFlagsMask": "3f",
@@ -25,7 +25,7 @@
"LegalCopyright": "Copyright (c) 2026 AJEAN contributors. MIT License.",
"OriginalFilename": "jean.exe",
"ProductName": "AJEAN",
"ProductVersion": "0.6.1",
"ProductVersion": "0.6.2",
"Comments": "https://github.com/nathaninline/jean — projet open source (MIT)"
},
"VarFileInfo": {
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"strings"
)
const Version = "0.6.1"
const Version = "0.6.2"
// Main est le vrai main() du binaire (cmd/jean ne fait que l'appeler).
func Main() {
+44 -9
View File
@@ -24,12 +24,39 @@
:root{color-scheme:light;--font:-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,Helvetica,Arial,sans-serif;--bubble:#f0f0f0;--bg:#ffffff;--panel:#fafafa;--border:#e0e0e2;--text:#0a0a0a;--dim:#6b6b70;--accent:#0a0a0a;--accent-bg:rgba(0,0,0,.05);--ok:#0a0a0a;--warn:#6b6b6b;--err:#c0392b;--mag:#6b6b6b;--code-bg:#f5f5f5;--danger-bg:#fbeae8;--warn-bg:#f2f2f2;--add:#1a7f37;--add-bg:rgba(26,127,55,.10);--del:#cf222e;--del-bg:rgba(207,34,46,.10)}
[data-theme="dark"]{color-scheme:dark;--bubble:#232326;--bg:#0b0b0c;--panel:#161618;--border:#33333a;--text:#f2f2f4;--dim:#a0a0a8;--accent:#f5f5f5;--accent-bg:rgba(255,255,255,.07);--ok:#f5f5f5;--warn:#8e8e8e;--err:#f2777a;--mag:#8e8e8e;--code-bg:#000000;--danger-bg:#2e1a19;--warn-bg:#1c1c1c;--add:#4ac26b;--add-bg:rgba(74,194,107,.13);--del:#f85149;--del-bg:rgba(248,81,73,.13)}
*{box-sizing:border-box}
body{margin:0;font-family:var(--font);background:var(--bg);color:var(--text);height:100vh;height:100dvh;display:flex;font-size:14px}
/* ⚠️ NE PAS mettre overflow:hidden sur html/body (tenté puis retiré le
2026-07-28) : en PWA iOS, si le document ne peut plus défiler, WebKit décale
TOUTE la mise en page à l'ouverture du clavier pour montrer le champ actif —
la carte de saisie se retrouve plaquée en haut de l'écran. Le rebond
élastique du document est le prix à payer ; il est cosmétique, le clavier
ne l'est pas. Le défilement du fil reste borné par #chat (overscroll:contain). */
/* Hauteur de la coque : 100vh, et SURTOUT ni 100dvh ni 100%.
Mesuré sur iPhone en PWA (2026-07-28) : la vue web couvre tout l'écran
(956 pt — le contenu passe bien sous l'horloge), mais la fenêtre de mise en
page ne fait que 894 pt et reste calée en haut. Or 100dvh ET 100% valent tous
deux 894 → il restait une bande morte de 62 pt (= la zone sûre du haut) en bas
de l'écran, sous la carte de saisie. 100vh se réfère au GRAND viewport, celui
qui vaut bien 956 : c'est la seule unité juste ici.
⚠️ Ne pas y ajouter overflow:hidden : voir plus bas, ça casse le clavier iOS. */
body{margin:0;font-family:var(--font);background:var(--bg);color:var(--text);height:100vh;overscroll-behavior:none;display:flex;font-size:14px}
/* PWA plein écran (viewport-fit=cover) : on décale le contenu des bords pour ne
pas passer sous l'encoche / la barre système / l'indicateur d'accueil. Les
env(safe-area-inset-*) valent 0 hors PWA, donc aucun impact ailleurs. */
body{padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)}
.side{width:320px;border-right:1px solid var(--border);padding:16px;overflow-y:auto;flex-shrink:0}
env(safe-area-inset-*) valent 0 hors PWA, donc aucun impact ailleurs.
⚠️ PAS de padding-bas ici : le composer est posé en bottom:0 DANS le body, donc
une marge basse le décollerait du bord de l'écran et laisserait une bande de
fond visible sous la carte (visible seulement en PWA, où l'inset vaut ~34 px).
L'indicateur d'accueil est esquivé bloc par bloc, en padding INTERNE. */
body{padding:env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left)}
/* Listes déroulantes : la LISTE ouverte n'hérite pas du fond de son <select>.
Plusieurs de nos select sont en background:transparent + color clair (chevron
discret) : en thème sombre, le navigateur peignait donc du texte clair sur le
fond blanc par défaut de la liste — illisible (signalé sur « Cache KV », mais
ça touchait TOUTES les listes déroulantes en sombre). On habille donc les
<option> eux-mêmes ; color-scheme (posé sur <html>) ne suffit pas dès que le
select porte des couleurs explicites. */
select{color-scheme:inherit}
option,optgroup{background:var(--panel);color:var(--text)}
.side{width:320px;border-right:1px solid var(--border);padding:16px;padding-bottom:calc(16px + env(safe-area-inset-bottom));overflow-y:auto;flex-shrink:0}
.main{flex:1;display:flex;flex-direction:column;min-width:0}
#menubtn{display:none;position:fixed;top:calc(10px + env(safe-area-inset-top));left:calc(10px + env(safe-area-inset-left));z-index:20;background:var(--panel);border:1px solid var(--border);color:var(--text);width:40px;height:40px;border-radius:6px;font-size:18px;cursor:pointer}
#backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:10}
@@ -167,7 +194,7 @@ button:disabled{opacity:.5;cursor:not-allowed}
.kv span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;unicode-bidi:plaintext;text-align:right;min-width:0;color:var(--dim)}
.bar{height:5px;background:var(--border);border-radius:3px;overflow:hidden;margin:0}
.bar>div{height:100%;background:var(--accent)}
#chat{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:14px}
#chat{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:20px;display:flex;flex-direction:column;gap:14px}
:root{--col:max(20px,calc(50% - 450px))}
@media (max-width:720px){#chat{padding:60px 8px 12px}}
.msg{max-width:80%;padding:10px 14px;border-radius:10px;white-space:pre-wrap;word-wrap:break-word;line-height:1.45}
@@ -382,7 +409,7 @@ textarea.sctl{min-height:76px;resize:vertical;line-height:1.5}
/* Tiroir latéral : on décale le TIROIR ENTIER après l'encoche (left = inset)
au lieu de padder à l'intérieur — sinon grosse bordure vide à gauche qui
rétrécit le contenu. Padding interne normal → largeur utile pleine. */
.side{width:300px;max-width:300px;left:env(safe-area-inset-left);padding:calc(14px + env(safe-area-inset-top)) 14px 14px 14px}
.side{width:300px;max-width:300px;left:env(safe-area-inset-left);padding:calc(14px + env(safe-area-inset-top)) 14px calc(14px + env(safe-area-inset-bottom)) 14px}
#chat{padding:48px 10px 6px;gap:7px}
.msg{padding:6px 10px;border-radius:8px;max-width:78%}
#chat .msg.assistant,#chat .msg.reasoning{max-width:88%}
@@ -623,9 +650,12 @@ h1{color:var(--text);font-weight:600;letter-spacing:-.01em}
(overflow:hidden sur le rayon). Les trois blocs sont des frères dans le HTML :
on les recolle en dessinant les bordures par morceaux et l'ordre visuel vient
de l'ordre flex — aucun changement de markup. */
#composer{position:absolute;left:0;right:0;bottom:0;z-index:4;border-top:none;display:flex;flex-direction:column;padding:34px 0 8px;--col:calc(max(16px,calc(50% - 380px)) + var(--sbw,0px));background:linear-gradient(to bottom,transparent 0,var(--bg) 34%)}
#chat{padding-bottom:170px}
#scrollbtn{bottom:180px;border-radius:999px}
/* Le padding BAS dégage l'indicateur d'accueil de l'iPhone en PWA : la carte
flotte au-dessus de lui, son arrondi bas reste donc bien visible. Hors PWA
l'inset vaut 0 → strictement les 8 px d'origine. */
#composer{position:absolute;left:0;right:0;bottom:0;z-index:4;border-top:none;display:flex;flex-direction:column;padding:34px 0 calc(8px + env(safe-area-inset-bottom));--col:calc(max(16px,calc(50% - 380px)) + var(--sbw,0px));background:linear-gradient(to bottom,transparent 0,var(--bg) 34%)}
#chat{padding-bottom:calc(170px + env(safe-area-inset-bottom))}
#scrollbtn{bottom:calc(180px + env(safe-area-inset-bottom));border-radius:999px}
#compact-banner{order:0;margin:0 var(--col) 8px;border-radius:14px}
#inputbar{order:1;margin:0 var(--col);padding:8px 8px 8px 16px;gap:8px;align-items:flex-end;background:var(--panel);border:1px solid var(--border);border-bottom:none;border-radius:26px 26px 0 0}
#input{background:transparent;border:none;border-radius:0;padding:9px 0;min-height:36px;line-height:18px;max-height:160px}
@@ -641,6 +671,11 @@ h1{color:var(--text);font-weight:600;letter-spacing:-.01em}
découper la jauge dans sa propre forme — la barre est bien épaisse ET rognée
exactement sur la courbe, symétrique du haut. */
#ctxmeta{order:2;margin:0 var(--col);padding:6px 16px 15px;gap:10px;background:var(--panel);border:1px solid var(--border);border-top:none;border-radius:0 0 26px 26px;overflow:hidden}
/* ⚠️ NE PAS piloter la position du composer en JS quand le clavier s'ouvre
(tenté puis retiré le 2026-07-28, deux fois) : ni asservir la hauteur de la
coque à visualViewport.height, ni décaler le composer de la hauteur du
clavier. Dans les deux cas la carte part en haut de l'écran en PWA iOS.
iOS gère déjà correctement le clavier tout seul — on le laisse faire. */
#ctx-text,#status-preset{color:var(--dim);font-size:10px;letter-spacing:.02em}
#ctx-compact{border-radius:999px;padding:2px 10px;font-size:10px;background:transparent;border-color:var(--border);color:var(--dim)}
#ctx-compact:hover{border-color:var(--dim);color:var(--text)}
+44 -9
View File
@@ -5,12 +5,39 @@
:root{color-scheme:light;--font:-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,Helvetica,Arial,sans-serif;--bubble:#f0f0f0;--bg:#ffffff;--panel:#fafafa;--border:#e0e0e2;--text:#0a0a0a;--dim:#6b6b70;--accent:#0a0a0a;--accent-bg:rgba(0,0,0,.05);--ok:#0a0a0a;--warn:#6b6b6b;--err:#c0392b;--mag:#6b6b6b;--code-bg:#f5f5f5;--danger-bg:#fbeae8;--warn-bg:#f2f2f2;--add:#1a7f37;--add-bg:rgba(26,127,55,.10);--del:#cf222e;--del-bg:rgba(207,34,46,.10)}
[data-theme="dark"]{color-scheme:dark;--bubble:#232326;--bg:#0b0b0c;--panel:#161618;--border:#33333a;--text:#f2f2f4;--dim:#a0a0a8;--accent:#f5f5f5;--accent-bg:rgba(255,255,255,.07);--ok:#f5f5f5;--warn:#8e8e8e;--err:#f2777a;--mag:#8e8e8e;--code-bg:#000000;--danger-bg:#2e1a19;--warn-bg:#1c1c1c;--add:#4ac26b;--add-bg:rgba(74,194,107,.13);--del:#f85149;--del-bg:rgba(248,81,73,.13)}
*{box-sizing:border-box}
body{margin:0;font-family:var(--font);background:var(--bg);color:var(--text);height:100vh;height:100dvh;display:flex;font-size:14px}
/* ⚠️ NE PAS mettre overflow:hidden sur html/body (tenté puis retiré le
2026-07-28) : en PWA iOS, si le document ne peut plus défiler, WebKit décale
TOUTE la mise en page à l'ouverture du clavier pour montrer le champ actif —
la carte de saisie se retrouve plaquée en haut de l'écran. Le rebond
élastique du document est le prix à payer ; il est cosmétique, le clavier
ne l'est pas. Le défilement du fil reste borné par #chat (overscroll:contain). */
/* Hauteur de la coque : 100vh, et SURTOUT ni 100dvh ni 100%.
Mesuré sur iPhone en PWA (2026-07-28) : la vue web couvre tout l'écran
(956 pt — le contenu passe bien sous l'horloge), mais la fenêtre de mise en
page ne fait que 894 pt et reste calée en haut. Or 100dvh ET 100% valent tous
deux 894 → il restait une bande morte de 62 pt (= la zone sûre du haut) en bas
de l'écran, sous la carte de saisie. 100vh se réfère au GRAND viewport, celui
qui vaut bien 956 : c'est la seule unité juste ici.
⚠️ Ne pas y ajouter overflow:hidden : voir plus bas, ça casse le clavier iOS. */
body{margin:0;font-family:var(--font);background:var(--bg);color:var(--text);height:100vh;overscroll-behavior:none;display:flex;font-size:14px}
/* PWA plein écran (viewport-fit=cover) : on décale le contenu des bords pour ne
pas passer sous l'encoche / la barre système / l'indicateur d'accueil. Les
env(safe-area-inset-*) valent 0 hors PWA, donc aucun impact ailleurs. */
body{padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)}
.side{width:320px;border-right:1px solid var(--border);padding:16px;overflow-y:auto;flex-shrink:0}
env(safe-area-inset-*) valent 0 hors PWA, donc aucun impact ailleurs.
⚠️ PAS de padding-bas ici : le composer est posé en bottom:0 DANS le body, donc
une marge basse le décollerait du bord de l'écran et laisserait une bande de
fond visible sous la carte (visible seulement en PWA, où l'inset vaut ~34 px).
L'indicateur d'accueil est esquivé bloc par bloc, en padding INTERNE. */
body{padding:env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left)}
/* Listes déroulantes : la LISTE ouverte n'hérite pas du fond de son <select>.
Plusieurs de nos select sont en background:transparent + color clair (chevron
discret) : en thème sombre, le navigateur peignait donc du texte clair sur le
fond blanc par défaut de la liste — illisible (signalé sur « Cache KV », mais
ça touchait TOUTES les listes déroulantes en sombre). On habille donc les
<option> eux-mêmes ; color-scheme (posé sur <html>) ne suffit pas dès que le
select porte des couleurs explicites. */
select{color-scheme:inherit}
option,optgroup{background:var(--panel);color:var(--text)}
.side{width:320px;border-right:1px solid var(--border);padding:16px;padding-bottom:calc(16px + env(safe-area-inset-bottom));overflow-y:auto;flex-shrink:0}
.main{flex:1;display:flex;flex-direction:column;min-width:0}
#menubtn{display:none;position:fixed;top:calc(10px + env(safe-area-inset-top));left:calc(10px + env(safe-area-inset-left));z-index:20;background:var(--panel);border:1px solid var(--border);color:var(--text);width:40px;height:40px;border-radius:6px;font-size:18px;cursor:pointer}
#backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:10}
@@ -148,7 +175,7 @@ button:disabled{opacity:.5;cursor:not-allowed}
.kv span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;unicode-bidi:plaintext;text-align:right;min-width:0;color:var(--dim)}
.bar{height:5px;background:var(--border);border-radius:3px;overflow:hidden;margin:0}
.bar>div{height:100%;background:var(--accent)}
#chat{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:14px}
#chat{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:20px;display:flex;flex-direction:column;gap:14px}
:root{--col:max(20px,calc(50% - 450px))}
@media (max-width:720px){#chat{padding:60px 8px 12px}}
.msg{max-width:80%;padding:10px 14px;border-radius:10px;white-space:pre-wrap;word-wrap:break-word;line-height:1.45}
@@ -363,7 +390,7 @@ textarea.sctl{min-height:76px;resize:vertical;line-height:1.5}
/* Tiroir latéral : on décale le TIROIR ENTIER après l'encoche (left = inset)
au lieu de padder à l'intérieur — sinon grosse bordure vide à gauche qui
rétrécit le contenu. Padding interne normal → largeur utile pleine. */
.side{width:300px;max-width:300px;left:env(safe-area-inset-left);padding:calc(14px + env(safe-area-inset-top)) 14px 14px 14px}
.side{width:300px;max-width:300px;left:env(safe-area-inset-left);padding:calc(14px + env(safe-area-inset-top)) 14px calc(14px + env(safe-area-inset-bottom)) 14px}
#chat{padding:48px 10px 6px;gap:7px}
.msg{padding:6px 10px;border-radius:8px;max-width:78%}
#chat .msg.assistant,#chat .msg.reasoning{max-width:88%}
@@ -604,9 +631,12 @@ h1{color:var(--text);font-weight:600;letter-spacing:-.01em}
(overflow:hidden sur le rayon). Les trois blocs sont des frères dans le HTML :
on les recolle en dessinant les bordures par morceaux et l'ordre visuel vient
de l'ordre flex — aucun changement de markup. */
#composer{position:absolute;left:0;right:0;bottom:0;z-index:4;border-top:none;display:flex;flex-direction:column;padding:34px 0 8px;--col:calc(max(16px,calc(50% - 380px)) + var(--sbw,0px));background:linear-gradient(to bottom,transparent 0,var(--bg) 34%)}
#chat{padding-bottom:170px}
#scrollbtn{bottom:180px;border-radius:999px}
/* Le padding BAS dégage l'indicateur d'accueil de l'iPhone en PWA : la carte
flotte au-dessus de lui, son arrondi bas reste donc bien visible. Hors PWA
l'inset vaut 0 → strictement les 8 px d'origine. */
#composer{position:absolute;left:0;right:0;bottom:0;z-index:4;border-top:none;display:flex;flex-direction:column;padding:34px 0 calc(8px + env(safe-area-inset-bottom));--col:calc(max(16px,calc(50% - 380px)) + var(--sbw,0px));background:linear-gradient(to bottom,transparent 0,var(--bg) 34%)}
#chat{padding-bottom:calc(170px + env(safe-area-inset-bottom))}
#scrollbtn{bottom:calc(180px + env(safe-area-inset-bottom));border-radius:999px}
#compact-banner{order:0;margin:0 var(--col) 8px;border-radius:14px}
#inputbar{order:1;margin:0 var(--col);padding:8px 8px 8px 16px;gap:8px;align-items:flex-end;background:var(--panel);border:1px solid var(--border);border-bottom:none;border-radius:26px 26px 0 0}
#input{background:transparent;border:none;border-radius:0;padding:9px 0;min-height:36px;line-height:18px;max-height:160px}
@@ -622,6 +652,11 @@ h1{color:var(--text);font-weight:600;letter-spacing:-.01em}
découper la jauge dans sa propre forme — la barre est bien épaisse ET rognée
exactement sur la courbe, symétrique du haut. */
#ctxmeta{order:2;margin:0 var(--col);padding:6px 16px 15px;gap:10px;background:var(--panel);border:1px solid var(--border);border-top:none;border-radius:0 0 26px 26px;overflow:hidden}
/* ⚠️ NE PAS piloter la position du composer en JS quand le clavier s'ouvre
(tenté puis retiré le 2026-07-28, deux fois) : ni asservir la hauteur de la
coque à visualViewport.height, ni décaler le composer de la hauteur du
clavier. Dans les deux cas la carte part en haut de l'écran en PWA iOS.
iOS gère déjà correctement le clavier tout seul — on le laisse faire. */
#ctx-text,#status-preset{color:var(--dim);font-size:10px;letter-spacing:.02em}
#ctx-compact{border-radius:999px;padding:2px 10px;font-size:10px;background:transparent;border-color:var(--border);color:var(--dim)}
#ctx-compact:hover{border-color:var(--dim);color:var(--text)}