feat(ui): sélecteur de modèle dans le composer, retiré du TopBar

Le chip modèle du composer était décoratif (pastille orange fixe) alors
que le TopBar montrait le vrai état de chargement. Le sélecteur complet
(liste + pastille GPU/CPU/à charger/préchargement) vit maintenant dans
la carte du chat, menu vers le haut.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 4.8 committed 2026-07-19 11:31:59 +02:00
1 parent bb8e87b612
commit b0018e8313
3 files changed
+23 -14

No files matched your search

+21 -4
View File
@@ -2,8 +2,15 @@ import { useEffect, useRef, useState } from "react";
import { useStore } from "../store/useStore";
import { ChevronDown } from "./Icon";
/** Sélecteur de modèle Ollama (chip orange de la barre supérieure). */
export function ModelSelector() {
/** Sélecteur de modèle Ollama (chip orange, pastille = état de chargement).
variant "composer" : taille alignée sur les chips du composer, menu vers
le haut. */
export function ModelSelector({
variant = "top",
}: {
variant?: "top" | "composer";
}) {
const {
models,
selectedModel,
@@ -31,7 +38,11 @@ export function ModelSelector() {
<div className="relative" ref={ref}>
<button
onClick={() => setOpen((v) => !v)}
className="flex h-[34px] min-w-0 max-w-[260px] items-center gap-2 border-[3px] border-white bg-accent px-3 text-white shadow-accent-soft"
className={
variant === "composer"
? "flex h-8 min-w-0 max-w-[220px] items-center gap-1.5 border-2 border-line bg-accent px-2.5 text-[13px] text-white"
: "flex h-[34px] min-w-0 max-w-[260px] items-center gap-2 border-[3px] border-white bg-accent px-3 text-white shadow-accent-soft"
}
title={selectedModel || undefined}
style={{ borderRadius: 7 }}
>
@@ -62,7 +73,13 @@ export function ModelSelector() {
</button>
{open && (
<div className="absolute right-0 top-11 z-20 w-64 border-[3px] border-line bg-card p-1 shadow-hard">
<div
className={`absolute z-20 w-64 border-[3px] border-line bg-card p-1 shadow-hard ${
variant === "composer"
? "bottom-[calc(100%+6px)] left-0"
: "right-0 top-11"
}`}
>
{models.length === 0 && (
<div className="px-3 py-2 text-xs text-muted-2">
Aucun modèle installé
-3
View File
@@ -2,7 +2,6 @@ import { useEffect, useState } from "react";
import { useStore } from "../store/useStore";
import { getVersion } from "../api/client";
import { LokiMark } from "./Icon";
import { ModelSelector } from "./ModelSelector";
import { SessionMenu } from "./SessionMenu";
/** Barre supérieure sombre : logo, fil d'Ariane, statut Ollama, sélecteur. */
@@ -72,8 +71,6 @@ export function TopBar() {
{connected ? status?.host.replace(/^https?:\/\//, "") : "déconnecté"}
</span>
</div>
<ModelSelector />
</div>
);
}
+2 -7
View File
@@ -4,6 +4,7 @@ import { ChevronDown, LokiMark, SendIcon } from "../components/Icon";
import { ToolCard } from "../components/ToolCard";
import { MessageContent } from "../components/MessageContent";
import { ProjectChip } from "../components/ProjectChip";
import { ModelSelector } from "../components/ModelSelector";
import type { Message, ToolCall } from "../api/client";
/** Panneau central : barre de contexte, fil de conversation, composer. */
@@ -138,13 +139,7 @@ export function ChatPanel() {
<div className="mt-1.5 flex items-center gap-2">
<ModeSelector />
<ProjectChip />
<div
className="flex h-8 min-w-0 max-w-[180px] items-center gap-1.5 border-2 border-line px-2.5 text-[13px] text-ink-2"
title={selectedModel || undefined}
>
<span className="h-2 w-2 border-2 border-line bg-accent" />
<span className="min-w-0 truncate">{selectedModel || "—"}</span>
</div>
<ModelSelector variant="composer" />
{streaming && !showingStreaming ? (
<span className="min-w-0 flex-1 truncate text-[13px] text-accent">
Travail en cours : {workingSession?.title ?? "session ouverte"}