mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
* feat(ui): add custom title bar window controls for Windows and Linux Hide the native title bar on win32/linux (titleBarStyle: 'hidden', frame untouched so native resize borders and snapping keep working) and render minimize / maximize-restore / close buttons in the renderer, mirroring the existing macOS traffic-light setup. - New WINDOW:* IPC contract (minimize, toggle-maximize, close, get-state) handled in window.events.ts, resolved from the sender WebContents; close goes through win.close() so window-bounds persistence still runs. - WINDOW:STATE_CHANGED pushed on maximize/unmaximize/fullscreen so the maximize/restore glyph stays correct for OS-triggered changes; controls hide while fullscreen. - WindowControlsComponent mounts once in app-root as a manual popover so it stays in the browser top layer above CDK overlays (dialogs, multi-EPG) - same behavior as macOS traffic lights. - Theme-aware via CSS vars (--app-on-surface, --app-hover-overlay); Windows-red close hover. Drag regions get right padding through a body-level frameless-platform class. - Gated by RuntimeCapabilitiesService.usesCustomWindowControls; PWA and macOS never mount the controls. Includes unit specs for the component and IPC handlers, an Electron E2E suite (window-controls.e2e.ts), and a window-chrome section in docs/architecture/workspace-shell.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(linux): upgrade Electron to 41 for frameless window decorations on Wayland With the native title bar hidden, Linux windows lost the WM-drawn shadow and rounded corners. Electron draws client-side decorations only on native Wayland, and frameless-window CSD (GTK drop shadow + extended resize boundaries) landed in Electron 41 - before that, frameless windows render as plain rectangles. - electron ^39.8.5 -> ^41.7.2 (Wayland auto-detected since 38.2; X11 sessions remain undecorated, matching other frameless Electron apps; Windows keeps its DWM shadow and rounded corners). - better-sqlite3 pinned to exactly 12.9.0: the last release shipping prebuilt binaries for both Node 20 (ABI 115, Jest) and Electron 41 (ABI 145, runtime). 12.10.0 dropped the Node 20 prebuilds, forcing a from-source build that fails without a C++ toolchain. - pnpm override node-abi 3.85.0 -> 3.92.0 so electron-builder install-app-deps can map Electron 41 to ABI 145. Reviewed Electron 40/41 breaking changes: only the renderer clipboard deprecation, which this app does not use. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(e2e): address review feedback and window-managerless Linux CI - Skip the three window-manager-dependent E2E assertions (maximize toggle, main-process state sync, minimize) on Linux CI: GitHub's ubuntu runners drive Electron under xvfb without a window manager, so maximize/minimize state never materializes there. Windows CI and local Linux/macOS runs keep the coverage. - WINDOW:TOGGLE_MAXIMIZE now returns the requested state instead of re-reading isMaximized() right after the call, which races on Linux window managers where maximize()/unmaximize() complete asynchronously; the WINDOW:STATE_CHANGED push stays authoritative. - Skip attaching window-state push listeners on macOS, where the custom controls never mount and the IPC traffic had no subscriber. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): gate custom window controls on the full bridge surface Include getWindowState and onWindowStateChange in the usesCustomWindowControls capability check — the controls rely on both for initial state and for keeping the maximize/restore glyph in sync with OS-triggered changes, so a partial bridge should not mount them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
89 lines
1.9 KiB
SCSS
89 lines
1.9 KiB
SCSS
// Floats above all app content so the window stays controllable while
|
|
// dialogs or the multi-EPG overlay are open — same behavior as the macOS
|
|
// traffic lights. The host is a manual popover (see component) because CDK
|
|
// overlays live in the browser top layer where z-index cannot compete; the
|
|
// declarations below also neutralize the UA popover styles (inset, margin,
|
|
// border, background) and keep the strip visible/positioned when the
|
|
// popover API is unavailable.
|
|
:host {
|
|
position: fixed;
|
|
inset: 0 0 auto auto;
|
|
z-index: 10000;
|
|
display: flex;
|
|
width: fit-content;
|
|
height: fit-content;
|
|
margin: 0;
|
|
padding: 0;
|
|
border: none;
|
|
background: transparent;
|
|
overflow: visible;
|
|
color: inherit;
|
|
app-region: no-drag;
|
|
-webkit-app-region: no-drag;
|
|
}
|
|
|
|
:host(.is-hidden) {
|
|
display: none;
|
|
}
|
|
|
|
.window-control {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 46px;
|
|
height: 32px;
|
|
margin: 0;
|
|
padding: 0;
|
|
border: none;
|
|
border-radius: 0;
|
|
background: transparent;
|
|
color: var(--app-on-surface, #1d1b1e);
|
|
opacity: 0.85;
|
|
// Native caption buttons use the arrow cursor, not the hand.
|
|
cursor: default;
|
|
|
|
svg {
|
|
display: block;
|
|
width: 10px;
|
|
height: 10px;
|
|
}
|
|
|
|
svg.crisp {
|
|
shape-rendering: crispEdges;
|
|
}
|
|
|
|
path {
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1;
|
|
}
|
|
|
|
&:hover {
|
|
background: var(--app-hover-overlay, rgba(0, 0, 0, 0.06));
|
|
opacity: 1;
|
|
}
|
|
|
|
&:active {
|
|
background: color-mix(
|
|
in srgb,
|
|
var(--app-on-surface, #1d1b1e) 14%,
|
|
transparent
|
|
);
|
|
}
|
|
|
|
&:focus-visible {
|
|
outline: 2px solid var(--mat-sys-primary);
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
&.close:hover {
|
|
background: #e81123;
|
|
color: #fff;
|
|
}
|
|
|
|
&.close:active {
|
|
background: #c50f1f;
|
|
color: #fff;
|
|
}
|
|
}
|