feat(web): UI responsive mobile (header, barre chat, review) (v0.35.0)

Header flex-wrap + détails masqués sous sm ; barre chat input min-w-0 +
boutons compacts + label Envoyer masqué sous sm ; actions Review empilées
pleine largeur sur mobile. Build web vert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016w5jRe87MGdd6AMvXQcHNi
This commit is contained in:
Kantin-Petit
2026-06-23 16:06:56 +02:00
parent ef382274fe
commit 4f3c85901e
4 changed files with 25 additions and 15 deletions
+6 -5
View File
@@ -14,8 +14,8 @@ function Shell() {
return (
<div className="min-h-dvh flex flex-col">
<header className="flex items-center gap-2 border-b border-border bg-surface px-4 py-2">
<span className="font-bold tracking-wide text-accent glow mr-2">CHLOVA</span>
<header className="flex flex-wrap items-center gap-x-2 gap-y-1 border-b border-border bg-surface px-3 sm:px-4 py-2">
<span className="font-bold tracking-wide text-accent glow mr-1 sm:mr-2">CHLOVA</span>
<nav className="flex gap-1">
<NavLink to="/chat" className={link}>
<MessageSquare size={16} /> Chat
@@ -27,10 +27,11 @@ function Shell() {
)}
</NavLink>
</nav>
<span className="ml-auto flex items-center gap-1.5 text-xs text-muted" title="Phase · outils">
<Cpu size={14} /> {phase || "…"} · {tools} outils
<span className="ml-auto flex items-center gap-1.5 text-xs text-muted whitespace-nowrap" title={`Phase ${phase} · ${tools} outils`}>
<Cpu size={14} /> {phase || "…"}
<span className="hidden sm:inline">· {tools} outils</span>
</span>
<button onClick={logout} className="ml-3 text-muted hover:text-fg cursor-pointer" aria-label="Déconnexion" title="Déconnexion">
<button onClick={logout} className="ml-1 sm:ml-3 shrink-0 text-muted hover:text-fg cursor-pointer" aria-label="Déconnexion" title="Déconnexion">
<LogOut size={18} />
</button>
</header>
+7 -7
View File
@@ -100,20 +100,20 @@ export function Chat() {
<div ref={bottom} />
</div>
<form onSubmit={submit} className="flex items-center gap-2 border-t border-border bg-surface p-3">
<form onSubmit={submit} className="flex items-center gap-1.5 border-t border-border bg-surface p-2 sm:p-3">
{speech.ttsSupported && (
<button
type="button"
onClick={toggleSpeak}
aria-label={speakReplies ? "Couper la voix" : "Activer la voix"}
title={speakReplies ? "Voix activée" : "Voix coupée"}
className={`rounded-md border px-3 py-2 cursor-pointer ring-accent ${speakReplies ? "border-accent text-accent" : "border-border text-muted"}`}
className={`shrink-0 rounded-md border px-2.5 sm:px-3 py-2 cursor-pointer ring-accent ${speakReplies ? "border-accent text-accent" : "border-border text-muted"}`}
>
{speakReplies ? <Volume2 size={18} /> : <VolumeX size={18} />}
</button>
)}
<input
className="flex-1 rounded-md bg-surface-2 border border-border px-3 py-2 text-fg placeholder:text-muted ring-accent"
className="flex-1 min-w-0 rounded-md bg-surface-2 border border-border px-3 py-2 text-fg placeholder:text-muted ring-accent"
placeholder={speech.listening ? "Écoute…" : "Message…"}
value={input}
onChange={(e) => setInput(e.target.value)}
@@ -124,7 +124,7 @@ export function Chat() {
type="button"
onClick={mic}
aria-label={speech.listening ? "Arrêter le micro" : "Parler"}
className={`rounded-md border px-3 py-2 cursor-pointer ring-accent ${speech.listening ? "border-accent text-accent animate-pulse" : "border-border text-muted"}`}
className={`shrink-0 rounded-md border px-2.5 sm:px-3 py-2 cursor-pointer ring-accent ${speech.listening ? "border-accent text-accent animate-pulse" : "border-border text-muted"}`}
>
{speech.listening ? <Square size={18} /> : <Mic size={18} />}
</button>
@@ -135,7 +135,7 @@ export function Chat() {
onClick={toggleHandsFree}
aria-label={speech.handsFree ? "Couper les mains libres" : "Activer les mains libres"}
title="Mains libres (wake-word CHLOVA)"
className={`rounded-md border px-3 py-2 cursor-pointer ring-accent ${speech.handsFree ? "border-accent text-accent" : "border-border text-muted"}`}
className={`shrink-0 rounded-md border px-2.5 sm:px-3 py-2 cursor-pointer ring-accent ${speech.handsFree ? "border-accent text-accent" : "border-border text-muted"}`}
>
<Radio size={18} />
</button>
@@ -144,9 +144,9 @@ export function Chat() {
type="submit"
disabled={busy || !input.trim()}
aria-label="Envoyer"
className="flex items-center gap-1.5 rounded-md bg-accent px-4 py-2 font-medium text-bg disabled:opacity-50 ring-accent cursor-pointer"
className="flex shrink-0 items-center gap-1.5 rounded-md bg-accent px-3 sm:px-4 py-2 font-medium text-bg disabled:opacity-50 ring-accent cursor-pointer"
>
<Send size={16} /> Envoyer
<Send size={16} /> <span className="hidden sm:inline">Envoyer</span>
</button>
</form>
</div>
+3 -3
View File
@@ -39,16 +39,16 @@ export function Review() {
expire {new Date(a.expiresAt).toISOString().slice(0, 10)}
</span>
)}
<div className="ml-auto flex gap-2">
<div className="flex gap-2 w-full sm:w-auto sm:ml-auto">
<button
onClick={() => void approve(a.id)}
className="flex items-center gap-1 rounded-md bg-success/15 text-success border border-success/40 px-3 py-1 text-sm cursor-pointer ring-accent"
className="flex flex-1 sm:flex-none items-center justify-center gap-1 rounded-md bg-success/15 text-success border border-success/40 px-3 py-1 text-sm cursor-pointer ring-accent"
>
<Check size={15} /> Approuver
</button>
<button
onClick={() => onRefuse(a.id)}
className="flex items-center gap-1 rounded-md bg-danger/15 text-danger border border-danger/50 px-3 py-1 text-sm cursor-pointer ring-accent"
className="flex flex-1 sm:flex-none items-center justify-center gap-1 rounded-md bg-danger/15 text-danger border border-danger/50 px-3 py-1 text-sm cursor-pointer ring-accent"
>
<X size={15} /> Refuser
</button>