From a7e3f0782cffe703085a2d22fbd370269a2eea89 Mon Sep 17 00:00:00 2001 From: nathaninline Date: Tue, 28 Jul 2026 15:48:48 +0200 Subject: [PATCH] v0.6.1 : notifications de nouveau visibles + colonne de lecture alignee sur la saisie - Les notifications du bas d'ecran (#toast) n'avaient pas de z-index. Depuis que la mise en page en colonne rend le composer absolu (z-index 4), elles etaient peintes DESSOUS et n'apparaissaient plus. Elles passent au-dessus du composer, sous les modales. - La zone de chat reserve une gouttiere de barre de defilement de chaque cote (scrollbar-gutter: stable both-edges) ; le composer, lui, n'est pas defilant. Les messages etaient donc en retrait d'une gouttiere (~15 px) par rapport a la zone de saisie, ecart bien visible quand la barre laterale est escamotee. La gouttiere reelle est mesuree en JS et reportee sur le composer. --- cmd/jean/resource_windows_amd64.syso | Bin 8340 -> 8340 bytes cmd/jean/resource_windows_arm64.syso | Bin 8340 -> 8340 bytes cmd/jean/versioninfo.json | 6 +++--- internal/jean/run.go | 2 +- internal/jean/ui/index.html | 17 +++++++++++++++-- internal/jean/ui/src/js/08-chat-render.js | 13 +++++++++++++ internal/jean/ui/src/styles.css | 4 ++-- 7 files changed, 34 insertions(+), 8 deletions(-) diff --git a/cmd/jean/resource_windows_amd64.syso b/cmd/jean/resource_windows_amd64.syso index e279a65cdda2af52409ef5f6a1f4e59ea14d7f92..0ffb3f41c8619f4b289b89ac41367eeecccd909c 100644 GIT binary patch delta 36 ncmbQ@IK^>;lnf^$0~-SfFm6_s5oKaD+-xZq%m}1<<=GhlgY^c~ delta 36 mcmbQ@IK^>;lnf^W0~-SvY*v;LWnwhgY$+Ga2&8)D*%<+YvIfuq diff --git a/cmd/jean/resource_windows_arm64.syso b/cmd/jean/resource_windows_arm64.syso index d3c12182cec74c1262b17a489f7566583cf345ba..dfa093e0b67de21ab86e4cab446835faf40ac9e3 100644 GIT binary patch delta 36 ncmbQ@IK^>;lnf^$0~-SfFm6_s5oKaD+-xZq%m}1<<=GhlgY^c~ delta 36 mcmbQ@IK^>;lnf^W0~-SvY*v;LWnwhgY$+Ga2&8)D*%<+YvIfuq diff --git a/cmd/jean/versioninfo.json b/cmd/jean/versioninfo.json index 72897c0..c5563ae 100644 --- a/cmd/jean/versioninfo.json +++ b/cmd/jean/versioninfo.json @@ -3,13 +3,13 @@ "FileVersion": { "Major": 0, "Minor": 6, - "Patch": 0, + "Patch": 1, "Build": 0 }, "ProductVersion": { "Major": 0, "Minor": 6, - "Patch": 0, + "Patch": 1, "Build": 0 }, "FileFlagsMask": "3f", @@ -25,7 +25,7 @@ "LegalCopyright": "Copyright (c) 2026 AJEAN contributors. MIT License.", "OriginalFilename": "jean.exe", "ProductName": "AJEAN", - "ProductVersion": "0.6.0", + "ProductVersion": "0.6.1", "Comments": "https://github.com/nathaninline/jean — projet open source (MIT)" }, "VarFileInfo": { diff --git a/internal/jean/run.go b/internal/jean/run.go index 4918b61..307f2b2 100644 --- a/internal/jean/run.go +++ b/internal/jean/run.go @@ -10,7 +10,7 @@ import ( "strings" ) -const Version = "0.6.0" +const Version = "0.6.1" // Main est le vrai main() du binaire (cmd/jean ne fait que l'appeler). func Main() { diff --git a/internal/jean/ui/index.html b/internal/jean/ui/index.html index ed0b8d8..759f1c2 100644 --- a/internal/jean/ui/index.html +++ b/internal/jean/ui/index.html @@ -358,7 +358,7 @@ textarea.sctl{min-height:76px;resize:vertical;line-height:1.5} #input:focus{outline:none;border-color:var(--accent)} #send{padding:0 20px} .muted{color:var(--dim);font-size:13px} -#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--panel);border:1px solid var(--border);padding:8px 16px;border-radius:6px;opacity:0;transition:opacity .2s;pointer-events:none} +#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:50;background:var(--panel);border:1px solid var(--border);padding:8px 16px;border-radius:8px;opacity:0;transition:opacity .2s;pointer-events:none;box-shadow:0 8px 30px rgba(0,0,0,.18)} #toast.show{opacity:1} @keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}} #compact-banner{display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;color:var(--accent);background:var(--accent-bg);border:1px solid var(--border);border-radius:8px;padding:6px 10px;margin-bottom:8px} @@ -623,7 +623,7 @@ 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:max(16px,calc(50% - 380px));background:linear-gradient(to bottom,transparent 0,var(--bg) 34%)} +#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} #compact-banner{order:0;margin:0 var(--col) 8px;border-radius:14px} @@ -2168,6 +2168,19 @@ function isNearBottom(){ const c = chatEl(); return c.scrollHeight - c.scrollTop - c.clientHeight < 60; } +// La zone de chat réserve une gouttière de barre de défilement de chaque côté +// (scrollbar-gutter: stable both-edges) ; le composer, lui, n'est pas défilant. +// On mesure la gouttière réelle et on la reporte sur le composer, sinon les +// messages sont en retrait par rapport à la zone de saisie — décalage visible +// surtout quand la barre latérale est escamotée. +function syncGutter(){ + const chat=document.getElementById('chat'); if(!chat) return; + const g=Math.max(0,(chat.offsetWidth-chat.clientWidth)/2); + document.documentElement.style.setProperty('--sbw', g+'px'); +} +addEventListener('resize', syncGutter); +addEventListener('DOMContentLoaded', syncGutter); + function scrollMaybe(){ // Pendant le replay initial on NE force AUCUN reflow : lire scrollHeight à chaque // événement rejoué = un layout synchrone forcé sur un DOM qui grossit → coût diff --git a/internal/jean/ui/src/js/08-chat-render.js b/internal/jean/ui/src/js/08-chat-render.js index f5e379c..61c1e90 100644 --- a/internal/jean/ui/src/js/08-chat-render.js +++ b/internal/jean/ui/src/js/08-chat-render.js @@ -4,6 +4,19 @@ function isNearBottom(){ const c = chatEl(); return c.scrollHeight - c.scrollTop - c.clientHeight < 60; } +// La zone de chat réserve une gouttière de barre de défilement de chaque côté +// (scrollbar-gutter: stable both-edges) ; le composer, lui, n'est pas défilant. +// On mesure la gouttière réelle et on la reporte sur le composer, sinon les +// messages sont en retrait par rapport à la zone de saisie — décalage visible +// surtout quand la barre latérale est escamotée. +function syncGutter(){ + const chat=document.getElementById('chat'); if(!chat) return; + const g=Math.max(0,(chat.offsetWidth-chat.clientWidth)/2); + document.documentElement.style.setProperty('--sbw', g+'px'); +} +addEventListener('resize', syncGutter); +addEventListener('DOMContentLoaded', syncGutter); + function scrollMaybe(){ // Pendant le replay initial on NE force AUCUN reflow : lire scrollHeight à chaque // événement rejoué = un layout synchrone forcé sur un DOM qui grossit → coût diff --git a/internal/jean/ui/src/styles.css b/internal/jean/ui/src/styles.css index e2b107b..e90a025 100644 --- a/internal/jean/ui/src/styles.css +++ b/internal/jean/ui/src/styles.css @@ -339,7 +339,7 @@ textarea.sctl{min-height:76px;resize:vertical;line-height:1.5} #input:focus{outline:none;border-color:var(--accent)} #send{padding:0 20px} .muted{color:var(--dim);font-size:13px} -#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--panel);border:1px solid var(--border);padding:8px 16px;border-radius:6px;opacity:0;transition:opacity .2s;pointer-events:none} +#toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:50;background:var(--panel);border:1px solid var(--border);padding:8px 16px;border-radius:8px;opacity:0;transition:opacity .2s;pointer-events:none;box-shadow:0 8px 30px rgba(0,0,0,.18)} #toast.show{opacity:1} @keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}} #compact-banner{display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;color:var(--accent);background:var(--accent-bg);border:1px solid var(--border);border-radius:8px;padding:6px 10px;margin-bottom:8px} @@ -604,7 +604,7 @@ 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:max(16px,calc(50% - 380px));background:linear-gradient(to bottom,transparent 0,var(--bg) 34%)} +#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} #compact-banner{order:0;margin:0 var(--col) 8px;border-radius:14px}