fix(ui): layouts responsive pour panneau agents et bandeau d'onglets sidebar
AgentsPanel : formulaire de création et items d'agent passent en colonne, les libellés/états longs (running in IdeA, profil) wrappent/tronquent au lieu de déborder. ProjectsView : les onglets de la sidebar wrappent sur plusieurs lignes pour rester tous visibles, le bouton collapse reste épinglé en haut. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -206,9 +206,9 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
|||||||
{/* ── Create form ── */}
|
{/* ── Create form ── */}
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => void handleCreate(e)}
|
onSubmit={(e) => void handleCreate(e)}
|
||||||
className="flex flex-wrap items-end gap-2 border-b border-border p-4"
|
className="flex flex-col gap-3 border-b border-border p-4"
|
||||||
>
|
>
|
||||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
<div className="flex min-w-0 flex-col gap-1">
|
||||||
<label
|
<label
|
||||||
htmlFor="agent-name-input"
|
htmlFor="agent-name-input"
|
||||||
className="text-xs font-medium text-muted"
|
className="text-xs font-medium text-muted"
|
||||||
@ -221,12 +221,12 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
|||||||
placeholder="My agent"
|
placeholder="My agent"
|
||||||
value={newName}
|
value={newName}
|
||||||
onChange={(e) => setNewName(e.target.value)}
|
onChange={(e) => setNewName(e.target.value)}
|
||||||
className="min-w-32"
|
className="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Template selector */}
|
{/* Template selector */}
|
||||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
<div className="flex min-w-0 flex-col gap-1">
|
||||||
<label
|
<label
|
||||||
htmlFor="agent-template-select"
|
htmlFor="agent-template-select"
|
||||||
className="text-xs font-medium text-muted"
|
className="text-xs font-medium text-muted"
|
||||||
@ -256,7 +256,7 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
|||||||
|
|
||||||
{/* Profile selector — hidden when a template is chosen */}
|
{/* Profile selector — hidden when a template is chosen */}
|
||||||
{!hasTemplate && (
|
{!hasTemplate && (
|
||||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
<div className="flex min-w-0 flex-col gap-1">
|
||||||
<label
|
<label
|
||||||
htmlFor="agent-profile-select"
|
htmlFor="agent-profile-select"
|
||||||
className="text-xs font-medium text-muted"
|
className="text-xs font-medium text-muted"
|
||||||
@ -304,6 +304,7 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
|||||||
aria-label="create agent"
|
aria-label="create agent"
|
||||||
disabled={!canCreate}
|
disabled={!canCreate}
|
||||||
loading={vm.busy}
|
loading={vm.busy}
|
||||||
|
className="self-end"
|
||||||
>
|
>
|
||||||
Create
|
Create
|
||||||
</Button>
|
</Button>
|
||||||
@ -330,17 +331,17 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
|||||||
<li
|
<li
|
||||||
key={a.id}
|
key={a.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center justify-between gap-3 py-2 first:pt-0 last:pb-0",
|
"flex flex-col gap-2 py-3 first:pt-0 last:pb-0",
|
||||||
isSelected && "rounded-md bg-raised px-2",
|
isSelected && "rounded-md bg-raised px-2",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => void vm.selectAgent(a.id)}
|
onClick={() => void vm.selectAgent(a.id)}
|
||||||
className="flex min-w-0 flex-1 flex-col items-start gap-0.5 text-left"
|
className="flex min-w-0 flex-col items-start gap-0.5 text-left"
|
||||||
aria-pressed={isSelected}
|
aria-pressed={isSelected}
|
||||||
>
|
>
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex min-w-0 max-w-full flex-wrap items-center gap-2">
|
||||||
<span className="font-medium text-content">{a.name}</span>
|
<span className="font-medium text-content">{a.name}</span>
|
||||||
{agentDrift && (
|
{agentDrift && (
|
||||||
<span
|
<span
|
||||||
@ -366,13 +367,13 @@ export function AgentsPanel({ projectId, projectRoot = "" }: AgentsPanelProps) {
|
|||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-muted">{profileName}</span>
|
<span className="text-xs text-muted">{profileName}</span>
|
||||||
{live && (
|
{live && (
|
||||||
<span className="text-xs text-primary">
|
<span className="block w-full min-w-0 truncate text-xs text-primary">
|
||||||
running in IdeA · {live.sessionId ?? live.nodeId}
|
running in IdeA · {live.sessionId ?? live.nodeId}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 shrink-0">
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
{/* Profile hot-swap selector (Chantier A). Changing the
|
{/* Profile hot-swap selector (Chantier A). Changing the
|
||||||
engine abandons the conversation history → confirmation. */}
|
engine abandons the conversation history → confirmation. */}
|
||||||
{vm.profiles.length > 0 && (
|
{vm.profiles.length > 0 && (
|
||||||
|
|||||||
@ -147,30 +147,35 @@ export function ProjectsView() {
|
|||||||
sidebarCollapsed && "hidden",
|
sidebarCollapsed && "hidden",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Sidebar tab strip (no role="tablist" to avoid collision with project tabs) */}
|
{/* Sidebar tab strip (no role="tablist" to avoid collision with project tabs).
|
||||||
<div className="flex shrink-0 items-stretch border-b border-border">
|
The tabs wrap onto multiple rows when they exceed the sidebar width
|
||||||
{SIDEBAR_TABS.map((t) => (
|
so every label stays visible without scrolling; the collapse button
|
||||||
<button
|
stays pinned to the top-right. */}
|
||||||
key={t.id}
|
<div className="flex shrink-0 items-start border-b border-border">
|
||||||
type="button"
|
<div className="flex min-w-0 flex-1 flex-wrap items-stretch">
|
||||||
aria-selected={sidebarTab === t.id}
|
{SIDEBAR_TABS.map((t) => (
|
||||||
onClick={() => setSidebarTab(t.id)}
|
<button
|
||||||
className={cn(
|
key={t.id}
|
||||||
"flex-1 px-2 py-2 text-xs font-medium transition-colors",
|
type="button"
|
||||||
sidebarTab === t.id
|
aria-selected={sidebarTab === t.id}
|
||||||
? "border-b-2 border-primary text-content"
|
onClick={() => setSidebarTab(t.id)}
|
||||||
: "text-muted hover:text-content",
|
className={cn(
|
||||||
)}
|
"shrink-0 whitespace-nowrap px-3 py-2 text-xs font-medium transition-colors",
|
||||||
>
|
sidebarTab === t.id
|
||||||
{t.label}
|
? "border-b-2 border-primary text-content"
|
||||||
</button>
|
: "text-muted hover:text-content",
|
||||||
))}
|
)}
|
||||||
|
>
|
||||||
|
{t.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="collapse sidebar"
|
aria-label="collapse sidebar"
|
||||||
title="Collapse sidebar"
|
title="Collapse sidebar"
|
||||||
onClick={() => setSidebarCollapsed(true)}
|
onClick={() => setSidebarCollapsed(true)}
|
||||||
className="shrink-0 px-2 text-muted hover:text-content"
|
className="shrink-0 self-stretch border-l border-border px-2 text-muted hover:text-content"
|
||||||
>
|
>
|
||||||
«
|
«
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user