Theme neo-brutaliste + panneau raisonnement + repli sans outils

UI : reskin complet vers un theme neo-brutaliste clair (bordures noires 3px,
ombres dures, accent orange, polices Press Start 2P + DM Mono).
- tailwind.config / index.css / index.html : palette, polices, ombres, scrollbars
- TopBar, ActivityBar, LeftPanel, ChatPanel, PreviewPanel, SettingsView,
  ToolCard, ModelSelector, Icon : restyle complet

Chat : panneau « Raisonnement » repliable et redimensionnable affichant le
thinking de l'agent en direct (diffuse depuis le backend, persiste dans meta).

Robustesse Ollama : les echecs de generation de parseur d'outils
(« Unable to generate parser for this template ») declenchent desormais le
repli automatique en conversation simple sans outils, au lieu d'un 400.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 4.8 committed 2026-06-30 14:21:05 +02:00
1 parent e8e6a1446c
commit b4fc8cee3d
16 files changed
+488 -419

No files matched your search

+20 -32
View File
@@ -15,7 +15,14 @@ const items: { id: View; icon: React.ReactNode }[] = [
{ id: "tools", icon: <NodesIcon /> },
];
/** Barre d'activité verticale (56px) à gauche. */
const btn = (on: boolean) =>
`flex h-10 w-10 items-center justify-center border-[3px] ${
on
? "border-white bg-accent text-white shadow-accent-soft"
: "border-chrome-3 text-on-dark-2 hover:text-white"
}`;
/** Barre d'activité verticale (60px) sombre à gauche. */
export function ActivityBar({
active,
onChange,
@@ -24,46 +31,27 @@ export function ActivityBar({
onChange: (v: View) => void;
}) {
return (
<div className="flex w-14 flex-none flex-col items-center gap-1 border-r border-line-soft bg-sunken py-3">
{items.map((it) => {
const on = active === it.id;
return (
<button
key={it.id}
onClick={() => onChange(it.id)}
className={`relative flex h-10 w-10 items-center justify-center rounded-[10px] ${
on ? "text-accent" : "text-muted-3 hover:text-ink-3"
}`}
style={on ? { background: "rgba(240,161,92,.14)" } : undefined}
>
{on && (
<span className="absolute left-[-12px] top-[11px] h-[18px] w-[3px] rounded bg-accent" />
)}
{it.icon}
</button>
);
})}
<div className="flex w-[60px] flex-none flex-col items-center gap-2 border-r-[3px] border-line bg-bar py-3">
{items.map((it) => (
<button
key={it.id}
onClick={() => onChange(it.id)}
className={btn(active === it.id)}
>
{it.icon}
</button>
))}
<div className="flex-1" />
<button
onClick={() => onChange("settings")}
className={`relative flex h-10 w-10 items-center justify-center rounded-[10px] ${
active === "settings" ? "text-accent" : "text-muted-3 hover:text-ink-3"
}`}
style={
active === "settings"
? { background: "rgba(240,161,92,.14)" }
: undefined
}
className={btn(active === "settings")}
>
{active === "settings" && (
<span className="absolute left-[-12px] top-[11px] h-[18px] w-[3px] rounded bg-accent" />
)}
<SettingsIcon />
</button>
<div className="mt-1 flex h-[30px] w-[30px] items-center justify-center rounded-full bg-[#3a332b] text-xs font-semibold text-ink-2">
<div className="font-pixel flex h-[34px] w-[34px] items-center justify-center border-[3px] border-white bg-white text-[11px] text-line">
M
</div>
</div>