diff --git a/frontend/src/components/editor/EditorMenuBar.tsx b/frontend/src/components/editor/EditorMenuBar.tsx index 5f9c9d3e..59841a0b 100644 --- a/frontend/src/components/editor/EditorMenuBar.tsx +++ b/frontend/src/components/editor/EditorMenuBar.tsx @@ -20,7 +20,11 @@ */ import React, { useEffect, useRef, useState, useSyncExternalStore } from 'react'; import { useTranslation } from 'react-i18next'; +import { useLocation, useNavigate } from 'react-router-dom'; import { useSimulatorStore } from '../../store/useSimulatorStore'; +import { useOscilloscopeStore } from '../../store/useOscilloscopeStore'; +import { LOCALES, LOCALE_META, type Locale } from '../../i18n/config'; +import { getLocaleFromPath, switchLocale } from '../../i18n/path'; import { hasEditorCommand, runEditorCommand, @@ -48,12 +52,19 @@ const SITE = import.meta.env.VITE_PRO_BUILD ? '' : 'https://velxio.dev'; export const EditorMenuBar: React.FC = () => { const { t } = useTranslation(); - const [open, setOpen] = useState<'file' | 'edit' | 'help' | null>(null); + const [open, setOpen] = useState<'file' | 'edit' | 'view' | 'lang' | 'help' | null>(null); const rootRef = useRef(null); // Re-render when owners (un)register their commands. useSyncExternalStore(subscribeEditorCommands, getEditorCommandsVersion); + const location = useLocation(); + const navigate = useNavigate(); + const currentLocale = getLocaleFromPath(location.pathname); + const serialOpen = useSimulatorStore((s) => s.serialMonitorOpen); + const toggleSerialMonitor = useSimulatorStore((s) => s.toggleSerialMonitor); + const scopeOpen = useOscilloscopeStore((s) => s.open); + const toggleOscilloscope = useOscilloscopeStore((s) => s.toggleOscilloscope); const undo = useSimulatorStore((s) => s.undo); const redo = useSimulatorStore((s) => s.redo); const history = useSimulatorStore((s) => s.history); @@ -118,8 +129,19 @@ export const EditorMenuBar: React.FC = () => { { kind: 'link', href: GITHUB_URL, label: t('editor.menu.github', 'GitHub Repository') }, ]; - const editItems: Item[] = [ - { kind: 'separator' }, // placeholder: undo/redo render specially above + // Edit is undo/redo only (they render specially, with live history state); + // everything view-shaped lives in the View menu, like the desktop app. + const editItems: Item[] = []; + + const viewItems: Item[] = [ + { kind: 'command', id: 'sim.compile', label: t('editor.toolbar.compile', 'Compile'), shortcut: 'Ctrl+B' }, + { kind: 'command', id: 'sim.run', label: t('editor.toolbar.run', 'Run') }, + { kind: 'command', id: 'sim.stop', label: t('editor.toolbar.stop', 'Stop') }, + { kind: 'command', id: 'sim.resetBoard', label: t('editor.toolbar.reset', 'Reset') }, + { kind: 'separator' }, + { kind: 'command', id: 'view.toggleExplorer', label: t('editor.menu.toggleExplorer', 'File Explorer') }, + { kind: 'command', id: 'view.toggleConsole', label: t('editor.menu.toggleConsole', 'Output Console') }, + { kind: 'separator' }, { kind: 'command', id: 'view.reset', label: t('editor.menu.centerView', 'Center canvas view') }, { kind: 'command', id: 'view.zoomIn', label: t('editor.canvas.zoomIn', 'Zoom in') }, { kind: 'command', id: 'view.zoomOut', label: t('editor.canvas.zoomOut', 'Zoom out') }, @@ -158,7 +180,7 @@ export const EditorMenuBar: React.FC = () => { ); - const menu = (which: 'file' | 'edit' | 'help', label: string, items: Item[]): React.ReactNode => ( + const menu = (which: 'file' | 'edit' | 'view' | 'lang' | 'help', label: string, items: Item[]): React.ReactNode => (
{open === which && (
+ {which === 'view' && ( + <> + + +
+ + )} + {which === 'lang' && ( + <> + {LOCALES.map((loc) => ( + + ))} + + )} {which === 'edit' && ( <>