feat: Improve scrolling and fullscreen editor layout with custom scrollbar styles and simplified CodeMirror wrapper structure.

This commit is contained in:
Bruno Charest 2026-03-14 11:53:49 -04:00
parent 3b82d69b22
commit 2a14e4cea2
2 changed files with 157 additions and 82 deletions

View File

@ -225,3 +225,84 @@ body {
color: var(--color-fox-500);
background: rgba(255, 109, 0, 0.1);
}
/* ─── Custom Scrollbar ───────────────────────────────────────────────────── */
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: var(--color-surface-500) transparent;
}
.custom-scrollbar::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: var(--color-surface-500);
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: var(--color-fox-600);
}
/* ─── CodeMirror Editor Fixes ────────────────────────────────────────────── */
.cm-editor {
outline: none !important;
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace !important;
}
.cm-scroller {
overflow: auto !important;
scrollbar-width: thin;
scrollbar-color: var(--color-surface-500) transparent;
}
.cm-scroller::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.cm-scroller::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.2);
}
.cm-scroller::-webkit-scrollbar-thumb {
background: var(--color-surface-500);
border-radius: 4px;
}
.cm-scroller::-webkit-scrollbar-thumb:hover {
background: var(--color-fox-600);
}
.cm-content {
padding: 12px 0 !important;
}
.cm-line {
padding: 0 12px !important;
}
/* ─── Fullscreen Overlay ─────────────────────────────────────────────────── */
.fullscreen-overlay {
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 99999 !important;
margin: 0 !important;
padding: 0 !important;
border-radius: 0 !important;
background: var(--color-surface-900) !important;
}

View File

@ -397,36 +397,38 @@ function AgentMemoryViewer({ agentName }: { agentName: string }) {
</div>
</div>
<div className="relative pl-6 before:absolute before:inset-0 before:left-[11px] before:w-0.5 before:bg-gradient-to-b before:from-blue-500/50 before:to-transparent pt-2">
{memory.timeline.length === 0 ? (
<div className="text-gray-500 text-sm py-4">La mémoire existe mais elle est actuellement vide.</div>
) : (
<div className="space-y-6">
{memory.timeline.map((item: Record<string, any>, idx: number) => (
<div key={idx} className="relative group">
{/* Node dot */}
<div className="absolute -left-[31px] top-1.5 w-4 h-4 rounded-full bg-surface-900 border-2 border-blue-500/50 group-hover:bg-blue-500 group-hover:shadow-[0_0_10px_rgba(59,130,246,0.6)] transition-all z-10"></div>
<div className="max-h-[600px] overflow-y-auto custom-scrollbar pr-2">
<div className="relative pl-6 before:absolute before:inset-0 before:left-[11px] before:w-0.5 before:bg-gradient-to-b before:from-blue-500/50 before:to-transparent pt-2">
{memory.timeline.length === 0 ? (
<div className="text-gray-500 text-sm py-4">La mémoire existe mais elle est actuellement vide.</div>
) : (
<div className="space-y-6 pb-4">
{memory.timeline.map((item: Record<string, any>, idx: number) => (
<div key={idx} className="relative group">
{/* Node dot */}
<div className="absolute -left-[31px] top-1.5 w-4 h-4 rounded-full bg-surface-900 border-2 border-blue-500/50 group-hover:bg-blue-500 group-hover:shadow-[0_0_10px_rgba(59,130,246,0.6)] transition-all z-10"></div>
{/* Content Card */}
<div className="glass-card p-4 border border-surface-700/50 hover:border-blue-500/30 transition-colors">
<div className="flex items-start justify-between mb-2">
<span className="text-[10px] font-mono text-gray-500 bg-surface-800 px-2 py-0.5 rounded">
{item.timestamp || item.created_at || 'Inconnu'}
</span>
{(item.type || item.event_type || item.role) && (
<span className="text-[10px] uppercase font-bold text-indigo-300 bg-indigo-500/10 px-2 py-0.5 rounded">
{item.type || item.event_type || item.role}
{/* Content Card */}
<div className="glass-card p-4 border border-surface-700/50 hover:border-blue-500/30 transition-colors">
<div className="flex items-start justify-between mb-2 gap-2">
<span className="text-[10px] font-mono text-gray-500 bg-surface-800 px-2 py-0.5 rounded">
{item.timestamp || item.created_at || 'Inconnu'}
</span>
)}
{(item.type || item.event_type || item.role) && (
<span className="text-[10px] uppercase font-bold text-indigo-300 bg-indigo-500/10 px-2 py-0.5 rounded">
{item.type || item.event_type || item.role}
</span>
)}
</div>
<pre className="text-sm text-gray-300 whitespace-pre-wrap font-sans leading-relaxed">
{item.content || item.message || JSON.stringify(item, null, 2)}
</pre>
</div>
<pre className="text-sm text-gray-300 whitespace-pre-wrap font-sans leading-relaxed">
{item.content || item.message || JSON.stringify(item, null, 2)}
</pre>
</div>
</div>
))}
</div>
)}
))}
</div>
)}
</div>
</div>
</div>
);
@ -626,9 +628,9 @@ function AgentsTab() {
{/* Identity File Editor */}
{activeFile?.agent === agent.name && (
<div className={`border border-glass-border bg-[#282c34] overflow-hidden shadow-inner mt-4 animate-fade-in flex flex-col ${
isFullscreen ? 'fixed inset-0 w-screen h-screen z-[9999] m-0 p-0 rounded-none' : 'h-[500px] rounded-xl relative'
isFullscreen ? 'fullscreen-overlay' : 'h-[500px] rounded-xl relative'
}`}>
<div className={`flex items-center justify-between px-3 py-2 bg-surface-900/80 border-b border-glass-border shrink-0 ${isFullscreen ? 'h-14 px-6' : ''}`}>
<div className={`flex items-center justify-between bg-surface-900/80 border-b border-glass-border shrink-0 ${isFullscreen ? 'h-16 px-6 py-4' : 'px-3 py-2'}`}>
<span className="text-xs font-mono text-purple-300 truncate pr-4">workspace/{agent.name}/{activeFile.file}</span>
<div className="flex gap-2 shrink-0">
<button onClick={() => setIsFullscreen(!isFullscreen)} className="px-2 py-1 rounded text-[10px] text-gray-400 hover:bg-surface-700 hover:text-white transition-colors">
@ -645,17 +647,15 @@ function AgentsTab() {
{fileLoading ? (
<div className="flex-1 flex items-center justify-center text-gray-500 text-sm animate-pulse">Chargement</div>
) : (
<div className="flex-1 overflow-hidden relative min-h-0 bg-[#282c34]">
<div className="absolute inset-0 custom-scrollbar [&_.cm-editor]:h-full [&_.cm-editor]:bg-transparent [&_.cm-scroller]:h-full [&_.cm-scroller]:overflow-auto [&_.cm-scroller]:font-mono [&_.cm-scroller]:text-xs pb-10">
<CodeMirror
value={fileContent}
height="100%"
theme={oneDark}
extensions={[markdown()]}
onChange={(val) => setFileContent(val)}
basicSetup={{ lineNumbers: true, foldGutter: false, highlightActiveLine: true, tabSize: 2 }}
/>
</div>
<div className="flex-1 overflow-auto bg-[#282c34] min-h-0">
<CodeMirror
value={fileContent}
height="100%"
theme={oneDark}
extensions={[markdown()]}
onChange={(val) => setFileContent(val)}
basicSetup={{ lineNumbers: true, foldGutter: false, highlightActiveLine: true, tabSize: 2 }}
/>
</div>
)}
</div>
@ -1154,7 +1154,7 @@ function ConfigFileEditor({ onClose, onSave }: { onClose: () => void, onSave: ()
};
return (
<div className="fixed inset-0 w-screen h-screen z-[9999] m-0 p-0 rounded-none glass-card flex flex-col overflow-hidden border border-glass-border shadow-[0_40px_80px_rgb(0,0,0,0.9)] bg-surface-900/95 backdrop-blur-xl animate-fade-in">
<div className="fullscreen-overlay glass-card flex flex-col overflow-hidden border border-glass-border shadow-[0_40px_80px_rgb(0,0,0,0.9)] backdrop-blur-xl animate-fade-in">
<div className="flex items-center justify-between px-6 py-4 bg-surface-800 border-b border-glass-border shrink-0 h-16">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-amber-500/20 to-orange-600/10 border border-amber-500/20 flex items-center justify-center text-xl">
@ -1186,28 +1186,26 @@ function ConfigFileEditor({ onClose, onSave }: { onClose: () => void, onSave: ()
</div>
</div>
<div className="flex-1 overflow-hidden relative bg-[#282c34]">
<div className="flex-1 overflow-auto bg-[#282c34] min-h-0">
{loading ? (
<div className="absolute inset-0 flex items-center justify-center flex-col gap-4">
<div className="flex items-center justify-center flex-col gap-4 h-full">
<span className="text-4xl animate-spin-slow opacity-50"></span>
<span className="text-gray-400 font-mono">Lecture de la configuration brute...</span>
</div>
) : (
<div className="h-full w-full absolute inset-0 [&_.cm-editor]:h-full [&_.cm-scroller]:h-full [&_.cm-scroller]:overflow-auto [&_.cm-scroller]:font-mono [&_.cm-scroller]:text-[13px] custom-scrollbar pb-10">
<CodeMirror
value={content}
height="100%"
theme={oneDark}
extensions={[json()]}
onChange={(val) => setContent(val)}
basicSetup={{
lineNumbers: true,
foldGutter: true,
highlightActiveLine: true,
tabSize: 2,
}}
/>
</div>
<CodeMirror
value={content}
height="100%"
theme={oneDark}
extensions={[json()]}
onChange={(val) => setContent(val)}
basicSetup={{
lineNumbers: true,
foldGutter: true,
highlightActiveLine: true,
tabSize: 2,
}}
/>
)}
</div>
</div>
@ -1307,7 +1305,7 @@ function FilesystemTab() {
{/* Editor Panel */}
<div className={isFullscreen
? "fixed inset-0 w-screen h-screen z-[9999] m-0 p-0 rounded-none glass-card flex flex-col overflow-hidden border border-glass-border bg-surface-900 shadow-[0_30px_60px_rgb(0,0,0,0.9)] min-h-0"
? "fullscreen-overlay glass-card flex flex-col overflow-hidden border border-glass-border shadow-[0_30px_60px_rgb(0,0,0,0.9)] min-h-0"
: "glass-card w-2/3 flex flex-col overflow-hidden border border-glass-border shadow-[0_8px_30px_rgb(0,0,0,0.5)] min-h-0"
}>
{fileLoading ? (
@ -1368,37 +1366,33 @@ function FilesystemTab() {
</div>
{/* Editor Body */}
<div className="flex-1 overflow-hidden relative bg-[#282c34]">
<div className="flex-1 overflow-auto bg-[#282c34] min-h-0">
{selectedFile.binary ? (
<div className="absolute inset-0 flex items-center justify-center text-gray-500 bg-surface-900/60">
<div className="flex items-center justify-center text-gray-500 bg-surface-900/60 h-full">
<div className="text-center">
<div className="text-5xl mb-3 opacity-30">📦</div>
<p className="tracking-wide">Fichier binaire. Aperçu non disponible.</p>
</div>
</div>
) : editMode ? (
<div className="h-full w-full absolute inset-0 [&_.cm-editor]:h-full [&_.cm-scroller]:h-full [&_.cm-scroller]:overflow-auto [&_.cm-scroller]:font-mono [&_.cm-scroller]:text-[13px] pb-10">
<CodeMirror
value={editContent}
height="100%"
theme={oneDark}
extensions={getExtensions()}
onChange={(val) => setEditContent(val)}
basicSetup={{
lineNumbers: true,
foldGutter: true,
highlightActiveLine: true,
tabSize: 2,
}}
/>
</div>
<CodeMirror
value={editContent}
height="100%"
theme={oneDark}
extensions={getExtensions()}
onChange={(val) => setEditContent(val)}
basicSetup={{
lineNumbers: true,
foldGutter: true,
highlightActiveLine: true,
tabSize: 2,
}}
/>
) : (
<div className="h-full overflow-y-auto w-full custom-scrollbar absolute inset-0">
<div className="p-4 min-h-full">
<pre className="text-[13px] text-[#abb2bf] font-mono whitespace-pre-wrap leading-relaxed">
{selectedFile.pretty || selectedFile.content}
</pre>
</div>
<div className="p-4">
<pre className="text-[13px] text-[#abb2bf] font-mono whitespace-pre-wrap leading-relaxed">
{selectedFile.pretty || selectedFile.content}
</pre>
</div>
)}
</div>