feat: Improve scrolling and fullscreen editor layout with custom scrollbar styles and simplified CodeMirror wrapper structure.
This commit is contained in:
parent
3b82d69b22
commit
2a14e4cea2
@ -225,3 +225,84 @@ body {
|
|||||||
color: var(--color-fox-500);
|
color: var(--color-fox-500);
|
||||||
background: rgba(255, 109, 0, 0.1);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -397,36 +397,38 @@ function AgentMemoryViewer({ agentName }: { agentName: string }) {
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
<div className="max-h-[600px] overflow-y-auto custom-scrollbar pr-2">
|
||||||
{memory.timeline.length === 0 ? (
|
<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">
|
||||||
<div className="text-gray-500 text-sm py-4">La mémoire existe mais elle est actuellement vide.</div>
|
{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 className="space-y-6 pb-4">
|
||||||
<div key={idx} className="relative group">
|
{memory.timeline.map((item: Record<string, any>, idx: number) => (
|
||||||
{/* Node dot */}
|
<div key={idx} className="relative group">
|
||||||
<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>
|
{/* 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 */}
|
{/* Content Card */}
|
||||||
<div className="glass-card p-4 border border-surface-700/50 hover:border-blue-500/30 transition-colors">
|
<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">
|
<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">
|
<span className="text-[10px] font-mono text-gray-500 bg-surface-800 px-2 py-0.5 rounded">
|
||||||
{item.timestamp || item.created_at || 'Inconnu'}
|
{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>
|
</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>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -626,9 +628,9 @@ function AgentsTab() {
|
|||||||
{/* Identity File Editor */}
|
{/* Identity File Editor */}
|
||||||
{activeFile?.agent === agent.name && (
|
{activeFile?.agent === agent.name && (
|
||||||
<div className={`border border-glass-border bg-[#282c34] overflow-hidden shadow-inner mt-4 animate-fade-in flex flex-col ${
|
<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>
|
<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">
|
<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">
|
<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 ? (
|
{fileLoading ? (
|
||||||
<div className="flex-1 flex items-center justify-center text-gray-500 text-sm animate-pulse">Chargement…</div>
|
<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="flex-1 overflow-auto bg-[#282c34] min-h-0">
|
||||||
<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
|
||||||
<CodeMirror
|
value={fileContent}
|
||||||
value={fileContent}
|
height="100%"
|
||||||
height="100%"
|
theme={oneDark}
|
||||||
theme={oneDark}
|
extensions={[markdown()]}
|
||||||
extensions={[markdown()]}
|
onChange={(val) => setFileContent(val)}
|
||||||
onChange={(val) => setFileContent(val)}
|
basicSetup={{ lineNumbers: true, foldGutter: false, highlightActiveLine: true, tabSize: 2 }}
|
||||||
basicSetup={{ lineNumbers: true, foldGutter: false, highlightActiveLine: true, tabSize: 2 }}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -1154,7 +1154,7 @@ function ConfigFileEditor({ onClose, onSave }: { onClose: () => void, onSave: ()
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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 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="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">
|
<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>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-hidden relative bg-[#282c34]">
|
<div className="flex-1 overflow-auto bg-[#282c34] min-h-0">
|
||||||
{loading ? (
|
{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-4xl animate-spin-slow opacity-50">⚙️</span>
|
||||||
<span className="text-gray-400 font-mono">Lecture de la configuration brute...</span>
|
<span className="text-gray-400 font-mono">Lecture de la configuration brute...</span>
|
||||||
</div>
|
</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
|
||||||
<CodeMirror
|
value={content}
|
||||||
value={content}
|
height="100%"
|
||||||
height="100%"
|
theme={oneDark}
|
||||||
theme={oneDark}
|
extensions={[json()]}
|
||||||
extensions={[json()]}
|
onChange={(val) => setContent(val)}
|
||||||
onChange={(val) => setContent(val)}
|
basicSetup={{
|
||||||
basicSetup={{
|
lineNumbers: true,
|
||||||
lineNumbers: true,
|
foldGutter: true,
|
||||||
foldGutter: true,
|
highlightActiveLine: true,
|
||||||
highlightActiveLine: true,
|
tabSize: 2,
|
||||||
tabSize: 2,
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1307,7 +1305,7 @@ function FilesystemTab() {
|
|||||||
|
|
||||||
{/* Editor Panel */}
|
{/* Editor Panel */}
|
||||||
<div className={isFullscreen
|
<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"
|
: "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 ? (
|
{fileLoading ? (
|
||||||
@ -1368,37 +1366,33 @@ function FilesystemTab() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Editor Body */}
|
{/* Editor Body */}
|
||||||
<div className="flex-1 overflow-hidden relative bg-[#282c34]">
|
<div className="flex-1 overflow-auto bg-[#282c34] min-h-0">
|
||||||
{selectedFile.binary ? (
|
{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-center">
|
||||||
<div className="text-5xl mb-3 opacity-30">📦</div>
|
<div className="text-5xl mb-3 opacity-30">📦</div>
|
||||||
<p className="tracking-wide">Fichier binaire. Aperçu non disponible.</p>
|
<p className="tracking-wide">Fichier binaire. Aperçu non disponible.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : editMode ? (
|
) : 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
|
||||||
<CodeMirror
|
value={editContent}
|
||||||
value={editContent}
|
height="100%"
|
||||||
height="100%"
|
theme={oneDark}
|
||||||
theme={oneDark}
|
extensions={getExtensions()}
|
||||||
extensions={getExtensions()}
|
onChange={(val) => setEditContent(val)}
|
||||||
onChange={(val) => setEditContent(val)}
|
basicSetup={{
|
||||||
basicSetup={{
|
lineNumbers: true,
|
||||||
lineNumbers: true,
|
foldGutter: true,
|
||||||
foldGutter: true,
|
highlightActiveLine: true,
|
||||||
highlightActiveLine: true,
|
tabSize: 2,
|
||||||
tabSize: 2,
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="h-full overflow-y-auto w-full custom-scrollbar absolute inset-0">
|
<div className="p-4">
|
||||||
<div className="p-4 min-h-full">
|
<pre className="text-[13px] text-[#abb2bf] font-mono whitespace-pre-wrap leading-relaxed">
|
||||||
<pre className="text-[13px] text-[#abb2bf] font-mono whitespace-pre-wrap leading-relaxed">
|
{selectedFile.pretty || selectedFile.content}
|
||||||
{selectedFile.pretty || selectedFile.content}
|
</pre>
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user