diff --git a/lib/bds/desktop/shell_live/index.html.heex b/lib/bds/desktop/shell_live/index.html.heex index fae2d0c..c8f8e73 100644 --- a/lib/bds/desktop/shell_live/index.html.heex +++ b/lib/bds/desktop/shell_live/index.html.heex @@ -134,9 +134,15 @@
diff --git a/priv/ui/app.css b/priv/ui/app.css index 44e6f22..1460b31 100644 --- a/priv/ui/app.css +++ b/priv/ui/app.css @@ -107,7 +107,7 @@ button { flex-shrink: 0; app-region: drag; -webkit-app-region: drag; - padding-right: 10px; + padding-right: calc(10px + var(--bds-titlebar-overlay-right, 0px)); } .window-titlebar-menu-bar { @@ -125,6 +125,10 @@ button { display: none; } +.window-titlebar.is-mac .window-titlebar-menu-bar { + margin-left: max(var(--bds-titlebar-macos-left-inset, 78px), calc(6px + var(--bds-titlebar-overlay-left, 0px))); +} + .window-titlebar-menu-button { height: 24px; border: none; @@ -142,6 +146,14 @@ button { background-color: var(--vscode-toolbar-hoverBackground); } +.window-titlebar-menu-button:focus, +.window-titlebar-menu-button:focus-visible, +.window-titlebar-action-button:focus, +.window-titlebar-action-button:focus-visible { + outline: none; + box-shadow: none; +} + .window-titlebar-drag-region { flex: 1; height: 100%; @@ -296,7 +308,7 @@ button { justify-content: center; background: transparent; border: none; - color: var(--vscode-titleBar-activeForeground); + color: var(--vscode-activityBar-foreground); opacity: 0.6; cursor: pointer; position: relative; @@ -319,7 +331,7 @@ button { top: 0; bottom: 0; width: 2px; - background-color: var(--vscode-titleBar-activeForeground); + background-color: var(--vscode-activityBar-foreground); } .activity-bar-item svg, @@ -551,6 +563,20 @@ button { font-style: italic; } +.tab-actions { + display: flex; + align-items: center; + gap: 2px; + margin-left: auto; + flex-shrink: 0; +} + +.tab-dirty-indicator { + color: var(--vscode-editorWarning-foreground, #e2c08d); + font-size: 10px; + line-height: 1; +} + .tab-icon { display: flex; align-items: center; @@ -567,28 +593,63 @@ button { } .tab-close { - margin-left: auto; - width: 18px; - height: 18px; - display: inline-flex; + width: 20px; + height: 20px; + display: flex; align-items: center; justify-content: center; font-size: 15px; line-height: 1; - color: var(--vscode-descriptionForeground); - border-radius: 4px; + color: var(--vscode-icon-foreground, #c5c5c5); + border-radius: 3px; cursor: pointer; flex-shrink: 0; border: none; background: transparent; padding: 0; + opacity: 0; +} + +.tab:hover .tab-close { + opacity: 0.7; +} + +.tab.active .tab-close { + opacity: 0.7; } .tab-close:hover { + opacity: 1 !important; background-color: var(--vscode-toolbar-hoverBackground); color: var(--vscode-tab-activeForeground); } +.tab-close:active { + background-color: var(--vscode-toolbar-activeBackground, rgba(99, 102, 103, 0.31)); +} + +.tab.dirty .tab-dirty-indicator { + display: block; +} + +.tab.dirty .tab-close { + display: none; +} + +.tab.dirty:hover .tab-close { + display: flex; + opacity: 0.7; +} + +.tab.dirty:hover .tab-dirty-indicator { + display: none; +} + +.tab:focus-visible { + outline: 1px solid var(--vscode-focusBorder, #007fd4); + outline-offset: -1px; +} + .output-item-details { margin: 4px 0 0; padding: 8px; diff --git a/priv/ui/live.js b/priv/ui/live.js index 2c8b99f..730e2b2 100644 --- a/priv/ui/live.js +++ b/priv/ui/live.js @@ -50,11 +50,52 @@ document.addEventListener("DOMContentLoaded", () => { window.localStorage.setItem(key, String(width)); }; + const syncTitlebarOverlayInsets = () => { + const rootStyle = document.documentElement.style; + const setInsets = (left, right) => { + rootStyle.setProperty("--bds-titlebar-overlay-left", `${left}px`); + rootStyle.setProperty("--bds-titlebar-overlay-right", `${right}px`); + }; + + const overlay = navigator.windowControlsOverlay; + + if (!overlay) { + setInsets(0, 0); + return () => {}; + } + + const updateInsets = () => { + if (!overlay.visible) { + setInsets(0, 0); + return; + } + + const titlebarRect = overlay.getTitlebarAreaRect(); + const viewportWidth = window.innerWidth || document.documentElement.clientWidth || titlebarRect.right; + const leftInset = Math.max(0, Math.round(titlebarRect.left)); + const rightInset = Math.max(0, Math.round(viewportWidth - titlebarRect.right)); + setInsets(leftInset, rightInset); + }; + + const onGeometryChange = () => updateInsets(); + const onResize = () => updateInsets(); + + updateInsets(); + overlay.addEventListener("geometrychange", onGeometryChange); + window.addEventListener("resize", onResize); + + return () => { + overlay.removeEventListener("geometrychange", onGeometryChange); + window.removeEventListener("resize", onResize); + }; + }; + const Hooks = { AppShell: { mounted() { this.syncStoredLayout(); this.syncStoredUiLanguage(); + this.destroyOverlaySync = syncTitlebarOverlayInsets(); this.handleMouseDown = (event) => { const handle = event.target.closest("[data-role='resize-handle']"); @@ -126,6 +167,9 @@ document.addEventListener("DOMContentLoaded", () => { this.el.removeEventListener("mousedown", this.handleMouseDown); this.el.removeEventListener("change", this.handleChange); window.removeEventListener("bds:native-menu-action", this.handleNativeMenuAction); + if (this.destroyOverlaySync) { + this.destroyOverlaySync(); + } }, syncStoredLayout() { diff --git a/test/bds/ui/shell_test.exs b/test/bds/ui/shell_test.exs index c0e62c2..b076f07 100644 --- a/test/bds/ui/shell_test.exs +++ b/test/bds/ui/shell_test.exs @@ -126,4 +126,23 @@ defmodule BDS.UI.ShellTest do assert css =~ ".status-bar-item.language-badge" assert css =~ ".status-bar-item.offline-badge" end + + test "desktop shell assets keep old activity, tab, focus, and titlebar overlay parity rules" do + css = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.css") + live_js = File.read!("/Users/gb/Projects/bDS2/priv/ui/live.js") + template = File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/index.html.heex") + + assert css =~ "color: var(--vscode-activityBar-foreground)" + assert css =~ ".tab-actions" + assert css =~ ".tab-dirty-indicator" + assert css =~ ".tab.dirty .tab-close" + assert css =~ ".tab:focus-visible" + assert css =~ ".window-titlebar-action-button:focus" + assert css =~ "padding-right: calc(10px + var(--bds-titlebar-overlay-right, 0px));" + assert live_js =~ "windowControlsOverlay" + assert live_js =~ "geometrychange" + assert live_js =~ "--bds-titlebar-overlay-left" + assert template =~ "tab-actions" + assert template =~ "tab-dirty-indicator" + end end