feat: compact window on macos

This commit is contained in:
2026-04-26 10:02:27 +02:00
parent 8e8a2e2cd2
commit ad9d8263ec
5 changed files with 153 additions and 55 deletions

View File

@@ -1,11 +1,15 @@
<div class="app" id="bds-shell-app" phx-hook="AppShell" data-shortcuts={encoded_shortcuts(@client_shortcuts)}>
<div
class={["window-titlebar", if(@is_mac_ui, do: "is-mac")]}
data-region="title-bar"
data-testid="window-titlebar"
data-open-menu-group={@titlebar_menu_group || ""}
>
<%= unless @is_mac_ui do %>
<%= if @is_mac_ui do %>
<span data-testid="window-title" hidden><%= @page_title %></span>
<% end %>
<%= unless @is_mac_ui do %>
<div
class="window-titlebar"
data-region="title-bar"
data-testid="window-titlebar"
data-open-menu-group={@titlebar_menu_group || ""}
>
<div class="window-titlebar-menu-bar" data-testid="window-titlebar-menu-bar">
<%= for group <- @menu_groups do %>
<button
@@ -23,48 +27,46 @@
><%= group.label %></button>
<% end %>
</div>
<% end %>
<div class="window-titlebar-drag-region"></div>
<div class="window-titlebar-title" data-testid="window-title"><%= @page_title %></div>
<div class="window-titlebar-actions">
<button
class="window-titlebar-action-button"
data-testid="toggle-sidebar"
type="button"
phx-click="toggle_sidebar"
aria-label="Toggle sidebar"
title="Toggle sidebar"
>
<span class={["window-titlebar-sidebar-icon", if(@workbench.sidebar_visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-sidebar-pane"></span>
</span>
</button>
<button
class="window-titlebar-action-button"
data-testid="toggle-panel"
type="button"
phx-click="toggle_panel"
aria-label="Toggle panel"
title="Toggle panel"
>
<span class={["window-titlebar-panel-icon", if(@workbench.panel.visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-panel-pane"></span>
</span>
</button>
<button
class="window-titlebar-action-button"
data-testid="toggle-assistant"
type="button"
phx-click="toggle_assistant_sidebar"
aria-label="Toggle assistant"
title="Toggle assistant"
>
<span class={["window-titlebar-assistant-icon", if(@workbench.assistant_sidebar_visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-assistant-pane"></span>
</span>
</button>
</div>
<%= if not @is_mac_ui do %>
<div class="window-titlebar-drag-region"></div>
<div class="window-titlebar-title" data-testid="window-title"><%= @page_title %></div>
<div class="window-titlebar-actions">
<button
class="window-titlebar-action-button"
data-testid="toggle-sidebar"
type="button"
phx-click="toggle_sidebar"
aria-label={translated("Toggle sidebar")}
title={translated("Toggle sidebar")}
>
<span class={["window-titlebar-sidebar-icon", if(@workbench.sidebar_visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-sidebar-pane"></span>
</span>
</button>
<button
class="window-titlebar-action-button"
data-testid="toggle-panel"
type="button"
phx-click="toggle_panel"
aria-label={translated("Toggle panel")}
title={translated("Toggle panel")}
>
<span class={["window-titlebar-panel-icon", if(@workbench.panel.visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-panel-pane"></span>
</span>
</button>
<button
class="window-titlebar-action-button"
data-testid="toggle-assistant"
type="button"
phx-click="toggle_assistant_sidebar"
aria-label={translated("Toggle assistant")}
title={translated("Toggle assistant")}
>
<span class={["window-titlebar-assistant-icon", if(@workbench.assistant_sidebar_visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-assistant-pane"></span>
</span>
</button>
</div>
<%= if group = active_titlebar_menu_group(assigns) do %>
<div
class="window-titlebar-menu-dropdown"
@@ -93,8 +95,8 @@
<% end %>
</div>
<% end %>
<% end %>
</div>
</div>
<% end %>
<div class="app-main">
<aside class="activity-bar" data-region="activity-bar">
@@ -495,6 +497,46 @@
<footer class="status-bar" data-region="status-bar" data-testid="status-bar">
<div class="status-bar-left">
<%= if @is_mac_ui do %>
<div class="status-shell-controls" data-testid="status-shell-controls">
<button
class="status-shell-toggle-button"
data-testid="toggle-sidebar"
type="button"
phx-click="toggle_sidebar"
aria-label={translated("Toggle sidebar")}
title={translated("Toggle sidebar")}
>
<span class={["window-titlebar-sidebar-icon", if(@workbench.sidebar_visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-sidebar-pane"></span>
</span>
</button>
<button
class="status-shell-toggle-button"
data-testid="toggle-panel"
type="button"
phx-click="toggle_panel"
aria-label={translated("Toggle panel")}
title={translated("Toggle panel")}
>
<span class={["window-titlebar-panel-icon", if(@workbench.panel.visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-panel-pane"></span>
</span>
</button>
<button
class="status-shell-toggle-button"
data-testid="toggle-assistant"
type="button"
phx-click="toggle_assistant_sidebar"
aria-label={translated("Toggle assistant")}
title={translated("Toggle assistant")}
>
<span class={["window-titlebar-assistant-icon", if(@workbench.assistant_sidebar_visible, do: "is-active", else: "is-inactive")]}>
<span class="window-titlebar-assistant-pane"></span>
</span>
</button>
</div>
<% end %>
<div class="project-selector">
<button
class="project-selector-trigger"

View File

@@ -964,6 +964,45 @@ button {
min-width: 0;
}
.status-shell-controls {
display: flex;
align-items: stretch;
gap: 2px;
flex-shrink: 0;
}
.status-shell-toggle-button {
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 100%;
padding: 0;
line-height: 0;
background: transparent;
border: none;
color: inherit;
cursor: pointer;
border-radius: 3px;
}
.status-shell-toggle-button:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.status-shell-toggle-button:focus,
.status-shell-toggle-button:focus-visible {
outline: none;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
}
.status-shell-toggle-button .window-titlebar-sidebar-icon,
.status-shell-toggle-button .window-titlebar-panel-icon,
.status-shell-toggle-button .window-titlebar-assistant-icon {
width: 12px;
height: 12px;
}
.status-bar-item {
display: flex;
align-items: center;

View File

@@ -112,13 +112,24 @@ defmodule BDS.Desktop.ShellLiveTest do
assert html =~ ~s(class="tab-bar-empty")
end
test "titlebar menu stays hidden on macos because the native menu owns it" do
test "macos hides the custom titlebar and moves shell toggles into the status bar" do
{:ok, view, html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
assert html =~ ~s(class="window-titlebar is-mac")
refute html =~ ~s(data-testid="window-titlebar")
refute html =~ ~s(data-testid="window-titlebar-menu-bar")
refute html =~ ~s(data-testid="window-titlebar-menu-button")
refute html =~ ~s(data-testid="window-titlebar-menu-dropdown")
assert html =~ ~s(data-testid="status-shell-controls")
assert html =~ ~s(data-testid="toggle-sidebar")
assert html =~ ~s(data-testid="toggle-panel")
assert html =~ ~s(data-testid="toggle-assistant")
html =
view
|> element("[data-testid='toggle-sidebar']")
|> render_click()
assert html =~ ~s(class="sidebar-shell is-hidden")
html =
render_hook(view, "native_menu_action", %{"action" => "edit_preferences"})

View File

@@ -101,9 +101,12 @@ defmodule BDS.DesktopTest do
assert conn.status == 200
assert conn.resp_body =~ ~s(class="app")
assert conn.resp_body =~ ~s(data-testid="window-titlebar")
assert conn.resp_body =~ ~s(class="window-titlebar is-mac")
refute conn.resp_body =~ ~s(data-testid="window-titlebar")
refute conn.resp_body =~ ~s(data-testid="window-titlebar-menu-bar")
assert conn.resp_body =~ ~s(data-testid="status-shell-controls")
assert conn.resp_body =~ ~s(data-testid="toggle-sidebar")
assert conn.resp_body =~ ~s(data-testid="toggle-panel")
assert conn.resp_body =~ ~s(data-testid="toggle-assistant")
assert conn.resp_body =~ ~s(class="activity-bar")
assert conn.resp_body =~ ~s(class="sidebar")
assert conn.resp_body =~ ~s(class="status-bar")

View File

@@ -121,6 +121,8 @@ defmodule BDS.UI.ShellTest do
assert css =~ ".window-titlebar-menu-bar.is-hidden"
assert css =~ "--vscode-statusBar-background: #007acc"
assert css =~ ".status-bar-left,"
assert css =~ ".status-shell-controls"
assert css =~ ".status-shell-toggle-button"
assert css =~ "gap: 4px"
assert css =~ "padding: 0 8px"
assert css =~ "height: 100%"
@@ -156,6 +158,7 @@ defmodule BDS.UI.ShellTest do
assert live_js =~ "event.preventDefault()"
assert live_js =~ "this.pushEvent(\"shortcut\""
assert template =~ "data-shortcuts={encoded_shortcuts(@client_shortcuts)}"
assert template =~ "data-testid=\"status-shell-controls\""
assert template =~ "activity-bar-badge"
assert template =~ "tab-actions"
assert template =~ "tab-dirty-indicator"