From 72e408a3aac6827edcd0bfd6a0a3f53b11e3566b Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Sat, 14 Mar 2026 12:20:23 -0400 Subject: [PATCH] feat: Refactor fullscreen editor to use React portals with maximum z-index and improved layout constraints. --- frontend/src/index.css | 36 +++- frontend/src/pages/OpenClaw.tsx | 289 ++++++++++++++++++++++++-------- 2 files changed, 256 insertions(+), 69 deletions(-) diff --git a/frontend/src/index.css b/frontend/src/index.css index b032ef8..0b2ddd5 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -300,9 +300,43 @@ body { bottom: 0 !important; width: 100vw !important; height: 100vh !important; - z-index: 99999 !important; + min-width: 100vw !important; + min-height: 100vh !important; + max-width: 100vw !important; + max-height: 100vh !important; + z-index: 2147483647 !important; /* Maximum z-index value */ margin: 0 !important; padding: 0 !important; border-radius: 0 !important; + border: none !important; background: var(--color-surface-900) !important; + transform: none !important; + box-sizing: border-box !important; + overflow: hidden !important; +} + +/* Portal-based fullscreen editor - renders directly to body */ +.fullscreen-editor-portal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100vw; + height: 100vh; + z-index: 2147483647; + background: var(--color-surface-900); +} + +/* Ensure fullscreen content fills the space */ +.fullscreen-overlay > *, +.fullscreen-editor-portal > * { + max-width: 100% !important; + width: 100% !important; + height: 100% !important; +} + +.fullscreen-overlay .cm-editor, +.fullscreen-editor-portal .cm-editor { + height: 100% !important; } diff --git a/frontend/src/pages/OpenClaw.tsx b/frontend/src/pages/OpenClaw.tsx index 2536ce1..79dd782 100644 --- a/frontend/src/pages/OpenClaw.tsx +++ b/frontend/src/pages/OpenClaw.tsx @@ -1,4 +1,5 @@ import { useEffect, useState, useCallback, useRef } from 'react'; +import { createPortal } from 'react-dom'; import CodeMirror from '@uiw/react-codemirror'; import { json } from '@codemirror/lang-json'; import { markdown } from '@codemirror/lang-markdown'; @@ -10,6 +11,38 @@ import type { } from '../api/client'; import { api } from '../api/client'; +// ═════════════════════════════════════════════════════════════════════════════════ +// Fullscreen Editor Component using Portal for true fullscreen +// ═════════════════════════════════════════════════════════════════════════════════ + +interface FullscreenEditorProps { + isOpen: boolean; + onClose: () => void; + children: React.ReactNode; +} + +function FullscreenEditor({ isOpen, onClose, children }: FullscreenEditorProps) { + useEffect(() => { + if (isOpen) { + document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = ''; + } + return () => { + document.body.style.overflow = ''; + }; + }, [isOpen]); + + if (!isOpen) return null; + + return createPortal( +
+ {children} +
, + document.body + ); +} + // ═════════════════════════════════════════════════════════════════════════════════ // Tab definitions // ═════════════════════════════════════════════════════════════════════════════════ @@ -625,16 +658,14 @@ function AgentsTab() { })} - {/* Identity File Editor */} - {activeFile?.agent === agent.name && ( -
-
+ {/* Identity File Editor - Inline (not fullscreen) */} + {activeFile?.agent === agent.name && !isFullscreen && ( +
+
workspace/{agent.name}/{activeFile.file}
-
)} + + {/* Identity File Editor - Fullscreen via Portal */} + {activeFile?.agent === agent.name && isFullscreen && createPortal( +
+
+
+ workspace/{agent.name}/{activeFile.file} +
+ + + +
+
+ {fileLoading ? ( +
Chargement…
+ ) : ( +
+ setFileContent(val)} + basicSetup={{ lineNumbers: true, foldGutter: false, highlightActiveLine: true, tabSize: 2 }} + /> +
+ )} +
+
, + document.body + )}
)} @@ -1153,62 +1221,65 @@ function ConfigFileEditor({ onClose, onSave }: { onClose: () => void, onSave: () } }; - return ( -
-
-
-
- ✏️ + return createPortal( +
+
+
+
+
+ ✏️ +
+
+

+ Édition directe +

+
openclaw.json
+
-
-

- Édition directe -

-
openclaw.json
+ +
+ +
- -
- - -
-
-
- {loading ? ( -
- ⚙️ - Lecture de la configuration brute... -
- ) : ( - setContent(val)} - basicSetup={{ - lineNumbers: true, - foldGutter: true, - highlightActiveLine: true, - tabSize: 2, - }} - /> - )} +
+ {loading ? ( +
+ ⚙️ + Lecture de la configuration brute... +
+ ) : ( + setContent(val)} + basicSetup={{ + lineNumbers: true, + foldGutter: true, + highlightActiveLine: true, + tabSize: 2, + }} + /> + )} +
-
+
, + document.body ); } @@ -1278,6 +1349,89 @@ function FilesystemTab() { return []; }; + // Fullscreen editor via portal + if (isFullscreen && selectedFile) { + return createPortal( +
+
+
+
+

+ 📄 {selectedFile.path.split('/').pop()} +

+
+ {selectedFile.path} + + {formatSize(selectedFile.size)} + + {selectedFile.language} +
+
+
+ + {!selectedFile.binary && ( + <> + {editMode ? ( + <> + + + + ) : ( + + )} + + )} +
+
+ +
+ {selectedFile.binary ? ( +
+
+
📦
+

Fichier binaire. Aperçu non disponible.

+
+
+ ) : editMode ? ( + setEditContent(val)} + basicSetup={{ + lineNumbers: true, + foldGutter: true, + highlightActiveLine: true, + tabSize: 2, + }} + /> + ) : ( +
+
+                  {selectedFile.pretty || selectedFile.content}
+                
+
+ )} +
+
+
, + document.body + ); + } + return (
{/* Sidebar Tree */} @@ -1303,11 +1457,9 @@ function FilesystemTab() {
- {/* Editor Panel */} -
+ {/* Editor Panel - hidden when in fullscreen */} + {!isFullscreen && ( +
{fileLoading ? (
@@ -1323,7 +1475,7 @@ function FilesystemTab() { ) : (
{/* Editor Header */} -
+

📄 {selectedFile.path.split('/').pop()} @@ -1338,11 +1490,11 @@ function FilesystemTab() {

{!selectedFile.binary && ( <> @@ -1399,6 +1551,7 @@ function FilesystemTab() {
)}
+ )}
); }