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

View File

@@ -964,6 +964,45 @@ button {
min-width: 0; 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 { .status-bar-item {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -112,13 +112,24 @@ defmodule BDS.Desktop.ShellLiveTest do
assert html =~ ~s(class="tab-bar-empty") assert html =~ ~s(class="tab-bar-empty")
end 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) {: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-bar")
refute html =~ ~s(data-testid="window-titlebar-menu-button") refute html =~ ~s(data-testid="window-titlebar-menu-button")
refute html =~ ~s(data-testid="window-titlebar-menu-dropdown") 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 = html =
render_hook(view, "native_menu_action", %{"action" => "edit_preferences"}) 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.status == 200
assert conn.resp_body =~ ~s(class="app") assert conn.resp_body =~ ~s(class="app")
assert conn.resp_body =~ ~s(data-testid="window-titlebar") refute 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-menu-bar") 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="activity-bar")
assert conn.resp_body =~ ~s(class="sidebar") assert conn.resp_body =~ ~s(class="sidebar")
assert conn.resp_body =~ ~s(class="status-bar") 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 =~ ".window-titlebar-menu-bar.is-hidden"
assert css =~ "--vscode-statusBar-background: #007acc" assert css =~ "--vscode-statusBar-background: #007acc"
assert css =~ ".status-bar-left," assert css =~ ".status-bar-left,"
assert css =~ ".status-shell-controls"
assert css =~ ".status-shell-toggle-button"
assert css =~ "gap: 4px" assert css =~ "gap: 4px"
assert css =~ "padding: 0 8px" assert css =~ "padding: 0 8px"
assert css =~ "height: 100%" assert css =~ "height: 100%"
@@ -156,6 +158,7 @@ defmodule BDS.UI.ShellTest do
assert live_js =~ "event.preventDefault()" assert live_js =~ "event.preventDefault()"
assert live_js =~ "this.pushEvent(\"shortcut\"" assert live_js =~ "this.pushEvent(\"shortcut\""
assert template =~ "data-shortcuts={encoded_shortcuts(@client_shortcuts)}" assert template =~ "data-shortcuts={encoded_shortcuts(@client_shortcuts)}"
assert template =~ "data-testid=\"status-shell-controls\""
assert template =~ "activity-bar-badge" assert template =~ "activity-bar-badge"
assert template =~ "tab-actions" assert template =~ "tab-actions"
assert template =~ "tab-dirty-indicator" assert template =~ "tab-dirty-indicator"