diff --git a/frontend/src/components/editor/EditorToolbar.css b/frontend/src/components/editor/EditorToolbar.css index 9f8dd7fa..b9f0c479 100644 --- a/frontend/src/components/editor/EditorToolbar.css +++ b/frontend/src/components/editor/EditorToolbar.css @@ -37,8 +37,8 @@ gap: 4px; } -/* Center slot — fills the gap between left/right groups, allows file tabs - to scroll horizontally inside it without pushing the icons off-screen. */ +/* Center slot — a flexible spacer between the left and right action groups + that keeps the right icons pinned to the far right. Normally empty. */ .toolbar-center-slot { flex: 1 1 auto; min-width: 0; @@ -46,25 +46,6 @@ align-items: stretch; overflow: hidden; } -.toolbar-center-slot > .file-tabs { - flex: 1; - min-width: 0; - border-bottom: none; - background: transparent; - min-height: 0; - height: 100%; -} -.toolbar-center-slot .file-tab { - height: 100%; - padding: 0 8px; - min-width: 70px; - max-width: 160px; - font-size: 11.5px; -} -.toolbar-center-slot .file-tab-active { - background: #1e1e1e; - border-top: 2px solid var(--color-action-primary); -} /* ── Divider ─────────────────────────────────────── */ .tb-divider { diff --git a/frontend/src/components/editor/EditorToolbar.tsx b/frontend/src/components/editor/EditorToolbar.tsx index d9a2a623..3af4affe 100644 --- a/frontend/src/components/editor/EditorToolbar.tsx +++ b/frontend/src/components/editor/EditorToolbar.tsx @@ -98,9 +98,9 @@ interface EditorToolbarProps { setCompileLogs: (logs: CompilationLog[] | ((prev: CompilationLog[]) => CompilationLog[])) => void; /** * Optional element rendered between the left action group and the right - * action group. The editor passes here so the tabs share the - * same row as the toolbar — keeping every action icon pinned and visible - * regardless of how narrow the editor pane gets. + * action group. Normally empty (the slot just acts as a flexible spacer + * that keeps the right action icons pinned); private overlays may inject + * deployment-specific content here without forking the toolbar. */ centerSlot?: React.ReactNode; /** @@ -1671,8 +1671,10 @@ export const EditorToolbar = ({ )} - {/* Center slot — file tabs share the row so action icons stay pinned. */} - {centerSlot &&
{centerSlot}
} + {/* Center slot — a flexible spacer that keeps the right action group + pinned to the far right. Rendered unconditionally so the layout + holds even when no overlay supplies content here. */} +
{centerSlot}
{/* Hidden file input for project import. Accepts both .vlx diff --git a/frontend/src/components/editor/FileTabs.css b/frontend/src/components/editor/FileTabs.css deleted file mode 100644 index 2103108b..00000000 --- a/frontend/src/components/editor/FileTabs.css +++ /dev/null @@ -1,161 +0,0 @@ -.file-tabs { - display: flex; - align-items: flex-end; - background: #1e1e1e; - border-bottom: 1px solid #333; - overflow-x: auto; - flex-shrink: 0; - min-height: 35px; - scrollbar-width: thin; - scrollbar-color: #3c3c3c transparent; -} - -/* Owner badge — names the board/chip whose files are shown, so the user knows - whose code these tabs belong to. */ -.file-tabs-owner { - display: flex; - align-items: center; - padding: 0 10px; - font-size: 10px; - font-weight: 700; - letter-spacing: 0.4px; - text-transform: uppercase; - color: #9aa0a6; - background: #181818; - border-right: 1px solid #333; - white-space: nowrap; - flex-shrink: 0; -} - -.file-tab { - display: flex; - align-items: center; - gap: 5px; - padding: 0 10px; - height: 35px; - min-width: 90px; - max-width: 180px; - cursor: pointer; - background: #2d2d2d; - border-right: 1px solid #2a2a2a; - color: #9d9d9d; - font-size: 12px; - font-family: 'Segoe UI', sans-serif; - user-select: none; - flex-shrink: 0; - white-space: nowrap; - overflow: hidden; - transition: - background 0.1s, - color 0.1s; -} - -.file-tab:hover { - background: #2a2d2e; - color: #ccc; -} - -.file-tab-active { - background: #1e1e1e; - color: #fff; - border-top: 2px solid var(--color-action-primary); -} - -.file-tab-modified { - width: 7px; - height: 7px; - border-radius: 50%; - background: #e8a87c; - flex-shrink: 0; -} - -.file-tab-name { - overflow: hidden; - text-overflow: ellipsis; - flex: 1; -} - -.file-tab-close { - background: none; - border: none; - color: transparent; - font-size: 16px; - line-height: 1; - cursor: pointer; - padding: 0; - border-radius: 3px; - flex-shrink: 0; - width: 18px; - height: 18px; - display: flex; - align-items: center; - justify-content: center; - transition: - background 0.1s, - color 0.1s; -} - -.file-tab:hover .file-tab-close, -.file-tab-active .file-tab-close { - color: #666; -} - -.file-tab-close:hover { - background: rgba(255, 255, 255, 0.12) !important; - color: #fff !important; -} - -/* Confirm dialog */ -.ftabs-overlay { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; -} - -.ftabs-confirm-box { - background: #252526; - border: 1px solid #3c3c3c; - border-radius: 6px; - padding: 20px 24px; - color: #ccc; - font-size: 14px; - min-width: 290px; -} - -.ftabs-confirm-box p { - margin: 0 0 16px; -} - -.ftabs-confirm-actions { - display: flex; - gap: 8px; - justify-content: flex-end; -} - -.ftabs-confirm-actions button { - padding: 6px 14px; - border-radius: 4px; - border: 1px solid #3c3c3c; - cursor: pointer; - font-size: 13px; - background: #2a2d2e; - color: #ccc; -} - -.ftabs-confirm-actions button:hover { - background: #333; -} - -.ftabs-btn-close { - background: #c62828 !important; - border-color: #c62828 !important; - color: #fff !important; -} - -.ftabs-btn-close:hover { - background: #d32f2f !important; -} diff --git a/frontend/src/components/editor/FileTabs.tsx b/frontend/src/components/editor/FileTabs.tsx deleted file mode 100644 index 6040b250..00000000 --- a/frontend/src/components/editor/FileTabs.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useEditorStore, CHIP_GROUP_PREFIX } from '../../store/useEditorStore'; -import { useSimulatorStore } from '../../store/useSimulatorStore'; -import { boardDisplayName } from '../../types/board'; -import './FileTabs.css'; - -export const FileTabs: React.FC = () => { - const { t } = useTranslation(); - const { files, openFileIds, activeFileId, activeGroupId, setActiveFile, closeFile } = - useEditorStore(); - const [confirmCloseId, setConfirmCloseId] = useState(null); - - const openFiles = openFileIds - .map((id) => files.find((f) => f.id === id)) - .filter(Boolean) as typeof files; - - // Which target owns the files currently shown — a board or a custom chip — - // so the user can tell whose code they're editing at a glance. Resolved as a - // SELECTOR returning just the label string, so FileTabs only re-renders when - // that label changes — not on every pin toggle that mutates the components - // array during simulation. - const ownerLabel = useSimulatorStore((s): string | null => { - if (activeGroupId?.startsWith(CHIP_GROUP_PREFIX)) { - const chipId = activeGroupId.slice(CHIP_GROUP_PREFIX.length); - const chip = s.components.find((c) => c.id === chipId); - return ( - String((chip?.properties as Record)?.chipName ?? '').trim() || - 'Custom Chip' - ); - } - const board = s.boards.find((b) => b.activeFileGroupId === activeGroupId); - return board ? boardDisplayName(board) : null; - }); - - const handleCloseClick = (e: React.MouseEvent, fileId: string, modified: boolean) => { - e.stopPropagation(); - if (modified) { - setConfirmCloseId(fileId); - } else { - closeFile(fileId); - } - }; - - const confirmClose = () => { - if (confirmCloseId) closeFile(confirmCloseId); - setConfirmCloseId(null); - }; - - return ( - <> -
- {ownerLabel && ( - - {ownerLabel} - - )} - {openFiles.map((file) => ( -
setActiveFile(file.id)} - title={file.name} - > - {file.modified && ( - - )} - {file.name} - -
- ))} -
- - {confirmCloseId && ( -
setConfirmCloseId(null)}> -
e.stopPropagation()}> -

{t('editor.fileTabs.confirmClose')}

-
- - -
-
-
- )} - - ); -}; diff --git a/frontend/src/pages/EditorPage.tsx b/frontend/src/pages/EditorPage.tsx index df65f8a7..13b3bffe 100644 --- a/frontend/src/pages/EditorPage.tsx +++ b/frontend/src/pages/EditorPage.tsx @@ -8,7 +8,6 @@ import { startSimulation } from '../simulation/spice/start'; import { useSEO } from '../utils/useSEO'; import { CodeEditor } from '../components/editor/CodeEditor'; import { EditorToolbar } from '../components/editor/EditorToolbar'; -import { FileTabs } from '../components/editor/FileTabs'; import { FileExplorer } from '../components/editor/FileExplorer'; // Lazy-load Pi workspace so xterm.js isn't in the main bundle @@ -491,7 +490,6 @@ export const EditorPage: React.FC = () => { setConsoleOpen={setConsoleOpen} compileLogs={compileLogs} setCompileLogs={setCompileLogs} - centerSlot={!isLinuxPi ? : null} />
@@ -572,7 +570,6 @@ export const EditorPage: React.FC = () => { setConsoleOpen={setConsoleOpen} compileLogs={compileLogs} setCompileLogs={setCompileLogs} - centerSlot={!isLinuxPi ? : null} />