feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
/**
|
|
|
|
|
* EditorMenuBar — File / Edit menus for the editor header.
|
|
|
|
|
*
|
|
|
|
|
* The editor grew a single toolbar row where every action, frequent or
|
|
|
|
|
* rare, competed for the same pixels; on small screens the buttons
|
|
|
|
|
* measurably overlapped. The classic fix is the classic desktop split:
|
|
|
|
|
* things you do every minute stay as buttons (Run, Stop, board, Add),
|
|
|
|
|
* things you do a few times per session move into menus. This is those
|
|
|
|
|
* menus.
|
|
|
|
|
*
|
|
|
|
|
* Actions are invoked through the editorCommands registry — their real
|
|
|
|
|
* owners (EditorPage, FileExplorer, EditorToolbar, SimulatorCanvas)
|
|
|
|
|
* register handlers on mount, so nothing here duplicates logic and an
|
|
|
|
|
* item whose owner is not mounted renders disabled. Undo/redo read the
|
|
|
|
|
* canvas history from the store directly, mirroring the canvas buttons.
|
|
|
|
|
*
|
|
|
|
|
* Menubar behaviour follows the desktop convention: click opens, click
|
|
|
|
|
* again closes, hovering a sibling while open switches menus, Escape and
|
|
|
|
|
* outside clicks close.
|
|
|
|
|
*/
|
|
|
|
|
import React, { useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
|
|
|
import { useTranslation } from 'react-i18next';
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
import { useLocation, useNavigate } from 'react-router-dom';
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
import { useSimulatorStore } from '../../store/useSimulatorStore';
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
import { useOscilloscopeStore } from '../../store/useOscilloscopeStore';
|
|
|
|
|
import { LOCALES, LOCALE_META, type Locale } from '../../i18n/config';
|
|
|
|
|
import { getLocaleFromPath, switchLocale } from '../../i18n/path';
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
import {
|
|
|
|
|
hasEditorCommand,
|
|
|
|
|
runEditorCommand,
|
|
|
|
|
subscribeEditorCommands,
|
|
|
|
|
getEditorCommandsVersion,
|
|
|
|
|
type EditorCommandId,
|
|
|
|
|
} from '../../lib/editorCommands';
|
|
|
|
|
import './EditorMenuBar.css';
|
|
|
|
|
|
|
|
|
|
type Item =
|
2026-08-11 00:47:20 +07:00
|
|
|
| {
|
|
|
|
|
kind: 'command';
|
|
|
|
|
id: EditorCommandId;
|
|
|
|
|
label: string;
|
|
|
|
|
shortcut?: string;
|
|
|
|
|
pro?: boolean;
|
|
|
|
|
/** Hide the row entirely when no handler is registered, instead of
|
|
|
|
|
* the default "render disabled". For account-scoped items the
|
|
|
|
|
* absence of a handler is not "temporarily unavailable" but "does
|
|
|
|
|
* not apply here": OSS has no accounts at all, and in pro exactly
|
|
|
|
|
* one of Sign in / My projects is meaningful at a time. A greyed-out
|
|
|
|
|
* "My projects" would read as a broken feature in both. */
|
|
|
|
|
optional?: boolean;
|
|
|
|
|
}
|
2026-07-30 22:31:31 +07:00
|
|
|
| { kind: 'link'; href: string; label: string }
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
| { kind: 'separator' };
|
|
|
|
|
|
2026-07-30 22:31:31 +07:00
|
|
|
// Same links the desktop app's Help menu opens (pro/desktop menu.rs) — the
|
|
|
|
|
// web editor mirrors that structure so both feel like one product. They
|
|
|
|
|
// replace the marketing nav this header no longer shows, opening in a new
|
|
|
|
|
// tab so the editor (and any unsaved work) stays put.
|
|
|
|
|
const GITHUB_URL = 'https://github.com/davidmonterocrespo24/velxio';
|
|
|
|
|
const DISCORD_URL = 'https://discord.gg/3mARjJrh4E';
|
refactor(routes): OSS is the editor; marketing moves to the overlay
The open-source build now ships exactly its product surface: /editor, the
examples gallery (/examples, /examples/:id) and the per-example editor
(/example/:id). Landing, about, pricing, docs, the 14 keyword-targeted
simulator landings and the v2/v2.5/v3 showcases move to the private
overlay, registered through the same registerProRoutes seam that already
carries login/admin/classroom.
Root behaves per build: an overlay that registers an index route claims
'/' (velxio.dev keeps its landing); otherwise '/' redirects to /editor.
The redirect waits for the overlay import to settle — same contract as
markProExamplesSettled — so a velxio.dev visitor is never bounced into
the editor because the landing was 300ms away from registering.
Prerender and sitemap follow the split: entry-server pulls the marketing
page map from '@pro/pages/marketing' behind a VITE_PRO_BUILD-gated dynamic
import (the proven main.tsx pattern, with an OSS stub for tsc), and
generate-sitemap lists only served routes in OSS builds (2 URLs) while
pro builds stay byte-identical — verified against a pre-migration
baseline: sitemap (37 URLs) and prerendered /, /about, /docs,
/arduino-simulator, /esp32-simulator, /v3 all identical modulo hashed
asset names. OSS prerender drops exactly the 32 marketing pages (348→316).
The OSS header slims down to match: Editor, Examples, GitHub, Discord —
the marketing links only render in pro builds, where their routes exist.
The editor Help menu links those pages absolutely (velxio.dev) in OSS,
exactly like the desktop app's Help menu.
2026-07-30 22:50:14 +07:00
|
|
|
// In the OSS build the marketing pages live on velxio.dev, not in this app
|
|
|
|
|
// (the overlay registers them only in pro builds) — link absolute, exactly
|
|
|
|
|
// like the desktop app's Help menu does.
|
|
|
|
|
const SITE = import.meta.env.VITE_PRO_BUILD ? '' : 'https://velxio.dev';
|
2026-07-30 22:31:31 +07:00
|
|
|
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
export const EditorMenuBar: React.FC = () => {
|
|
|
|
|
const { t } = useTranslation();
|
2026-08-08 09:02:32 +07:00
|
|
|
const [open, setOpen] = useState<'file' | 'edit' | 'view' | 'account' | 'help' | null>(null);
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
// Re-render when owners (un)register their commands.
|
|
|
|
|
useSyncExternalStore(subscribeEditorCommands, getEditorCommandsVersion);
|
|
|
|
|
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
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);
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
const undo = useSimulatorStore((s) => s.undo);
|
|
|
|
|
const redo = useSimulatorStore((s) => s.redo);
|
|
|
|
|
const history = useSimulatorStore((s) => s.history);
|
|
|
|
|
const historyIndex = useSimulatorStore((s) => s.historyIndex);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!open) return;
|
|
|
|
|
const onDown = (e: MouseEvent): void => {
|
|
|
|
|
if (!rootRef.current?.contains(e.target as Node)) setOpen(null);
|
|
|
|
|
};
|
|
|
|
|
const onKey = (e: KeyboardEvent): void => {
|
|
|
|
|
if (e.key === 'Escape') setOpen(null);
|
|
|
|
|
};
|
|
|
|
|
document.addEventListener('mousedown', onDown);
|
|
|
|
|
document.addEventListener('keydown', onKey);
|
|
|
|
|
return () => {
|
|
|
|
|
document.removeEventListener('mousedown', onDown);
|
|
|
|
|
document.removeEventListener('keydown', onKey);
|
|
|
|
|
};
|
|
|
|
|
}, [open]);
|
|
|
|
|
|
|
|
|
|
const fileItems: Item[] = [
|
|
|
|
|
{ kind: 'command', id: 'project.new', label: t('editor.menu.newProject', 'New workspace') },
|
|
|
|
|
{ kind: 'command', id: 'file.new', label: t('editor.menu.newFile', 'New file') },
|
|
|
|
|
{ kind: 'separator' },
|
2026-08-11 00:47:20 +07:00
|
|
|
// Third item, and deliberately at the head of the project group rather
|
|
|
|
|
// than tacked onto the "new …" pair above: it opens the user's saved
|
|
|
|
|
// work, which is what Open/Save below are about.
|
|
|
|
|
{
|
|
|
|
|
kind: 'command',
|
|
|
|
|
id: 'account.myProjects',
|
|
|
|
|
label: t('header.auth.myProjects', 'My projects'),
|
|
|
|
|
optional: true,
|
|
|
|
|
},
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
{ kind: 'command', id: 'project.open', label: t('editor.menu.open', 'Open project…') },
|
|
|
|
|
{
|
|
|
|
|
kind: 'command',
|
|
|
|
|
id: 'project.save',
|
|
|
|
|
label: t('editor.menu.save', 'Save project'),
|
|
|
|
|
shortcut: 'Ctrl+S',
|
|
|
|
|
},
|
|
|
|
|
{ kind: 'separator' },
|
|
|
|
|
{ kind: 'command', id: 'project.import', label: t('editor.toolbar.importLabel', 'Import project') },
|
|
|
|
|
{ kind: 'command', id: 'project.export', label: t('editor.toolbar.exportLabel', 'Export project (.zip)') },
|
2026-07-31 00:18:37 +07:00
|
|
|
{ kind: 'command', id: 'project.exportBom', label: t('editor.toolbar.exportBomLabel', 'Bill of Materials (CSV)'), pro: true },
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
{
|
|
|
|
|
kind: 'command',
|
|
|
|
|
id: 'project.exportScreenshot',
|
|
|
|
|
label: t('editor.toolbar.exportScreenshotLabel', 'Schematic image (PNG)'),
|
2026-07-31 00:18:37 +07:00
|
|
|
pro: true,
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
},
|
2026-07-31 00:18:37 +07:00
|
|
|
{ kind: 'separator' },
|
|
|
|
|
// The toolbar's "..." menu folded in here — same actions, same PRO
|
|
|
|
|
// pills, one button fewer in the strip.
|
|
|
|
|
{ kind: 'command', id: 'project.share', label: t('editor.toolbar.shareLabel', 'Share / Embed') },
|
|
|
|
|
{ kind: 'command', id: 'project.githubSync', label: t('editor.toolbar.githubSyncLabel', 'Sync to GitHub'), pro: true },
|
|
|
|
|
{ kind: 'command', id: 'firmware.upload', label: t('editor.toolbar.uploadFirmwareLabel', 'Upload firmware') },
|
|
|
|
|
{ kind: 'command', id: 'sim.record', label: t('editor.toolbar.recordLabel', 'Record simulation'), pro: true },
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
];
|
|
|
|
|
|
2026-08-11 00:47:20 +07:00
|
|
|
// Sign in / My projects for the Account menu. The bottom-left account
|
|
|
|
|
// dropdown gets these from its own (pro) markup; this menubar only ever
|
|
|
|
|
// hosted the shared `user-menu` slot, which is why the editor's Account
|
|
|
|
|
// menu had no way in or out of a session.
|
|
|
|
|
const accountItems: Item[] = [
|
|
|
|
|
{
|
|
|
|
|
kind: 'command',
|
|
|
|
|
id: 'account.myProjects',
|
|
|
|
|
label: t('header.auth.myProjects', 'My projects'),
|
|
|
|
|
optional: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
kind: 'command',
|
|
|
|
|
id: 'account.login',
|
|
|
|
|
label: t('header.auth.signIn', 'Sign in'),
|
|
|
|
|
optional: true,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2026-07-30 22:31:31 +07:00
|
|
|
const helpItems: Item[] = [
|
feat(news): announce with a toast, open the modal only on request
Entering the editor could stack two overlays: the starter-template
dialog opened on mount, then four seconds later the "What's new" modal
landed on top of it. Two dimmed backdrops over each other, and the
smaller, *less* important surface in front — the z-indexes said it
outright, news 10000 against the starter's 9000.
The delay made it worse rather than gentler. Arriving after the user has
started reading the templates is the most disruptive moment available;
appearing instantly would at least have let them clear it before
engaging.
The rule this restores: a modal is for what BLOCKS, and an announcement
never blocks. News now slides into the corner as a toast that dims
nothing, steals no focus (role="status", polite), and retires by itself.
The full post is one click behind "Read more" — a modal the user asked
for is a categorically different thing from one thrown at them — and
stays reachable from Help ▸ What's new once the toast is gone.
Worth noting the audience argument too: the starter dialog only fires on
a PRISTINE visit, i.e. for someone brand new, and "what's new" is
meaningless without a baseline to compare against. Returning users, the
ones it is actually written for, arrive with a project loaded and never
saw the collision.
Renamed NewsModal → NewsAnnouncer: it is not a modal by default any more,
and leaving the old name would have mislead the next reader.
Strings are new keys under `news.*`, filled in for all nine locales — the
previous modal had "What's new" and "Got it" hardcoded in English.
Toast sits at z-index 8000, deliberately BELOW the starter dialog, so if
the two ever coincide again the blocking task keeps the foreground.
2026-08-11 00:52:55 +07:00
|
|
|
// Only present once a post has been delivered — the announcement is a
|
|
|
|
|
// toast now, and this is how it stays reachable after it retires.
|
|
|
|
|
{
|
|
|
|
|
kind: 'command',
|
|
|
|
|
id: 'help.whatsNew',
|
|
|
|
|
label: t('news.kicker', "What's new"),
|
|
|
|
|
optional: true,
|
|
|
|
|
},
|
refactor(routes): OSS is the editor; marketing moves to the overlay
The open-source build now ships exactly its product surface: /editor, the
examples gallery (/examples, /examples/:id) and the per-example editor
(/example/:id). Landing, about, pricing, docs, the 14 keyword-targeted
simulator landings and the v2/v2.5/v3 showcases move to the private
overlay, registered through the same registerProRoutes seam that already
carries login/admin/classroom.
Root behaves per build: an overlay that registers an index route claims
'/' (velxio.dev keeps its landing); otherwise '/' redirects to /editor.
The redirect waits for the overlay import to settle — same contract as
markProExamplesSettled — so a velxio.dev visitor is never bounced into
the editor because the landing was 300ms away from registering.
Prerender and sitemap follow the split: entry-server pulls the marketing
page map from '@pro/pages/marketing' behind a VITE_PRO_BUILD-gated dynamic
import (the proven main.tsx pattern, with an OSS stub for tsc), and
generate-sitemap lists only served routes in OSS builds (2 URLs) while
pro builds stay byte-identical — verified against a pre-migration
baseline: sitemap (37 URLs) and prerendered /, /about, /docs,
/arduino-simulator, /esp32-simulator, /v3 all identical modulo hashed
asset names. OSS prerender drops exactly the 32 marketing pages (348→316).
The OSS header slims down to match: Editor, Examples, GitHub, Discord —
the marketing links only render in pro builds, where their routes exist.
The editor Help menu links those pages absolutely (velxio.dev) in OSS,
exactly like the desktop app's Help menu.
2026-07-30 22:50:14 +07:00
|
|
|
{ kind: 'link', href: `${SITE}/docs`, label: t('header.nav.documentation', 'Documentation') },
|
2026-07-30 22:31:31 +07:00
|
|
|
{ kind: 'link', href: '/examples', label: t('header.nav.examples', 'Examples') },
|
refactor(routes): OSS is the editor; marketing moves to the overlay
The open-source build now ships exactly its product surface: /editor, the
examples gallery (/examples, /examples/:id) and the per-example editor
(/example/:id). Landing, about, pricing, docs, the 14 keyword-targeted
simulator landings and the v2/v2.5/v3 showcases move to the private
overlay, registered through the same registerProRoutes seam that already
carries login/admin/classroom.
Root behaves per build: an overlay that registers an index route claims
'/' (velxio.dev keeps its landing); otherwise '/' redirects to /editor.
The redirect waits for the overlay import to settle — same contract as
markProExamplesSettled — so a velxio.dev visitor is never bounced into
the editor because the landing was 300ms away from registering.
Prerender and sitemap follow the split: entry-server pulls the marketing
page map from '@pro/pages/marketing' behind a VITE_PRO_BUILD-gated dynamic
import (the proven main.tsx pattern, with an OSS stub for tsc), and
generate-sitemap lists only served routes in OSS builds (2 URLs) while
pro builds stay byte-identical — verified against a pre-migration
baseline: sitemap (37 URLs) and prerendered /, /about, /docs,
/arduino-simulator, /esp32-simulator, /v3 all identical modulo hashed
asset names. OSS prerender drops exactly the 32 marketing pages (348→316).
The OSS header slims down to match: Editor, Examples, GitHub, Discord —
the marketing links only render in pro builds, where their routes exist.
The editor Help menu links those pages absolutely (velxio.dev) in OSS,
exactly like the desktop app's Help menu.
2026-07-30 22:50:14 +07:00
|
|
|
{ kind: 'link', href: `${SITE}/pricing`, label: t('header.nav.pricing', 'Pricing') },
|
2026-07-30 22:31:31 +07:00
|
|
|
{ kind: 'separator' },
|
refactor(routes): OSS is the editor; marketing moves to the overlay
The open-source build now ships exactly its product surface: /editor, the
examples gallery (/examples, /examples/:id) and the per-example editor
(/example/:id). Landing, about, pricing, docs, the 14 keyword-targeted
simulator landings and the v2/v2.5/v3 showcases move to the private
overlay, registered through the same registerProRoutes seam that already
carries login/admin/classroom.
Root behaves per build: an overlay that registers an index route claims
'/' (velxio.dev keeps its landing); otherwise '/' redirects to /editor.
The redirect waits for the overlay import to settle — same contract as
markProExamplesSettled — so a velxio.dev visitor is never bounced into
the editor because the landing was 300ms away from registering.
Prerender and sitemap follow the split: entry-server pulls the marketing
page map from '@pro/pages/marketing' behind a VITE_PRO_BUILD-gated dynamic
import (the proven main.tsx pattern, with an OSS stub for tsc), and
generate-sitemap lists only served routes in OSS builds (2 URLs) while
pro builds stay byte-identical — verified against a pre-migration
baseline: sitemap (37 URLs) and prerendered /, /about, /docs,
/arduino-simulator, /esp32-simulator, /v3 all identical modulo hashed
asset names. OSS prerender drops exactly the 32 marketing pages (348→316).
The OSS header slims down to match: Editor, Examples, GitHub, Discord —
the marketing links only render in pro builds, where their routes exist.
The editor Help menu links those pages absolutely (velxio.dev) in OSS,
exactly like the desktop app's Help menu.
2026-07-30 22:50:14 +07:00
|
|
|
{ kind: 'link', href: SITE || '/', label: t('editor.menu.home', 'Velxio Home') },
|
|
|
|
|
{ kind: 'link', href: `${SITE}/blog/`, label: t('header.nav.blog', 'Blog') },
|
|
|
|
|
{ kind: 'link', href: `${SITE}/about`, label: t('editor.menu.about', 'About Velxio') },
|
2026-07-30 22:31:31 +07:00
|
|
|
{ kind: 'separator' },
|
|
|
|
|
{ kind: 'link', href: DISCORD_URL, label: t('editor.menu.discord', 'Discord Community') },
|
|
|
|
|
{ kind: 'link', href: GITHUB_URL, label: t('editor.menu.github', 'GitHub Repository') },
|
|
|
|
|
];
|
|
|
|
|
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
// 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[] = [
|
2026-07-31 02:12:28 +07:00
|
|
|
{ kind: 'command', id: 'sim.compile', label: t('editor.menu.compile', 'Compile'), shortcut: 'Ctrl+B' },
|
|
|
|
|
{ kind: 'command', id: 'sim.run', label: t('editor.menu.run', 'Run') },
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
{ 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' },
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
{ 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') },
|
|
|
|
|
];
|
|
|
|
|
|
2026-07-30 22:31:31 +07:00
|
|
|
const renderLink = (item: Extract<Item, { kind: 'link' }>): React.ReactNode => (
|
|
|
|
|
<a
|
|
|
|
|
key={item.href}
|
|
|
|
|
role="menuitem"
|
|
|
|
|
className="emb-item"
|
|
|
|
|
href={item.href}
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
onClick={() => setOpen(null)}
|
|
|
|
|
>
|
|
|
|
|
<span>{item.label}</span>
|
|
|
|
|
</a>
|
|
|
|
|
);
|
|
|
|
|
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
const renderCommand = (item: Extract<Item, { kind: 'command' }>): React.ReactNode => (
|
|
|
|
|
<button
|
|
|
|
|
key={item.id}
|
|
|
|
|
role="menuitem"
|
|
|
|
|
className="emb-item"
|
|
|
|
|
disabled={!hasEditorCommand(item.id)}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(null);
|
|
|
|
|
runEditorCommand(item.id);
|
|
|
|
|
}}
|
|
|
|
|
>
|
2026-07-31 00:18:37 +07:00
|
|
|
<span>
|
|
|
|
|
{item.label}
|
|
|
|
|
{item.pro && <span className="emb-pro">PRO</span>}
|
|
|
|
|
</span>
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
{item.shortcut && <span className="emb-shortcut">{item.shortcut}</span>}
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
|
2026-08-08 09:02:32 +07:00
|
|
|
const menu = (which: 'file' | 'edit' | 'view' | 'account' | 'help', label: string, items: Item[]): React.ReactNode => (
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
<div className="emb-root" key={which}>
|
|
|
|
|
<button
|
|
|
|
|
className={`emb-trigger${open === which ? ' emb-trigger-open' : ''}`}
|
|
|
|
|
aria-haspopup="menu"
|
|
|
|
|
aria-expanded={open === which}
|
|
|
|
|
onClick={() => setOpen((cur) => (cur === which ? null : which))}
|
|
|
|
|
onMouseEnter={() => setOpen((cur) => (cur && cur !== which ? which : cur))}
|
|
|
|
|
>
|
|
|
|
|
{label}
|
|
|
|
|
</button>
|
|
|
|
|
{open === which && (
|
|
|
|
|
<div className="emb-menu" role="menu">
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
{which === 'view' && (
|
|
|
|
|
<>
|
|
|
|
|
<button
|
|
|
|
|
role="menuitemcheckbox"
|
|
|
|
|
aria-checked={serialOpen}
|
|
|
|
|
className="emb-item"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(null);
|
|
|
|
|
toggleSerialMonitor();
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span>{t('editor.canvas.toggleSerialMonitor', 'Serial Monitor')}</span>
|
|
|
|
|
<span className="emb-shortcut">{serialOpen ? '✓' : ''}</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
role="menuitemcheckbox"
|
|
|
|
|
aria-checked={scopeOpen}
|
|
|
|
|
className="emb-item"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(null);
|
|
|
|
|
toggleOscilloscope();
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span>{t('editor.menu.toggleScope', 'Oscilloscope / Logic Analyzer')}</span>
|
|
|
|
|
<span className="emb-shortcut">{scopeOpen ? '✓' : ''}</span>
|
|
|
|
|
</button>
|
|
|
|
|
<div className="emb-separator" />
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2026-08-08 09:02:32 +07:00
|
|
|
{which === 'account' && (
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
<>
|
2026-08-11 00:47:20 +07:00
|
|
|
{/* Session entry points, above the pro extras. Exactly one of
|
|
|
|
|
the two is registered at a time (pro registers by session
|
|
|
|
|
state) and neither exists in OSS, so this block renders
|
|
|
|
|
nothing in an OSS build. */}
|
|
|
|
|
{accountItems
|
|
|
|
|
.filter((item) => item.kind !== 'command' || hasEditorCommand(item.id))
|
|
|
|
|
.map((item) => (item.kind === 'command' ? renderCommand(item) : null))}
|
|
|
|
|
{accountItems.some(
|
|
|
|
|
(item) => item.kind === 'command' && hasEditorCommand(item.id),
|
|
|
|
|
) && <div className="emb-separator" />}
|
2026-08-08 09:02:32 +07:00
|
|
|
{/* Pro account items (PRO badge, Subscribe / Manage
|
|
|
|
|
subscription, licenses, history, replays, Privacy) mount
|
|
|
|
|
here via the SAME user-menu slot the bottom-left account
|
|
|
|
|
dropdown uses — one overlay renderer, two hosts. Clicking
|
|
|
|
|
any of them closes this menu (they navigate or open their
|
|
|
|
|
own modal). Empty in OSS builds. */}
|
|
|
|
|
<div
|
|
|
|
|
data-velxio-slot="user-menu"
|
|
|
|
|
style={{ display: 'contents' }}
|
|
|
|
|
onClick={() => setOpen(null)}
|
|
|
|
|
/>
|
|
|
|
|
<div className="emb-separator" />
|
|
|
|
|
{/* Language moved in here from its own top-level menu — the
|
|
|
|
|
menubar was one trigger too wide once the AI chat docks. */}
|
|
|
|
|
<div className="emb-section-label">
|
|
|
|
|
{t('editor.menu.language', 'Language')}
|
|
|
|
|
</div>
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
{LOCALES.map((loc) => (
|
|
|
|
|
<button
|
|
|
|
|
key={loc}
|
|
|
|
|
role="menuitemradio"
|
|
|
|
|
aria-checked={currentLocale === loc}
|
|
|
|
|
className="emb-item"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(null);
|
|
|
|
|
if (loc === currentLocale) return;
|
|
|
|
|
navigate(
|
|
|
|
|
switchLocale(location.pathname, loc as Locale) +
|
|
|
|
|
location.search +
|
|
|
|
|
location.hash,
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span>{LOCALE_META[loc].nativeName}</span>
|
|
|
|
|
<span className="emb-shortcut">{currentLocale === loc ? '✓' : ''}</span>
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
{which === 'edit' && (
|
|
|
|
|
<>
|
|
|
|
|
<button
|
|
|
|
|
role="menuitem"
|
|
|
|
|
className="emb-item"
|
|
|
|
|
disabled={historyIndex < 0}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(null);
|
|
|
|
|
undo();
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span>{t('editor.menu.undo', 'Undo')}</span>
|
|
|
|
|
<span className="emb-shortcut">Ctrl+Z</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
role="menuitem"
|
|
|
|
|
className="emb-item"
|
|
|
|
|
disabled={historyIndex >= history.length - 1}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(null);
|
|
|
|
|
redo();
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span>{t('editor.menu.redo', 'Redo')}</span>
|
|
|
|
|
<span className="emb-shortcut">Ctrl+Y</span>
|
|
|
|
|
</button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2026-08-11 00:47:20 +07:00
|
|
|
{items
|
|
|
|
|
.filter(
|
|
|
|
|
(item) =>
|
|
|
|
|
item.kind !== 'command' || !item.optional || hasEditorCommand(item.id),
|
|
|
|
|
)
|
|
|
|
|
.map((item, i) =>
|
|
|
|
|
item.kind === 'separator' ? (
|
|
|
|
|
<div key={`sep-${i}`} className="emb-separator" />
|
|
|
|
|
) : item.kind === 'link' ? (
|
|
|
|
|
renderLink(item)
|
|
|
|
|
) : (
|
|
|
|
|
renderCommand(item)
|
|
|
|
|
),
|
|
|
|
|
)}
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="editor-menubar" ref={rootRef}>
|
|
|
|
|
{menu('file', t('editor.menu.file', 'File'), fileItems)}
|
|
|
|
|
{menu('edit', t('editor.menu.edit', 'Edit'), editItems)}
|
feat(editor): View and Language menus — full desktop-menu parity
The menubar now matches the desktop app's native menu set: File, Edit,
View, Language, Help.
View collects what the user asked to reach from a menu: Compile (Ctrl+B),
Run, Stop, Reset up top; the panel toggles — File Explorer, Output
Console, Serial Monitor, Oscilloscope/Logic Analyzer — in the middle
(store-backed ones render a live check, like a real desktop menu); and
the canvas view actions (center, zoom) move here from Edit, which goes
back to being undo/redo only, as menus have always worked.
Language lists the nine locales with the current one checked, switching
through the same switchLocale path the header globe uses — so language is
reachable from the menubar regardless of the account state, on top of
living in the signed-in account menu.
Run/Stop/Compile/Reset and the console toggle register through the
editorCommands seam from EditorToolbar (their handlers close over its
state); the explorer toggle from EditorPage; serial and scope call their
stores directly, same as undo/redo.
2026-07-31 02:05:55 +07:00
|
|
|
{menu('view', t('editor.menu.view', 'View'), viewItems)}
|
2026-08-08 09:02:32 +07:00
|
|
|
{menu('account', t('editor.menu.account', 'Account'), [])}
|
2026-07-30 22:31:31 +07:00
|
|
|
{menu('help', t('editor.menu.help', 'Help'), helpItems)}
|
feat(editor): menus File/Edit en la cabecera y editor sin nav de marketing
La queja: demasiados botones en una sola fila, y en pantallas pequenas se
solapan — medido, no impresion: a 1024px Code/Both/Circuit pisaban a
Compile/Run/Stop por 9-20px y Add pisaba el chat por 29px, con el idioma y
el usuario cortados fuera del viewport.
Tres piezas:
1. En el editor, el nav de marketing (Home/Docs/Pricing/...) sobra: ya
estas dentro, y cuesta exactamente el ancho que le falta a la toolbar.
AppHeader gana la variante editorMenu — mismo mecanismo que ya usa la
build de escritorio (VITE_DESKTOP) — que oculta el nav y pinta un menu
File/Edit junto al logo. El logo sigue llevando a inicio; idioma,
autoguardado, Share y usuario se quedan.
2. File/Edit al estilo escritorio: lo que se usa cada minuto sigue siendo
boton; lo que se usa unas veces por sesion va al menu. File: nuevo
workspace, nuevo fichero, abrir, guardar, importar, exportar, BOM,
imagen del esquema. Edit: undo/redo (con su estado real del historial),
centrar vista, zoom. Las acciones viven en cierres de cuatro
componentes distintos, asi que hay un registro id->handler
(lib/editorCommands, mismo patron de seam que registerProExamples o
registerBoardBuiltins): cada dueno registra al montar y el menu invoca
por id; un item sin dueno montado se pinta deshabilitado, que ademas es
la verdad. El registro sobrevive al remontaje StrictMode (el cleanup
viejo no borra al sucesor) y tiene test de eso.
3. La toolbar adelgaza: fuera Undo/Redo (Ctrl+Z/Y siguen), fuera los
botones inline de Import/Export y sus gemelos responsivos del More
(~70px recuperados); el More queda solo con los extras pro (firmware,
GitHub, share, grabacion). El CSS responsivo de los botones retirados
se va con ellos.
Suite en verde (2300) y build del overlay verificado desde este arbol.
2026-07-30 21:26:36 +07:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|