Refonte de l'interface : direction « Sober Tech »

Reprise du design d'après la maquette fournie, sans changer d'architecture :
l'UI reste du HTML/CSS/JS assemblé dans le binaire (voir plus bas).

Charte
- Palette ardoise + sauge en remplacement des bruns « Terre ». Deux variantes :
  claire par défaut (celle de la maquette) et « Deep Dark » (fond #0F172A,
  cartes #1E293B), à un clic depuis l'en-tête. Une variable --on-accent porte ce
  qui s'écrit sur les aplats de sauge, pour que le contraste tienne dans les
  deux variantes.
- Typographie Inter (interface) + JetBrains Mono (code, chiffres, chemins), en
  sous-ensemble latin, embarquées comme l'étaient Bricolage et IBM Plex Mono —
  toujours aucune requête vers un service de polices.
- Boutons sans contour, fond au survol, léger enfoncement au clic.
- Coque à plat : plus de cartes flottantes séparées par une gouttière, la barre
  latérale est collée au bord et le fil occupe tout le reste.

Coque
- Barre d'en-tête : titre de la discussion + sélecteur de modèle. Changer de
  preset demandait d'ouvrir la barre latérale et de descendre jusqu'aux
  presets ; c'est désormais une liste déroulante, toujours visible.
- Barre latérale en trois zones — marque, contenu défilant, moniteur machine —
  et escamotable d'un clic sur grand écran. Les discussions y passent au
  premier plan, avec une recherche textuelle (filtrage côté client : la liste
  est déjà chargée, sans les messages) ; les réglages descendent sous un repli
  unique, d'où openDetails(), qui déplie aussi les parents.
- Moniteur machine en pied de colonne : une jauge par ressource (charge GPU,
  puis VRAM et température en détail, mémoire vive), sauge jusqu'à 75 %, ambre
  puis rouille quand la machine sature. Il remplace la section « Machine », qui
  disait la même chose en plus verbeux et en plus loin.
- L'option « barre latérale escamotable » disparaît d'Apparence : elle faisait
  de la barre un tiroir posé SUR la conversation, là où le bouton d'en-tête
  l'escamote pour de bon. Deux mécanismes concurrents pour la même intention.

Fil et saisie
- La réponse de l'IA redevient une carte, la question un aplat de sauge : sur un
  fond de fil coloré, du texte nu flottait sans ancrage.
- Saisie en pilule, ses outils (joindre, fichiers, envoyer) dans la barre
  elle-même. L'envoi est une pastille ronde à flèche ; le mot « Envoyer » reste
  porté par aria-label et l'infobulle.

Corrections croisées
- L'heure d'une discussion prenait la moitié de la ligne (flex:1 hérité de
  `.preset>span`), le titre était tronqué au premier mot.
- Une liste déroulante posée directement dans une ligne de modale débordait
  sous son intitulé quand sa valeur était longue (chemin de destination).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd
This commit is contained in:
Claude committed 2026-08-16 16:17:59 +00:00
1 parent 7310c84129
commit f99e5b59b8
16 files changed
+1160 -255

No files matched your search

+4 -4
View File
@@ -28,13 +28,13 @@ async function loadLlamacpp(){
// Job en cours (page rechargée pendant une install) → on raccroche l'affichage.
if(s.job && s.job.exists && s.job.running && !lcPoll){
document.getElementById('lc-details').open = true;
openDetails('lc-details');
lcStartPolling();
}
// Job terminé/interrompu qu'on n'a pas encore montré (rechargement APRÈS coup,
// typiquement quand le service a redémarré) : on l'affiche sans polling.
else if(s.job && s.job.exists && !s.job.running && !lcPoll && s.job.error && !lcEndShown){
document.getElementById('lc-details').open = true;
openDetails('lc-details');
document.getElementById('lc-job').style.display = '';
lcLogNext = 0;
document.getElementById('lc-log').textContent = '';
@@ -73,7 +73,7 @@ function lcChipOpen(){
const side = document.getElementById('side');
if(!side.classList.contains('open')) toggleSide();
const det = document.getElementById('lc-details');
det.open = true;
openDetails(det); // déplie aussi « Réglages », qui contient la section
det.scrollIntoView({block:'center'});
if(!document.getElementById('lc-chip').classList.contains('failed')) return;
lcSeenEnd = true;
@@ -235,7 +235,7 @@ async function lcInstallCustom(){
const r = await jpost('/api/llamacpp/install-custom', {repo:url, name});
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
closeCustomBackends();
document.getElementById('lc-details').open = true;
openDetails('lc-details');
lcStartPolling();
}