App menu: the titlebar's "Settings and more" (Alt+F, F10, the palette, the account menu's last row) with rows from the site config; page zoom per tab in the host

Frame: AppMenu.tsx is a menu at the end of the titlebar cluster (before the caption buttons; macOS has none there). Its rows are `ShellSite.menu`: ordered groups of built-in rows by name and the app's own ({id, label, icon, shortcut, hint, when, checked, run | submenu}); `DEFAULT_MENU`, `menuWith` and `menuWithout` order, add and remove. A built-in row shows only when the app serves it (decks, `menu.languages`, themes, `menu.modes`, and `features`: zoom, store, workspaces, developer, updates), so no app gets a dead row. Language, Theme, Mode, Workspaces and Developer are submenus; Language and Theme apply live and keep the menu open, Mode asks the same keep-my-changes question as Settings (panel `menuModes()`). Keyboard: arrows, Home/End, type-ahead, the arrow along the reading direction opens a submenu, Esc closes one level; ARIA menu roles; submenus stay inside the window; one highlight for pointer and keys. It is an overlay like the other shell menus (the shell is raised, panes stay visible, nothing is dimmed).

Words: menuMessages.en.json (`wb.menu.*`), read through the framework i18n with that English as the fallback until the catalogs have them; words the panel already has are reused.

Host: `tab_zoom {id, factor}` (shell-only) sets a tab's page zoom with the engine's own zoom, clamped to 25%..500% and remembered per tab id in app data `zoom.json` (a number per tab id, nothing else; a closed tab's entry goes); without a factor it reads. A tab may forward four more shortcut names: `app-menu`, `zoom-in`, `zoom-out`, `zoom-reset`. The titlebar shows a zoom chip only while the pane in front is not at 100%.

create-waybetter: `tab_zoom` in the shell capability list; the template says which panel sections it lacks (store, updates) and how to add menu rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CRTkafa 2026-09-30 21:52:51 +07:00
parent eed6bdd8f4
commit e5d43afffc
27 changed files with 1587 additions and 18 deletions

View file

@ -9,6 +9,7 @@ import type { AddressModel } from '../addressModel.ts';
import type { ColumnSource, DeckColumn } from '../deckModel.ts';
import type { AccountRules } from '../profileModel.ts';
import type { IconName } from './icons.tsx';
import type { ShellMenu } from './menuModel.ts';
import type { PaletteItem } from './paletteModel.ts';
import type { ThemeStore } from './themeStore.ts';
@ -145,10 +146,18 @@ export type ShellSite = {
themes?: ThemeStore<any, any>;
/**
* Native features the app serves (waybetter-host modules it wires up): workspaces (`workspaces_*`),
* encrypted folder sync (`sync_*`), developer mode (`dev_*`) and plugin palette commands
* (`tab_run_command`). Each is on unless set to false; off, the frame shows nothing of it.
* encrypted folder sync (`sync_*`), developer mode (`dev_*`), plugin palette commands
* (`tab_run_command`) and page zoom (`tab_zoom`, the host's own); and what its panel has that the
* app menu links to: the Store (`PanelSite.store`) and the updater (`PanelSite.updates`). Each is
* on unless set to false; off, the frame shows nothing of it.
*/
features?: { workspaces?: boolean; sync?: boolean; developer?: boolean; pluginCommands?: boolean };
features?: { workspaces?: boolean; sync?: boolean; developer?: boolean; pluginCommands?: boolean; zoom?: boolean; store?: boolean; updates?: boolean };
/**
* The app menu (the titlebar's "Settings and more", Alt+F / F10): its rows in order (built-in
* ones by name, the app's own as objects) and what the Language and Mode submenus need. Omit for
* the default menu: every built-in row this app can serve (menuModel.ts `DEFAULT_MENU`).
*/
menu?: ShellMenu;
/** Components rendered on top of the shell (they listen to their own events). */
overlays?: ReadonlyArray<ComponentType>;
/** Called once the dock exists (read site settings, listen to site events). Returns a cleanup. */