app: dropdown improvements
This commit is contained in:
parent
c81d112eb8
commit
2771a7bcb2
6 changed files with 141 additions and 116 deletions
|
@ -31,24 +31,30 @@ defmodule PrymnWeb.Button do
|
||||||
|
|
||||||
def secondary(assigns), do: button(assign(assigns, :variant, "secondary"))
|
def secondary(assigns), do: button(assign(assigns, :variant, "secondary"))
|
||||||
|
|
||||||
defp button_assigns(assigns) do
|
@doc """
|
||||||
assign(
|
Render a tertiary variant button.
|
||||||
assigns,
|
|
||||||
:style,
|
|
||||||
[
|
|
||||||
"inline-flex justify-center items-center rounded-2xl shadow transition-colors active:shadow-sm",
|
|
||||||
by_variant(assigns.variant),
|
|
||||||
by_size(assigns.size),
|
|
||||||
assigns[:class]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp button(%{rest: %{href: _}} = assigns), do: link_button(assigns)
|
## Examples
|
||||||
defp button(%{rest: %{navigate: _}} = assigns), do: link_button(assigns)
|
|
||||||
defp button(%{rest: %{patch: _}} = assigns), do: link_button(assigns)
|
|
||||||
|
|
||||||
defp button(assigns) do
|
<.tertiary>Click me</.tertiary>
|
||||||
|
<.tertiary href="/a/path" size="sm">Link button</.tertiary>
|
||||||
|
"""
|
||||||
|
def tertiary(assigns), do: button(assign(assigns, :variant, "tertiary"))
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Render a button.
|
||||||
|
"""
|
||||||
|
attr :variant, :string, default: "primary"
|
||||||
|
attr :size, :string, default: "md", values: ~w(sm md lg)
|
||||||
|
attr :class, :string, default: nil
|
||||||
|
attr :rest, :global, include: ~w(href navigate patch)
|
||||||
|
slot :inner_block, required: true
|
||||||
|
|
||||||
|
def button(%{rest: %{href: _}} = assigns), do: link_button(assigns)
|
||||||
|
def button(%{rest: %{navigate: _}} = assigns), do: link_button(assigns)
|
||||||
|
def button(%{rest: %{patch: _}} = assigns), do: link_button(assigns)
|
||||||
|
|
||||||
|
def button(assigns) do
|
||||||
assigns = button_assigns(assigns)
|
assigns = button_assigns(assigns)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
|
@ -58,6 +64,19 @@ defmodule PrymnWeb.Button do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp button_assigns(assigns) do
|
||||||
|
assign(
|
||||||
|
assigns,
|
||||||
|
:style,
|
||||||
|
[
|
||||||
|
"inline-flex justify-center items-center rounded-2xl transition-colors",
|
||||||
|
by_variant(assigns.variant),
|
||||||
|
by_size(assigns.size),
|
||||||
|
assigns[:class]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
defp link_button(assigns) do
|
defp link_button(assigns) do
|
||||||
assigns = button_assigns(assigns)
|
assigns = button_assigns(assigns)
|
||||||
|
|
||||||
|
@ -73,9 +92,14 @@ defmodule PrymnWeb.Button do
|
||||||
defp by_size("lg"), do: "text-lg px-7 py-3"
|
defp by_size("lg"), do: "text-lg px-7 py-3"
|
||||||
|
|
||||||
defp by_variant("primary"),
|
defp by_variant("primary"),
|
||||||
do: "font-medium bg-black text-white hover:bg-slate-800 active:text-white/80"
|
do:
|
||||||
|
"font-medium bg-black text-white shadow active:shadow-sm hover:bg-slate-800 active:text-white/80"
|
||||||
|
|
||||||
defp by_variant("secondary"),
|
defp by_variant("secondary"),
|
||||||
do:
|
do:
|
||||||
"font-medium bg-transparent border border-slate-800 text-slate-800 hover:bg-slate-800 hover:text-white active:text-white/80"
|
"font-medium bg-transparent border shadow active:shadow-sm border-slate-800 text-slate-800 hover:bg-slate-800 hover:text-white active:text-white/80"
|
||||||
|
|
||||||
|
defp by_variant("tertiary"),
|
||||||
|
do:
|
||||||
|
"font-medium border-none text-black hover:bg-slate-50 focus:bg-slate-50 active:text-black/80"
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ defmodule PrymnWeb.CoreComponents do
|
||||||
|
|
||||||
Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage.
|
Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage.
|
||||||
"""
|
"""
|
||||||
use Phoenix.Component
|
use Phoenix.Component, global_prefixes: ~w(x-)
|
||||||
|
|
||||||
alias Phoenix.LiveView.JS
|
alias Phoenix.LiveView.JS
|
||||||
import PrymnWeb.Gettext
|
import PrymnWeb.Gettext
|
||||||
|
@ -594,10 +594,21 @@ defmodule PrymnWeb.CoreComponents do
|
||||||
attr :title, :string, default: nil
|
attr :title, :string, default: nil
|
||||||
attr :position, :string, default: "left", values: ~w(left right)
|
attr :position, :string, default: "left", values: ~w(left right)
|
||||||
|
|
||||||
slot :button
|
slot :button do
|
||||||
|
attr :title, :string
|
||||||
|
attr :variant, :string, values: ~w(primary secondary tertiary)
|
||||||
|
attr :size, :string, values: ~w(sm md lg)
|
||||||
|
end
|
||||||
|
|
||||||
slot :item
|
slot :item
|
||||||
|
|
||||||
def dropdown(assigns) do
|
def dropdown(assigns) do
|
||||||
|
assigns =
|
||||||
|
assign(assigns, :style, [
|
||||||
|
(assigns.position == "left" && "left-0") || "right-0",
|
||||||
|
"absolute z-10 w-56 rounded-xl bg-white shadow-lg ring-1 ring-black ring-opacity-5"
|
||||||
|
])
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div
|
<div
|
||||||
class="relative inline-block"
|
class="relative inline-block"
|
||||||
|
@ -608,36 +619,41 @@ defmodule PrymnWeb.CoreComponents do
|
||||||
focusAfter && focusAfter.focus()
|
focusAfter && focusAfter.focus()
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
x-id="['dropdown-button']"
|
|
||||||
x-on:keydown.escape.prevent.stop="close($refs.button)"
|
x-on:keydown.escape.prevent.stop="close($refs.button)"
|
||||||
>
|
>
|
||||||
<button
|
<%= for button <- @button do %>
|
||||||
title={@title}
|
<PrymnWeb.Button.button
|
||||||
type="button"
|
title={button[:title]}
|
||||||
x-ref="button"
|
variant={button[:variant] || "primary"}
|
||||||
x-bind:aria-expanded="open"
|
size={button[:size] || "md"}
|
||||||
x-on:click="open = !open"
|
type="button"
|
||||||
>
|
x-ref="button"
|
||||||
<%= render_slot(@button) %>
|
x-bind:aria-expanded="open"
|
||||||
<.icon class="ml-2 h-4 w-4" name="hero-chevron-down" />
|
x-on:click="open = !open"
|
||||||
</button>
|
>
|
||||||
|
<%= render_slot(@button) %>
|
||||||
|
<.icon class="ml-2 h-4 w-4" name="hero-chevron-down" />
|
||||||
|
</PrymnWeb.Button.button>
|
||||||
|
<% end %>
|
||||||
<div
|
<div
|
||||||
class="absolute left-0 z-10 w-56 rounded-xl bg-white shadow-lg ring-1 ring-black ring-opacity-5"
|
class={@style}
|
||||||
role="menu"
|
role="menu"
|
||||||
aria-orientation="vertical"
|
aria-orientation="vertical"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
x-show="open"
|
x-show="open"
|
||||||
x-on:click.outside="close($refs.button)"
|
x-on:click.outside="close($refs.button)"
|
||||||
x-transition.origin.top.left
|
{if assigns.position == "left", do: ["x-transition.origin.top.left": true], else: []}
|
||||||
|
{if assigns.position == "right", do: ["x-transition.origin.top.right": true], else: []}
|
||||||
>
|
>
|
||||||
<div
|
<.link
|
||||||
:for={item <- @item}
|
:for={item <- @item}
|
||||||
class="my-2 px-4 py-2 hover:bg-slate-100"
|
{item}
|
||||||
role="none"
|
class="my-2 block px-4 py-2 hover:bg-slate-100"
|
||||||
|
role="menuitem"
|
||||||
x-on:click="close()"
|
x-on:click="close()"
|
||||||
>
|
>
|
||||||
<%= render_slot(item, item) %>
|
<%= render_slot(item) %>
|
||||||
</div>
|
</.link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -16,16 +16,12 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center text-zinc-900">
|
<div class="flex items-center text-zinc-900">
|
||||||
<.dropdown>
|
<.dropdown position="right">
|
||||||
<:button>
|
<:button variant="tertiary">
|
||||||
<.icon name="hero-user-solid" />
|
<.icon name="hero-user-solid" />
|
||||||
</:button>
|
</:button>
|
||||||
<:item>
|
<:item href={~p"/users/settings"}>Settings</:item>
|
||||||
<.link href={~p"/users/settings"}>Settings</.link>
|
<:item method="DELETE" href={~p"/auth/log_out"}>Log out</:item>
|
||||||
</:item>
|
|
||||||
<:item>
|
|
||||||
<.link method="DELETE" href={~p"/auth/log_out"}>Log out</.link>
|
|
||||||
</:item>
|
|
||||||
</.dropdown>
|
</.dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,6 +26,50 @@ defmodule PrymnWeb.ServerLive.Index do
|
||||||
|> assign(:healths, healths)}
|
|> assign(:healths, healths)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="mx-auto max-w-2xl">
|
||||||
|
<.header>
|
||||||
|
Your servers
|
||||||
|
<small class="block">
|
||||||
|
<%= "#{Enum.count(@servers)} servers" %>
|
||||||
|
</small>
|
||||||
|
<:actions>
|
||||||
|
<Button.primary patch={~p"/servers/new"}>Connect a Server</Button.primary>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
<div class="space-y-5" phx-update="replace" id="servers">
|
||||||
|
<.link
|
||||||
|
:for={server <- @servers}
|
||||||
|
navigate={~p"/servers/#{server}"}
|
||||||
|
class="group block rounded-lg bg-gray-100 p-5 shadow-sm shadow-gray-300 hover:bg-black hover:text-white"
|
||||||
|
>
|
||||||
|
<div class="flex flex-row flex-wrap justify-between">
|
||||||
|
<h2 class="text-xl"><%= server.name %></h2>
|
||||||
|
<.server_status status={server.status} health={@healths[server.public_ip]} />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row flex-wrap justify-between lg:text-sm">
|
||||||
|
<span>IP: <%= server.public_ip || "N/A" %></span>
|
||||||
|
<span
|
||||||
|
:if={@healths[server.public_ip] && Enum.count(@healths[server.public_ip].tasks)}
|
||||||
|
class="text-right text-xs text-slate-700"
|
||||||
|
>
|
||||||
|
<%= for {name, task} <- Enum.take(@healths[server.public_ip].tasks, 1) do %>
|
||||||
|
<div>In progress: <%= name %></div>
|
||||||
|
<div><%= task.progress %></div>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</.link>
|
||||||
|
</div>
|
||||||
|
<.modal :if={@live_action == :new} id="server-modal" show on_cancel={JS.patch(~p"/servers")}>
|
||||||
|
<.live_component module={PrymnWeb.ServerLive.NewServer} id={:new} patch={~p"/servers"} />
|
||||||
|
</.modal>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_params(_params, _url, socket) do
|
def handle_params(_params, _url, socket) do
|
||||||
socket =
|
socket =
|
||||||
|
@ -63,7 +107,7 @@ defmodule PrymnWeb.ServerLive.Index do
|
||||||
|
|
||||||
{:registered, nil} ->
|
{:registered, nil} ->
|
||||||
~H"""
|
~H"""
|
||||||
<.spinner class="w-5" />
|
<.spinner size="md" />
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{:registered, %Agents.Health{status: :connected}} ->
|
{:registered, %Agents.Health{status: :connected}} ->
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
<div class="mx-auto max-w-2xl">
|
|
||||||
<.header>
|
|
||||||
Your servers
|
|
||||||
<small class="block">
|
|
||||||
<%= "#{Enum.count(@servers)} servers" %>
|
|
||||||
</small>
|
|
||||||
<:actions>
|
|
||||||
<Button.primary patch={~p"/servers/new"}>Connect a Server</Button.primary>
|
|
||||||
</:actions>
|
|
||||||
</.header>
|
|
||||||
|
|
||||||
<div class="space-y-5" phx-update="replace" id="servers">
|
|
||||||
<.link
|
|
||||||
:for={server <- @servers}
|
|
||||||
navigate={~p"/servers/#{server}"}
|
|
||||||
class="group block rounded-lg bg-gray-100 p-5 shadow-sm shadow-gray-300 hover:bg-black hover:text-white"
|
|
||||||
>
|
|
||||||
<div class="flex flex-row flex-wrap justify-between">
|
|
||||||
<h2 class="text-xl"><%= server.name %></h2>
|
|
||||||
<.server_status status={server.status} health={@healths[server.public_ip]} />
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-row flex-wrap justify-between lg:text-sm">
|
|
||||||
<span>IP: <%= server.public_ip || "N/A" %></span>
|
|
||||||
<span
|
|
||||||
:if={@healths[server.public_ip] && Enum.count(@healths[server.public_ip].tasks)}
|
|
||||||
class="text-right text-xs text-slate-700"
|
|
||||||
>
|
|
||||||
<%= for {name, task} <- Enum.take(@healths[server.public_ip].tasks, 1) do %>
|
|
||||||
<div>In progress: <%= name %></div>
|
|
||||||
<div><%= task.progress %></div>
|
|
||||||
<% end %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</.link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<.modal :if={@live_action == :new} id="server-modal" show on_cancel={JS.patch(~p"/servers")}>
|
|
||||||
<.live_component module={PrymnWeb.ServerLive.NewServer} id={:new} patch={~p"/servers"} />
|
|
||||||
</.modal>
|
|
||||||
</div>
|
|
|
@ -15,51 +15,36 @@ defmodule PrymnWeb.ServerLive.Show do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="mx-auto max-w-2xl">
|
<div class="mx-auto max-w-2xl">
|
||||||
<div class="flex justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div id="server-name" class="relative flex items-center">
|
<div id="server-name" class="relative flex items-center">
|
||||||
<.dropdown title="Select a different server">
|
<.dropdown title="Select a different server">
|
||||||
<:button>Server <%= @server.name %></:button>
|
<:button variant="tertiary">Server <%= @server.name %></:button>
|
||||||
<:item :for={server <- Enum.filter(@servers, fn s -> s.id != @server.id end)}>
|
<:item
|
||||||
<.link
|
:for={server <- Enum.filter(@servers, fn s -> s.id != @server.id end)}
|
||||||
patch={~p"/servers/#{server}"}
|
patch={~p"/servers/#{server}"}
|
||||||
class="block text-sm text-gray-700"
|
>
|
||||||
role="menuitem"
|
<%= server.name %>
|
||||||
>
|
|
||||||
<%= server.name %>
|
|
||||||
</.link>
|
|
||||||
</:item>
|
</:item>
|
||||||
</.dropdown>
|
</.dropdown>
|
||||||
<button
|
<Button.tertiary title="Edit server name" phx-click={show_edit_server_name()}>
|
||||||
class="ml-4 inline-flex items-center"
|
|
||||||
title="Edit server name"
|
|
||||||
phx-click={show_edit_server_name()}
|
|
||||||
>
|
|
||||||
<.icon class="h-4 w-4" name="hero-pencil-solid" />
|
<.icon class="h-4 w-4" name="hero-pencil-solid" />
|
||||||
</button>
|
</Button.tertiary>
|
||||||
<.indicator message={@health.message} />
|
<.indicator message={@health.message} />
|
||||||
</div>
|
</div>
|
||||||
<form class="hidden" id="server-name-edit" phx-submit={submit_edit_server_name()}>
|
<form class="hidden" id="server-name-edit" phx-submit={submit_edit_server_name()}>
|
||||||
<input
|
<input class="rounded-xl" type="text" name="name" value={@server.name} required />
|
||||||
class="border-0 border-b border-gray-500"
|
<Button.tertiary type="submit" title="Confirm">
|
||||||
type="text"
|
|
||||||
name="name"
|
|
||||||
value={@server.name}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<button type="submit" title="Confirm">
|
|
||||||
<.icon name="hero-check" />
|
<.icon name="hero-check" />
|
||||||
</button>
|
</Button.tertiary>
|
||||||
</form>
|
</form>
|
||||||
<div class="space-x-2">
|
<div class="space-x-2">
|
||||||
<Button.primary size="sm">New App</Button.primary>
|
|
||||||
<.dropdown>
|
<.dropdown>
|
||||||
<:button>
|
<:button variant="tertiary" size="sm">Quick actions</:button>
|
||||||
Quick actions
|
|
||||||
</:button>
|
|
||||||
<:item>
|
<:item>
|
||||||
Test
|
Test
|
||||||
</:item>
|
</:item>
|
||||||
</.dropdown>
|
</.dropdown>
|
||||||
|
<Button.primary size="sm">New App</Button.primary>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm opacity-75"><%= @server.public_ip %></span>
|
<span class="text-sm opacity-75"><%= @server.public_ip %></span>
|
||||||
|
|
Loading…
Reference in a new issue