import { Component, inject, input, output, signal } from '@angular/core'; import { RpcService } from '../rpc.service'; /** * The Aero title bar. Rendered by all three window kinds. The native frame is * gone on every platform (titleBarStyle 'hidden'), so this row IS the window's * chrome. * * The markup is 7.css's contract, not ours: `.title-bar` > `.title-bar-text` + * `.title-bar-controls` > buttons keyed by `aria-label` (Minimize / Maximize / * Restore / Close each get their own glyph). Nothing here is styled with * Tailwind on purpose — the whole row comes from @layer skin. * * `.title-bar` lives on the HOST element, not on an inner div. 7.css couples * the glass treatment with a DIRECT-child selector — `.window.glass > * .title-bar` — and an inner div puts in between, so the rule * never matched: the title bar rendered as the opaque fallback with its own * border, visibly disconnected from the frame, instead of the translucent * streaked glass that fuses with it. * * Dragging rides on electrobun's preload drag-region classes. Two things * electrobun does NOT provide and this component implements: * - double-click to maximize (it only wires mousedown/mouseup) * - the maximize/restore glyph state, which has no event; bun derives it * from the native resize and pushes `windowState` (see trackMaximizeState). */ @Component({ selector: 'app-title-bar', host: { class: 'title-bar electrobun-webkit-app-region-drag', '(dblclick)': 'toggle()', }, template: `
{{ title() }}
@if (resizable()) { }
`, }) export class TitleBar { readonly title = input(''); /** The manager window is a fixed-size modal — it gets Close only. */ readonly resizable = input(true); /** Hosts decide what closing means (quit / dirty prompt / managerClose). */ readonly closeRequested = output(); protected readonly maximized = signal(false); private readonly rpc = inject(RpcService); constructor() { if (!this.rpc.available) return; // No maximize event exists, so seed from a one-shot read and then follow // the resize-derived push (which also covers Aero Snap and Win+Up). void this.rpc.request.windowIsMaximized({}).then((res) => { if (res.ok) this.maximized.set(res.maximized); }); this.rpc.onWindowState((maximized) => this.maximized.set(maximized)); } protected minimize(): void { void this.rpc.request.windowMinimize({}); } protected toggle(): void { void this.rpc.request.windowToggleMaximize({}).then((res) => { if (res.ok) this.maximized.set(res.maximized); }); } }