@@ -57,23 +57,12 @@ defmodule BDS.Desktop.ShellLive do
|
||||
{:noreply, reload_shell(socket, workbench)}
|
||||
end
|
||||
|
||||
def handle_event("open_sidebar_item", %{"route" => route, "id" => id} = params, socket) do
|
||||
route_atom = sidebar_route_atom(route)
|
||||
tab_id = tab_id_for_route(route_atom, id)
|
||||
def handle_event("open_sidebar_item", %{"route" => _route, "id" => _id} = params, socket) do
|
||||
{:noreply, open_sidebar_item(socket, params, :preview)}
|
||||
end
|
||||
|
||||
workbench =
|
||||
Workbench.open_tab(socket.assigns.workbench, route_atom, tab_id, tab_intent(route_atom))
|
||||
|
||||
tab_meta =
|
||||
Map.put(socket.assigns.tab_meta, {route_atom, tab_id}, %{
|
||||
title: Map.get(params, "title", ""),
|
||||
subtitle: Map.get(params, "subtitle", "")
|
||||
})
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:tab_meta, tab_meta)
|
||||
|> reload_shell(workbench)}
|
||||
def handle_event("pin_sidebar_item", %{"route" => _route, "id" => _id} = params, socket) do
|
||||
{:noreply, open_sidebar_item(socket, params, :pin)}
|
||||
end
|
||||
|
||||
def handle_event("select_tab", %{"type" => type, "id" => id}, socket) do
|
||||
@@ -181,6 +170,8 @@ defmodule BDS.Desktop.ShellLive do
|
||||
data-testid="sidebar-open-item"
|
||||
data-route={item.route}
|
||||
data-item-id={item.id}
|
||||
data-open-title={item.title}
|
||||
data-open-subtitle={format_sidebar_timestamp(item.meta_timestamp)}
|
||||
type="button"
|
||||
phx-click="open_sidebar_item"
|
||||
phx-value-route={item.route}
|
||||
@@ -218,6 +209,8 @@ defmodule BDS.Desktop.ShellLive do
|
||||
data-testid="sidebar-open-item"
|
||||
data-route={item.route}
|
||||
data-item-id={item.id}
|
||||
data-open-title={item.title}
|
||||
data-open-subtitle={item.meta}
|
||||
type="button"
|
||||
title={item.title}
|
||||
phx-click="open_sidebar_item"
|
||||
@@ -259,6 +252,8 @@ defmodule BDS.Desktop.ShellLive do
|
||||
data-testid="sidebar-open-item"
|
||||
data-route={item.route}
|
||||
data-item-id={item.id}
|
||||
data-open-title={item.title}
|
||||
data-open-subtitle={translated(item.meta || "")}
|
||||
type="button"
|
||||
phx-click="open_sidebar_item"
|
||||
phx-value-route={item.route}
|
||||
@@ -290,6 +285,8 @@ defmodule BDS.Desktop.ShellLive do
|
||||
data-testid="sidebar-open-item"
|
||||
data-route={item.route}
|
||||
data-item-id={item.id}
|
||||
data-open-title={translated(item.title)}
|
||||
data-open-subtitle={translated(Map.get(@sidebar_data, :subtitle, ""))}
|
||||
type="button"
|
||||
phx-click="open_sidebar_item"
|
||||
phx-value-route={item.route}
|
||||
@@ -433,6 +430,24 @@ defmodule BDS.Desktop.ShellLive do
|
||||
Enum.find(tabs, &(&1.type == type and &1.id == id))
|
||||
end
|
||||
|
||||
defp open_sidebar_item(socket, params, intent) do
|
||||
route_atom = sidebar_route_atom(Map.fetch!(params, "route"))
|
||||
tab_id = tab_id_for_route(route_atom, Map.fetch!(params, "id"))
|
||||
|
||||
workbench =
|
||||
Workbench.open_tab(socket.assigns.workbench, route_atom, tab_id, tab_intent(route_atom, intent))
|
||||
|
||||
tab_meta =
|
||||
Map.put(socket.assigns.tab_meta, {route_atom, tab_id}, %{
|
||||
title: Map.get(params, "title", ""),
|
||||
subtitle: Map.get(params, "subtitle", "")
|
||||
})
|
||||
|
||||
socket
|
||||
|> assign(:tab_meta, tab_meta)
|
||||
|> reload_shell(workbench)
|
||||
end
|
||||
|
||||
defp sidebar_route_atom(route) when is_atom(route), do: route
|
||||
defp sidebar_route_atom(route) when is_binary(route), do: String.to_existing_atom(route)
|
||||
|
||||
@@ -443,10 +458,10 @@ defmodule BDS.Desktop.ShellLive do
|
||||
end
|
||||
end
|
||||
|
||||
defp tab_intent(route) do
|
||||
defp tab_intent(route, requested_intent) do
|
||||
case Registry.editor_route(route) do
|
||||
%{singleton: true} -> :pin
|
||||
_other -> :preview
|
||||
_other -> requested_intent
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
style={"width: #{@workbench.sidebar_width}px;"}
|
||||
>
|
||||
<div class="sidebar" data-region="sidebar">
|
||||
<div class="sidebar-content sidebar-body">
|
||||
<div id="sidebar-content" class="sidebar-content sidebar-body" phx-hook="SidebarInteractions">
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header">
|
||||
<span><%= String.upcase(sidebar_header_label(@sidebar_header)) %></span>
|
||||
|
||||
@@ -3,8 +3,36 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
.querySelector("meta[name='csrf-token']")
|
||||
.getAttribute("content");
|
||||
|
||||
const Hooks = {
|
||||
SidebarInteractions: {
|
||||
mounted() {
|
||||
this.handleDblClick = (event) => {
|
||||
const button = event.target.closest("[data-testid='sidebar-open-item']");
|
||||
|
||||
if (!button || !this.el.contains(button)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pushEvent("pin_sidebar_item", {
|
||||
route: button.dataset.route,
|
||||
id: button.dataset.itemId,
|
||||
title: button.dataset.openTitle || "",
|
||||
subtitle: button.dataset.openSubtitle || ""
|
||||
});
|
||||
};
|
||||
|
||||
this.el.addEventListener("dblclick", this.handleDblClick);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.el.removeEventListener("dblclick", this.handleDblClick);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const liveSocket = new LiveView.LiveSocket("/live", Phoenix.Socket, {
|
||||
params: { _csrf_token: csrfToken }
|
||||
params: { _csrf_token: csrfToken },
|
||||
hooks: Hooks
|
||||
});
|
||||
|
||||
liveSocket.connect();
|
||||
|
||||
@@ -64,4 +64,65 @@ defmodule BDS.Desktop.ShellLiveTest do
|
||||
refute html =~ ~s(data-tab-type="settings")
|
||||
assert html =~ ~s(class="tab-bar-empty")
|
||||
end
|
||||
|
||||
test "sidebar open supports preview and pin intents for entity tabs" do
|
||||
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
||||
|
||||
html =
|
||||
render_click(view, "open_sidebar_item", %{
|
||||
"route" => "post",
|
||||
"id" => "post-1",
|
||||
"title" => "First Post",
|
||||
"subtitle" => "draft"
|
||||
})
|
||||
|
||||
assert html =~ ~s(data-tab-type="post")
|
||||
assert html =~ ~s(data-tab-id="post-1")
|
||||
assert html =~ ~s(class="tab active transient")
|
||||
|
||||
html =
|
||||
render_click(view, "pin_sidebar_item", %{
|
||||
"route" => "post",
|
||||
"id" => "post-1",
|
||||
"title" => "First Post",
|
||||
"subtitle" => "draft"
|
||||
})
|
||||
|
||||
assert html =~ ~s(data-tab-id="post-1")
|
||||
refute html =~ ~s(class="tab active transient")
|
||||
|
||||
html =
|
||||
render_click(view, "open_sidebar_item", %{
|
||||
"route" => "post",
|
||||
"id" => "page-1",
|
||||
"title" => "About Page",
|
||||
"subtitle" => "page"
|
||||
})
|
||||
|
||||
assert html =~ ~s(data-tab-id="post-1")
|
||||
assert html =~ ~s(data-tab-id="page-1")
|
||||
assert String.contains?(html, ">First Post<")
|
||||
assert String.contains?(html, ">About Page<")
|
||||
|
||||
_html =
|
||||
render_click(view, "pin_sidebar_item", %{
|
||||
"route" => "media",
|
||||
"id" => "media-1",
|
||||
"title" => "hero.png",
|
||||
"subtitle" => "12 KB"
|
||||
})
|
||||
|
||||
html =
|
||||
render_click(view, "open_sidebar_item", %{
|
||||
"route" => "media",
|
||||
"id" => "media-2",
|
||||
"title" => "cover.png",
|
||||
"subtitle" => "8 KB"
|
||||
})
|
||||
|
||||
assert html =~ ~s(data-tab-id="media-1")
|
||||
assert html =~ ~s(data-tab-id="media-2")
|
||||
assert String.contains?(html, ">hero.png<")
|
||||
assert String.contains?(html, ">cover.png<")
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user