fix: menu in macos now with hotkeys
This commit is contained in:
@@ -2,6 +2,7 @@ defmodule BDS.Desktop.MenuBar do
|
|||||||
@moduledoc false
|
@moduledoc false
|
||||||
|
|
||||||
use BDS.Desktop.MenuCompat
|
use BDS.Desktop.MenuCompat
|
||||||
|
alias BDS.UI.Commands
|
||||||
alias BDS.UI.MenuBar, as: ShellMenuBar
|
alias BDS.UI.MenuBar, as: ShellMenuBar
|
||||||
alias Desktop.OS
|
alias Desktop.OS
|
||||||
alias Desktop.Window
|
alias Desktop.Window
|
||||||
@@ -38,7 +39,7 @@ defmodule BDS.Desktop.MenuBar do
|
|||||||
<%= if item.separator do %>
|
<%= if item.separator do %>
|
||||||
<hr />
|
<hr />
|
||||||
<% else %>
|
<% else %>
|
||||||
<item onclick={Atom.to_string(item.id)}>{item.label}</item>
|
<item onclick={Atom.to_string(item.id)}>{item.native_label}</item>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</menu>
|
</menu>
|
||||||
@@ -110,9 +111,21 @@ defmodule BDS.Desktop.MenuBar do
|
|||||||
defp normalize_item(%{separator: true}), do: %{separator: true}
|
defp normalize_item(%{separator: true}), do: %{separator: true}
|
||||||
|
|
||||||
defp normalize_item(item) do
|
defp normalize_item(item) do
|
||||||
%{id: item.id, label: item_label(item.id), separator: false}
|
label = item_label(item.id)
|
||||||
|
shortcut = Commands.accelerator_label(item.id)
|
||||||
|
|
||||||
|
%{
|
||||||
|
id: item.id,
|
||||||
|
label: label,
|
||||||
|
native_label: native_label(label, shortcut),
|
||||||
|
separator: false,
|
||||||
|
shortcut: shortcut
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp native_label(label, nil), do: label
|
||||||
|
defp native_label(label, shortcut), do: label <> "\t" <> shortcut
|
||||||
|
|
||||||
defp group_label(:file), do: "File"
|
defp group_label(:file), do: "File"
|
||||||
defp group_label(:edit), do: "Edit"
|
defp group_label(:edit), do: "Edit"
|
||||||
defp group_label(:view), do: "View"
|
defp group_label(:view), do: "View"
|
||||||
|
|||||||
@@ -3,18 +3,54 @@ defmodule BDS.UI.Commands do
|
|||||||
|
|
||||||
alias BDS.UI.MenuBar
|
alias BDS.UI.MenuBar
|
||||||
|
|
||||||
|
@menu_shortcuts [
|
||||||
|
%{id: :new_post, accelerator: "CTRL+N"},
|
||||||
|
%{id: :import_media, accelerator: "CTRL+I"},
|
||||||
|
%{id: :save, accelerator: "CTRL+S"},
|
||||||
|
%{id: :close_tab, accelerator: "CTRL+W", key: "w", primary: true},
|
||||||
|
%{id: :quit, accelerator: "CTRL+Q"},
|
||||||
|
%{id: :undo, accelerator: "CTRL+Z"},
|
||||||
|
%{id: :redo, accelerator: "CTRL+Y"},
|
||||||
|
%{id: :cut, accelerator: "CTRL+X"},
|
||||||
|
%{id: :copy, accelerator: "CTRL+C"},
|
||||||
|
%{id: :paste, accelerator: "CTRL+V"},
|
||||||
|
%{id: :select_all, accelerator: "CTRL+A"},
|
||||||
|
%{id: :find, accelerator: "CTRL+F"},
|
||||||
|
%{id: :replace, accelerator: "CTRL+H"},
|
||||||
|
%{id: :edit_preferences, accelerator: "CTRL+,"},
|
||||||
|
%{id: :view_posts, accelerator: "CTRL+1", key: "1", primary: true},
|
||||||
|
%{id: :view_media, accelerator: "CTRL+2", key: "2", primary: true},
|
||||||
|
%{id: :toggle_sidebar, accelerator: "CTRL+B", key: "b", primary: true},
|
||||||
|
%{id: :toggle_panel, accelerator: "CTRL+J", key: "j", primary: true},
|
||||||
|
%{id: :toggle_assistant_sidebar, accelerator: "CTRL+\\", key: "\\", primary: true},
|
||||||
|
%{id: :toggle_dev_tools, accelerator: "CTRL+SHIFT+I"},
|
||||||
|
%{id: :publish_selected, accelerator: "CTRL+SHIFT+P"},
|
||||||
|
%{id: :preview_post, accelerator: "CTRL+SHIFT+V"},
|
||||||
|
%{id: :generate_sitemap, accelerator: "CTRL+R"},
|
||||||
|
%{id: :validate_site, accelerator: "CTRL+SHIFT+L"},
|
||||||
|
%{id: :upload_site, accelerator: "CTRL+SHIFT+U"}
|
||||||
|
]
|
||||||
|
|
||||||
def handle_shortcut(state, shortcut) when is_map(shortcut) do
|
def handle_shortcut(state, shortcut) when is_map(shortcut) do
|
||||||
key = shortcut |> Map.get(:key, Map.get(shortcut, "key", "")) |> String.downcase()
|
key = shortcut |> Map.get(:key, Map.get(shortcut, "key", "")) |> String.downcase()
|
||||||
primary = Map.get(shortcut, :meta, false) or Map.get(shortcut, :ctrl, false)
|
primary = Map.get(shortcut, :meta, false) or Map.get(shortcut, :ctrl, false)
|
||||||
|
|
||||||
cond do
|
case Enum.find(@menu_shortcuts, &shortcut_match?(&1, key, primary)) do
|
||||||
primary and key == "b" -> MenuBar.execute(state, :toggle_sidebar)
|
%{id: command_id} -> MenuBar.execute(state, command_id)
|
||||||
primary and key == "j" -> MenuBar.execute(state, :toggle_panel)
|
nil -> state
|
||||||
primary and key == "1" -> MenuBar.execute(state, :view_posts)
|
|
||||||
primary and key == "2" -> MenuBar.execute(state, :view_media)
|
|
||||||
primary and key == "\\" -> MenuBar.execute(state, :toggle_assistant_sidebar)
|
|
||||||
primary and key == "w" -> MenuBar.execute(state, :close_tab)
|
|
||||||
true -> state
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def accelerator_label(command_id) when is_atom(command_id) do
|
||||||
|
case Enum.find(@menu_shortcuts, &(&1.id == command_id)) do
|
||||||
|
%{accelerator: accelerator} -> accelerator
|
||||||
|
nil -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp shortcut_match?(%{key: expected_key, primary: expected_primary}, key, primary) do
|
||||||
|
key == expected_key and primary == expected_primary
|
||||||
|
end
|
||||||
|
|
||||||
|
defp shortcut_match?(_shortcut, _key, _primary), do: false
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -68,6 +68,37 @@ defmodule BDS.DesktopTest do
|
|||||||
assert :api_documentation in help_actions
|
assert :api_documentation in help_actions
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "desktop menu bar exposes native accelerator labels for system menu items" do
|
||||||
|
groups = BDS.Desktop.MenuBar.groups(dev_mode?: false)
|
||||||
|
|
||||||
|
assert menu_item(groups, :new_post).native_label == "New Post\tCTRL+N"
|
||||||
|
assert menu_item(groups, :import_media).native_label == "Import Media\tCTRL+I"
|
||||||
|
assert menu_item(groups, :save).native_label == "Save\tCTRL+S"
|
||||||
|
assert menu_item(groups, :close_tab).shortcut == "CTRL+W"
|
||||||
|
assert menu_item(groups, :close_tab).native_label == "Close Tab\tCTRL+W"
|
||||||
|
assert menu_item(groups, :quit).native_label == "Quit\tCTRL+Q"
|
||||||
|
assert menu_item(groups, :undo).native_label == "Undo\tCTRL+Z"
|
||||||
|
assert menu_item(groups, :redo).native_label == "Redo\tCTRL+Y"
|
||||||
|
assert menu_item(groups, :cut).native_label == "Cut\tCTRL+X"
|
||||||
|
assert menu_item(groups, :copy).native_label == "Copy\tCTRL+C"
|
||||||
|
assert menu_item(groups, :paste).native_label == "Paste\tCTRL+V"
|
||||||
|
assert menu_item(groups, :select_all).native_label == "Select All\tCTRL+A"
|
||||||
|
assert menu_item(groups, :find).native_label == "Find\tCTRL+F"
|
||||||
|
assert menu_item(groups, :replace).native_label == "Replace\tCTRL+H"
|
||||||
|
assert menu_item(groups, :edit_preferences).native_label == "Preferences\tCTRL+,"
|
||||||
|
assert menu_item(groups, :view_posts).native_label == "Posts\tCTRL+1"
|
||||||
|
assert menu_item(groups, :view_media).native_label == "Media\tCTRL+2"
|
||||||
|
assert menu_item(groups, :toggle_sidebar).native_label == "Toggle Sidebar\tCTRL+B"
|
||||||
|
assert menu_item(groups, :toggle_panel).native_label == "Toggle Panel\tCTRL+J"
|
||||||
|
assert menu_item(groups, :toggle_assistant_sidebar).native_label == "Toggle Assistant Sidebar\tCTRL+\\"
|
||||||
|
assert menu_item(groups, :publish_selected).native_label == "Publish Selected\tCTRL+SHIFT+P"
|
||||||
|
assert menu_item(groups, :preview_post).native_label == "Preview Post\tCTRL+SHIFT+V"
|
||||||
|
assert menu_item(groups, :generate_sitemap).native_label == "Generate Sitemap\tCTRL+R"
|
||||||
|
assert menu_item(groups, :validate_site).native_label == "Validate Site\tCTRL+SHIFT+L"
|
||||||
|
assert menu_item(groups, :upload_site).native_label == "Upload Site\tCTRL+SHIFT+U"
|
||||||
|
assert menu_item(groups, :metadata_diff).shortcut == nil
|
||||||
|
end
|
||||||
|
|
||||||
test "desktop shell html follows the old app frame regions and references bundled assets" do
|
test "desktop shell html follows the old app frame regions and references bundled assets" do
|
||||||
html = BDS.Desktop.ShellController.index_html()
|
html = BDS.Desktop.ShellController.index_html()
|
||||||
|
|
||||||
@@ -244,4 +275,10 @@ defmodule BDS.DesktopTest do
|
|||||||
assert payload["result"]["project_id"] == project.id
|
assert payload["result"]["project_id"] == project.id
|
||||||
assert payload["result"]["url"] == "http://127.0.0.1:4123/"
|
assert payload["result"]["url"] == "http://127.0.0.1:4123/"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp menu_item(groups, id) do
|
||||||
|
groups
|
||||||
|
|> Enum.flat_map(& &1.items)
|
||||||
|
|> Enum.find(&Map.get(&1, :id) == id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user