Merge main into feat/7css-skin + give the HTML context menu an Aero skin
main retired electrobun's native context menu (a documented no-op on Linux) in favour of an HTML one on every platform. Merging that here needs the menu to look right under the Win7 skin as well. Conflicts, all resolved by keeping both sides: - src/bun/index.ts — createAppRPC keeps the branch's mainWindow getter, drops main's removed contextMenu dep. - ui/src/app/app.ts — imports both TitleBar and ContextMenu. - ui/src/app/platform.ts — kept the branch's version (its IS_MAC_CHROME accounts for the frameless win7 chrome, and MOD_LABEL correctly keys on the real platform rather than the chrome), plus exporting IS_MAC and adding IS_LINUX for the menu's per-OS shell wording. Aero menu (branch-only): 7.css has no menu component, so it is hand-authored across both layers — the row <button>s shed their push-button slab in `skin` (revert-layer only reaches `utilities` from there), and the square-cornered slab, hairline border and gradient selection band are stated in `skinfix`. Built strictly from existing --w7-* vars, never literal hex, so the hand-written dark Win7 palette recolours it for free. Hover and the keyboard cursor share one band (the component marks the cursor with `bg-accent`, which is overridden alongside :hover) as a real Win7 menu does. Also answers a question the merge raised: frameless windows DO work on Linux. The GTK wrapper honours titleBarStyle "hidden" — it calls gtk_window_set_decorated(false) and logs "GTK: Created window without decorations (custom titlebar)". Verified on GNOME/Wayland and documented in architecture.md. Verified: backend `tsc --noEmit` clean, `bun run build:ui` clean (492.52 kB initial, still under the 500 kB budget), app launches with the skin active, frameless, no console errors and no GBM failures. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+35
-11
@@ -10,7 +10,8 @@ Dense reference for development and debugging. Companion files:
|
||||
its native launcher. Owns every privileged capability: filesystem, SSH,
|
||||
window management, native menus/dialogs/tray, the connection/settings stores.
|
||||
- **Webviews** (`ui/` Angular): one per window, system WebKit on macOS /
|
||||
WebView2 on Windows. Zero privileged access — everything goes through RPC.
|
||||
WebView2 on Windows / WebKitGTK on Linux. Zero privileged access — everything
|
||||
goes through RPC.
|
||||
- **RPC transport**: one WebSocket server in the bun process, multiplexed by
|
||||
`webviewId` (each webview auto-connects using natively injected globals).
|
||||
Requests are typed by the `AppRPC` schema in `src/shared/rpc.ts`.
|
||||
@@ -148,10 +149,6 @@ would float over editor windows).
|
||||
- `store/connections.ts` — plaintext-passwords JSON (deliberate v1 choice),
|
||||
atomic tmp+rename, 0600 + win32 `icacls` ACL. `store/settings.ts` — defaults
|
||||
spread-merge on load, so NEW SETTINGS KEYS need no backend change.
|
||||
- `context-menu.ts` — native row/empty-space menus + the column picker.
|
||||
Local shell actions (reveal/open/copy-path) run bun-side via Utils; others
|
||||
forward through `menuAction` and the UI applies them to the row it
|
||||
remembered (`FileActionsService.menuTarget`). Labels are per-platform.
|
||||
- `menu.ts` — macOS-only app menu, rebuilt on every connections change (the
|
||||
Connect submenu mirrors the store). ⌘W is intercepted by the menu, so bun
|
||||
routes `close-tab` to the focused editor window first. Labels go through
|
||||
@@ -161,7 +158,8 @@ would float over editor windows).
|
||||
locale (from `settings.locale`, `system` via `Intl…resolvedOptions().locale`);
|
||||
`t(key, params)` shares the same `src/shared/i18n` dictionaries as the UI.
|
||||
Wired in index.ts on boot and on `settingsChanged` (relocalizes + rebuilds
|
||||
the app menu). `context-menu.ts` labels resolve through `t()` at show-time.
|
||||
the app menu). The context menu no longer needs this — it is Angular and reads
|
||||
`I18nService` directly.
|
||||
- `tray.ts` — static icon, click = activate main. macOS template image;
|
||||
Windows colored icon. No `setImage` calls ever (they lose the template
|
||||
treatment) and no menu (clicks arrive directly).
|
||||
@@ -220,12 +218,24 @@ would float over editor windows).
|
||||
boot and on the `settingsChanged` broadcast (so editor/manager windows follow).
|
||||
- `file-actions.service.ts` — toolbar/keyboard/context-menu file ops, always
|
||||
against an explicit panel; `menuTarget` remembers the right-clicked row.
|
||||
- `context-menu.service.ts` + `context-menu.ts` — the panel right-click menus,
|
||||
in HTML. Electrobun's native `showContextMenu` is a no-op on Linux, so it was
|
||||
retired on ALL platforms rather than kept as a second code path (see
|
||||
platform-notes.md). The service builds the item list (row / empty-space menu,
|
||||
and the header column picker) and holds the open request as a signal; the
|
||||
component renders it at the pointer with edge-flip clamping, arrow/Enter/Escape
|
||||
keys, and close-on-blur/resize/scroll. Picked items are emitted verbatim as
|
||||
`ctx-*` / `col:*` strings through `RpcService.emitMenuAction`, so they land in
|
||||
the SAME `App.handleMenuAction` dispatcher the macOS app menubar uses — one
|
||||
handler, two sources. The three shell actions the webview cannot perform
|
||||
(reveal, open-with-default, copy path) go back to bun via the `shellItemAction`
|
||||
RPC, which is all that remains of the old native menu.
|
||||
- `file-icons.ts` — extension → category map driving glyphs, colors
|
||||
(fixed `--icon-*` tokens, never accent-tinted) and the Kind column.
|
||||
- `platform.ts` — preload-global readers (`PLATFORM`, `APP_MODE`,
|
||||
`EDITOR_CONTEXT`, `IS_MAC_CHROME`, `IS_WINDOWS`, `MOD_LABEL`/`ALT_LABEL`)
|
||||
+ `blockNativeContextMenu` (kills WebKit's Reload/Inspect menu outside
|
||||
text fields).
|
||||
`EDITOR_CONTEXT`, `IS_MAC`/`IS_MAC_CHROME`, `IS_WINDOWS`, `IS_LINUX`,
|
||||
`MOD_LABEL`/`ALT_LABEL`) + `blockNativeContextMenu` (kills WebKit's
|
||||
Reload/Inspect menu outside text fields — the app draws its own menu instead).
|
||||
- `updater.service.ts` — auto-updater state for the tab-bar pill. Signals
|
||||
`state` (`idle→available→downloading→ready`|`error`), `version`, `progress`.
|
||||
Subscribes the `updateStatus` push (backend `Updater.checkForUpdate` on
|
||||
@@ -298,7 +308,18 @@ still scales and 7.css's `pt` shorthand stops resetting weight/line-height.
|
||||
(+aria) on the transfer bars, `has-scrollbar` on scroll containers (7.css only
|
||||
styles `::-webkit-scrollbar` under that class), `w7-toolbar` on the three
|
||||
header rows (their buttons go flat — Explorer's command bar was flat, unlike
|
||||
dialog push buttons), `w7-btn` on the 10 dialog action buttons.
|
||||
dialog push buttons), `w7-btn` on the 10 dialog action buttons, `w7-menu` (+
|
||||
`w7-menu-sep`) on the HTML context menu.
|
||||
|
||||
**Context menu**: 7.css ships no menu component, so the Aero menu is
|
||||
hand-authored across both layers — the row `<button>`s lose their push-button
|
||||
slab in `skin` (needs `revert-layer`), and the slab/border/selection-band paint
|
||||
is stated in `skinfix`. It is built ONLY from existing `--w7-*` vars (never
|
||||
literal hex), so the hand-written dark Win7 palette recolours it for free —
|
||||
the same constraint the dark block documents for itself. The hover and
|
||||
keyboard-cursor highlights are deliberately given the same band: the component
|
||||
marks the keyboard cursor with `bg-accent`, which is overridden alongside
|
||||
`:hover` so the two are indistinguishable, as in a real Win7 menu.
|
||||
|
||||
**Font**: Segoe UI is absent off Windows and not redistributable. Noto Sans —
|
||||
the substitute 7.css itself names — is vendored (OFL-1.1, from
|
||||
@@ -309,7 +330,10 @@ so esbuild emits it hashed into `media/` and rewrites the `url()`.
|
||||
place either skin's frame is decided, spread by both the main window and
|
||||
`openSecondaryWindow`. `win7` uses `titleBarStyle: "hidden"` on **every**
|
||||
platform — that clears `Titled` from the Cocoa style mask, which is also the
|
||||
only way to remove the macOS traffic lights. The webview then draws the whole
|
||||
only way to remove the macOS traffic lights. **Linux honours it too**: the GTK
|
||||
wrapper calls `gtk_window_set_decorated(false)` and logs "GTK: Created window
|
||||
without decorations (custom titlebar)" (verified on GNOME/Wayland), so the
|
||||
frameless Aero chrome is not a mac/win-only feature. The webview then draws the whole
|
||||
frame via `ui/src/app/title-bar/title-bar.ts` (7.css's `.title-bar` >
|
||||
`.title-bar-text` + `.title-bar-controls`, buttons keyed by `aria-label`),
|
||||
mounted by all three window roots. Because `titleBarStyle` is fixed at
|
||||
|
||||
Reference in New Issue
Block a user