use phoenix component modal

This commit is contained in:
shibao 2022-02-14 01:26:51 -05:00
parent f517ffc8f8
commit 114f63b47a
16 changed files with 193 additions and 150 deletions

View File

@ -1,43 +0,0 @@
defmodule CanneryWeb.Components.Modal do
@moduledoc """
Livecomponent that displays a floating modal window
"""
use CanneryWeb, :live_component
@impl true
def render(assigns) do
~H"""
<div
id={@id}
class="fixed z-10 left-0 top-0
w-full h-full overflow-hidden
p-8 flex flex-col justify-center items-center"
style="opacity: 1 !important; background-color: rgba(0,0,0,0.4);"
phx-capture-click="close"
phx-window-keydown="close"
phx-key="escape"
phx-target={"#{@id}"}
phx-page-loading
>
<div class="w-full max-w-3xl max-h-128 relative overflow-y-auto
flex flex-col justify-start items-center
bg-white border-2 rounded-lg">
<%= live_patch to: @return_to,
class:
"absolute top-8 right-10 text-gray-500 hover:text-gray-800 transition-all duration-500 ease-in-out" do %>
<i class="fa-fw fa-lg fas fa-times"></i>
<% end %>
<div class="p-8 flex flex-col space-y-4 justify-start items-center">
<%= live_component(@component, @opts) %>
</div>
</div>
</div>
"""
end
@impl true
def handle_event("close", _, socket) do
{:noreply, push_patch(socket, to: socket.assigns.return_to)}
end
end

View File

@ -79,12 +79,15 @@
</div>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal(CanneryWeb.AmmoGroupLive.FormComponent,
id: @ammo_group.id || :new,
title: @page_title,
action: @live_action,
ammo_group: @ammo_group,
return_to: Routes.ammo_group_index_path(@socket, :index),
current_user: @current_user
) %>
<.modal return_to={Routes.ammo_group_index_path(@socket, :index)}>
<.live_component
module={CanneryWeb.AmmoGroupLive.FormComponent}
id={@ammo_group.id || :new}
title={@page_title}
action={@live_action}
ammo_group={@ammo_group}
return_to={Routes.ammo_group_index_path(@socket, :index)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -53,12 +53,15 @@
</div>
<%= if @live_action in [:edit] do %>
<%= live_modal(CanneryWeb.AmmoGroupLive.FormComponent,
id: @ammo_group.id,
title: @page_title,
action: @live_action,
ammo_group: @ammo_group,
return_to: Routes.ammo_group_show_path(@socket, :show, @ammo_group),
current_user: @current_user
) %>
<.modal return_to={Routes.ammo_group_show_path(@socket, :show, @ammo_group)}>
<.live_component
module={CanneryWeb.AmmoGroupLive.FormComponent}
id={@ammo_group.id}
title={@page_title}
action={@live_action}
ammo_group={@ammo_group}
return_to={Routes.ammo_group_show_path(@socket, :show, @ammo_group)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -13,7 +13,7 @@ defmodule CanneryWeb.AmmoTypeLive.FormComponent do
%{:ammo_type => AmmoType.t(), :current_user => User.t(), optional(any) => any},
Socket.t()
) :: {:ok, Socket.t()}
def update(%{ammo_type: ammo_type} = assigns, socket) do
def update(%{ammo_type: ammo_type, current_user: _current_user} = assigns, socket) do
{:ok, socket |> assign(assigns) |> assign(:changeset, Ammo.change_ammo_type(ammo_type))}
end
@ -186,9 +186,13 @@ defmodule CanneryWeb.AmmoTypeLive.FormComponent do
{:noreply, socket}
end
defp save_ammo_type(%{assigns: %{return_to: return_to}} = socket, :new, ammo_type_params) do
defp save_ammo_type(
%{assigns: %{current_user: current_user, return_to: return_to}} = socket,
:new,
ammo_type_params
) do
socket =
case Ammo.create_ammo_type(ammo_type_params) do
case Ammo.create_ammo_type(ammo_type_params, current_user) do
{:ok, %{name: ammo_type_name}} ->
prompt = dgettext("prompts", "%{name} created successfully", name: ammo_type_name)
socket |> put_flash(:info, prompt) |> push_redirect(to: return_to)

View File

@ -5,8 +5,8 @@ defmodule CanneryWeb.AmmoTypeLive.Index do
use CanneryWeb, :live_view
alias Cannery.Ammo
alias Cannery.Ammo.AmmoType
alias Cannery.{Ammo, Ammo.AmmoType}
alias CanneryWeb.Endpoint
@impl true
def mount(_params, session, socket) do

View File

@ -115,11 +115,16 @@
</div>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal(CanneryWeb.AmmoTypeLive.FormComponent,
id: @ammo_type.id || :new,
title: @page_title,
action: @live_action,
ammo_type: @ammo_type,
return_to: Routes.ammo_type_index_path(@socket, :index)
) %>
<.modal return_to={Routes.ammo_type_index_path(Endpoint, :index)}>
<.live_component
module={CanneryWeb.AmmoTypeLive.FormComponent}
id={@ammo_type.id || :new}
title={@page_title}
action={@live_action}
ammo_type={@ammo_type}
return_to={Routes.ammo_type_index_path(Endpoint, :index)}
current_user={@current_user}
}
/>
</.modal>
<% end %>

View File

@ -6,6 +6,7 @@ defmodule CanneryWeb.AmmoTypeLive.Show do
use CanneryWeb, :live_view
import CanneryWeb.Components.AmmoGroupCard
alias Cannery.Ammo
alias CanneryWeb.Endpoint
@impl true
def mount(_params, session, socket) do

View File

@ -106,11 +106,15 @@
</div>
<%= if @live_action in [:edit] do %>
<%= live_modal(CanneryWeb.AmmoTypeLive.FormComponent,
id: @ammo_type.id,
title: @page_title,
action: @live_action,
ammo_type: @ammo_type,
return_to: Routes.ammo_type_show_path(@socket, :show, @ammo_type)
) %>
<.modal return_to={Routes.ammo_type_show_path(Endpoint, :show, @ammo_type)}>
<.live_component
module={CanneryWeb.AmmoTypeLive.FormComponent}
id={@ammo_type.id}
title={@page_title}
action={@live_action}
ammo_type={@ammo_type}
return_to={Routes.ammo_type_show_path(Endpoint, :show, @ammo_type)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -43,12 +43,15 @@
</div>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal(CanneryWeb.ContainerLive.FormComponent,
id: @container.id || :new,
title: @page_title,
action: @live_action,
container: @container,
return_to: Routes.container_index_path(@socket, :index),
current_user: @current_user
) %>
<.modal return_to={Routes.container_index_path(@socket, :index)}>
<.live_component
module={CanneryWeb.ContainerLive.FormComponent}
id={@container.id || :new}
title={@page_title}
action={@live_action}
container={@container}
return_to={Routes.container_index_path(@socket, :index)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -92,23 +92,29 @@
</div>
<%= if @live_action in [:edit] do %>
<%= live_modal(CanneryWeb.ContainerLive.FormComponent,
id: @container.id,
title: @page_title,
action: @live_action,
container: @container,
return_to: Routes.container_show_path(Endpoint, :show, @container),
current_user: @current_user
) %>
<.modal return_to={Routes.container_show_path(Endpoint, :show, @container)}>
<.live_component
module={CanneryWeb.ContainerLive.FormComponent}
id={@container.id}
title={@page_title}
action={@live_action}
container={@container}
return_to={Routes.container_show_path(Endpoint, :show, @container)}
current_user={@current_user}
/>
</.modal>
<% end %>
<%= if @live_action == :add_tag do %>
<%= live_modal(CanneryWeb.ContainerLive.AddTagComponent,
id: @container.id,
title: @page_title,
action: @live_action,
container: @container,
return_to: Routes.container_show_path(Endpoint, :show, @container),
current_user: @current_user
) %>
<.modal return_to={Routes.container_show_path(Endpoint, :show, @container)}>
<.live_component
module={CanneryWeb.ContainerLive.AddTagComponent}
id={@container.id}
title={@page_title}
action={@live_action}
container={@container}
return_to={Routes.container_show_path(Endpoint, :show, @container)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -125,12 +125,15 @@
</div>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal(CanneryWeb.InviteLive.FormComponent,
id: @invite.id || :new,
title: @page_title,
action: @live_action,
invite: @invite,
return_to: Routes.invite_index_path(@socket, :index),
current_user: @current_user
) %>
<.modal return_to={Routes.invite_index_path(@socket, :index)}>
<.live_component
module={CanneryWeb.InviteLive.FormComponent}
id={@invite.id || :new}
title={@page_title}
action={@live_action}
invite={@invite}
return_to={Routes.invite_index_path(@socket, :index)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -3,29 +3,10 @@ defmodule CanneryWeb.LiveHelpers do
Contains common helper functions for liveviews
"""
import Phoenix.LiveView
import Phoenix.LiveView.Helpers
import Phoenix.LiveView, only: [assign_new: 3]
alias Cannery.Accounts
alias CanneryWeb.Components.Modal
@doc """
Renders a component inside the `Modal` component.
The rendered modal receives a `:return_to` option to properly update
the URL when the modal is closed.
## Examples
<%= live_modal CanneryWeb.TagLive.FormComponent,
id: @tag.id || :new,
action: @live_action,
tag: @tag,
return_to: Routes.tag_index_path(@socket, :index) %>
"""
def live_modal(component, opts) do
path = Keyword.fetch!(opts, :return_to)
live_component(Modal, id: :modal, return_to: path, component: component, opts: opts)
end
alias Phoenix.LiveView.JS
def assign_defaults(socket, %{"user_token" => user_token} = _session) do
socket
@ -35,4 +16,77 @@ defmodule CanneryWeb.LiveHelpers do
def assign_defaults(socket, _session) do
socket
end
@doc """
Renders a live component inside a modal.
The rendered modal receives a `:return_to` option to properly update
the URL when the modal is closed.
## Examples
<.modal return_to={Routes.<%= schema.singular %>_index_path(@socket, :index)}>
<.live_component
module={<%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent}
id={@<%= schema.singular %>.id || :new}
title={@page_title}
action={@live_action}
return_to={Routes.<%= schema.singular %>_index_path(@socket, :index)}
<%= schema.singular %>: @<%= schema.singular %>
/>
</.modal>
"""
def modal(assigns) do
assigns = assign_new(assigns, :return_to, fn -> nil end)
~H"""
<div
id="modal"
class="fade-in fixed z-10 left-0 top-0
w-full h-full overflow-hidden
p-8 flex flex-col justify-center items-center"
style="opacity: 1 !important; background-color: rgba(0,0,0,0.4);"
phx-remove={hide_modal()}
>
<div
id="modal-content"
class="fade-in-scale w-full max-w-3xl max-h-128 relative overflow-y-auto
flex flex-col justify-start items-center
bg-white border-2 rounded-lg"
phx-click-away={hide_modal()}
phx-window-keydown={hide_modal()}
phx-key="escape"
>
<%= if @return_to do %>
<%= live_patch to: @return_to,
id: "close",
class:
"absolute top-8 right-10 text-gray-500 hover:text-gray-800 transition-all duration-500 ease-in-out",
phx_click: hide_modal() do %>
<i class="fa-fw fa-lg fas fa-times"></i>
<% end %>
<% else %>
<a
id="close"
href="#"
class="absolute top-8 right-10 text-gray-500 hover:text-gray-800 transition-all duration-500 ease-in-out"
phx-click={hide_modal()}
>
<i class="fa-fw fa-lg fas fa-times"></i>
</a>
<% end %>
<div class="p-8 flex flex-col space-y-4 justify-start items-center">
<%= render_slot(@inner_block) %>
</div>
</div>
</div>
"""
end
def hide_modal(js \\ %JS{}) do
js
|> JS.hide(to: "#modal", transition: "fade-out")
|> JS.hide(to: "#modal-content", transition: "fade-out-scale")
end
end

View File

@ -43,12 +43,15 @@
</div>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal(CanneryWeb.TagLive.FormComponent,
id: @tag.id || :new,
title: @page_title,
action: @live_action,
tag: @tag,
return_to: Routes.tag_index_path(@socket, :index),
current_user: @current_user
) %>
<.modal return_to={Routes.tag_index_path(@socket, :index)}>
<.live_component
module={CanneryWeb.TagLive.FormComponent}
id={@tag.id || :new}
title={@page_title}
action={@live_action}
tag={@tag}
return_to={Routes.tag_index_path(@socket, :index)}
current_user={@current_user}
/>
</.modal>
<% end %>

View File

@ -65,8 +65,7 @@ msgid "Invite someone new!"
msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/components/topbar.ex:96
#: lib/cannery_web/templates/layout/topbar.html.heex:36
#: lib/cannery_web/components/topbar.ex:102
#: lib/cannery_web/templates/user_confirmation/new.html.heex:26
#: lib/cannery_web/templates/user_registration/new.html.heex:39
#: lib/cannery_web/templates/user_reset_password/edit.html.heex:41
@ -102,8 +101,7 @@ msgid "New Tag"
msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/components/topbar.ex:89
#: lib/cannery_web/templates/layout/topbar.html.heex:28
#: lib/cannery_web/components/topbar.ex:95
#: lib/cannery_web/templates/user_confirmation/new.html.heex:21
#: lib/cannery_web/templates/user_registration/new.html.heex:3
#: lib/cannery_web/templates/user_registration/new.html.heex:34

View File

@ -154,7 +154,7 @@ msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/live/ammo_type_live/index.ex:23
#: lib/cannery_web/live/ammo_type_live/show.ex:46
#: lib/cannery_web/live/ammo_type_live/show.ex:47
msgid "Edit Ammo type"
msgstr ""
@ -218,7 +218,7 @@ msgid "Invite Only"
msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/components/topbar.ex:60
#: lib/cannery_web/components/topbar.ex:66
msgid "Invites"
msgstr ""
@ -451,7 +451,7 @@ msgid "Show Ammo group"
msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/live/ammo_type_live/show.ex:45
#: lib/cannery_web/live/ammo_type_live/show.ex:46
msgid "Show Ammo type"
msgstr ""

View File

@ -11,7 +11,7 @@ msgid ""
msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/live/ammo_type_live/form_component.ex:193
#: lib/cannery_web/live/ammo_type_live/form_component.ex:197
#: lib/cannery_web/live/container_live/form_component.ex:126
#: lib/cannery_web/live/invite_live/form_component.ex:98
#: lib/cannery_web/live/tag_live/form_component.ex:101
@ -20,7 +20,7 @@ msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/live/ammo_type_live/index.ex:41
#: lib/cannery_web/live/ammo_type_live/show.ex:39
#: lib/cannery_web/live/ammo_type_live/show.ex:40
#: lib/cannery_web/live/invite_live/index.ex:54
#: lib/cannery_web/live/invite_live/index.ex:120
#: lib/cannery_web/live/tag_live/index.ex:41
@ -109,8 +109,7 @@ msgid "Are you sure you want to delete your account?"
msgstr ""
#, elixir-format, ex-autogen
#: lib/cannery_web/components/topbar.ex:75
#: lib/cannery_web/templates/layout/topbar.html.heex:21
#: lib/cannery_web/components/topbar.ex:81
msgid "Are you sure you want to log out?"
msgstr ""