ux(menubar): Account menu replaces the top-level Language menu

The account options that only lived in the bottom-left user button
(subscription, licenses, simulation history, replays, privacy) are now
reachable from the header too: a new Account menu hosts the pro items via
the SAME data-velxio-slot="user-menu" the corner dropdown uses — one
overlay renderer, two hosts, empty in OSS builds. Language moves from its
own top-level trigger into a section of that menu, so the menubar stays at
five triggers and frees header room for when the AI chat docks.
This commit is contained in:
David Montero Crespo 2026-08-08 04:02:32 +02:00
parent f9a9657b5e
commit 9d38beae0e
4 changed files with 35 additions and 4 deletions

View File

@ -84,6 +84,18 @@
margin: 4px 6px;
}
/* Small uppercase section header inside a menu (the Account menu groups
the pro items and the Language list under one trigger). */
.emb-section-label {
padding: 6px 12px 2px;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.8px;
text-transform: uppercase;
color: #8a8f98;
user-select: none;
}
/* Same PRO pill the old toolbar overflow used (tb-overflow-pro) — users
should know an item is premium BEFORE clicking, not via a surprise
upgrade prompt. */

View File

@ -52,7 +52,7 @@ 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' | 'view' | 'lang' | 'help' | null>(null);
const [open, setOpen] = useState<'file' | 'edit' | 'view' | 'account' | 'help' | null>(null);
const rootRef = useRef<HTMLDivElement>(null);
// Re-render when owners (un)register their commands.
@ -180,7 +180,7 @@ export const EditorMenuBar: React.FC = () => {
</button>
);
const menu = (which: 'file' | 'edit' | 'view' | 'lang' | 'help', label: string, items: Item[]): React.ReactNode => (
const menu = (which: 'file' | 'edit' | 'view' | 'account' | 'help', label: string, items: Item[]): React.ReactNode => (
<div className="emb-root" key={which}>
<button
className={`emb-trigger${open === which ? ' emb-trigger-open' : ''}`}
@ -222,8 +222,25 @@ export const EditorMenuBar: React.FC = () => {
<div className="emb-separator" />
</>
)}
{which === 'lang' && (
{which === 'account' && (
<>
{/* 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>
{LOCALES.map((loc) => (
<button
key={loc}
@ -293,7 +310,7 @@ export const EditorMenuBar: React.FC = () => {
{menu('file', t('editor.menu.file', 'File'), fileItems)}
{menu('edit', t('editor.menu.edit', 'Edit'), editItems)}
{menu('view', t('editor.menu.view', 'View'), viewItems)}
{menu('lang', t('editor.menu.language', 'Language'), [])}
{menu('account', t('editor.menu.account', 'Account'), [])}
{menu('help', t('editor.menu.help', 'Help'), helpItems)}
</div>
);

View File

@ -378,6 +378,7 @@
"edit": "Edit",
"view": "View",
"language": "Language",
"account": "Account",
"help": "Help",
"newProject": "New workspace",
"newFile": "New file",

View File

@ -378,6 +378,7 @@
"edit": "Edición",
"view": "Ver",
"language": "Idioma",
"account": "Cuenta",
"help": "Ayuda",
"newProject": "Nuevo espacio de trabajo",
"newFile": "Nuevo archivo",