freedive/lib/liliform/flash.ex

143 lines
4.2 KiB
Elixir

defmodule Liliform.Flash do
use Liliform.Component
alias Phoenix.LiveView.JS
import FreediveWeb.Gettext
import Liliform.Button
import Liliform.Content
import Liliform.Hero
import Liliform.Media
import Liliform.Title
@doc """
Renders flash notices.
## Examples
<.flash kind={:info} flash={@flash} />
<.flash kind={:info} phx-mounted={show("#flash")}>Welcome Back!</.flash>
"""
attr :id, :string, doc: "the optional id of flash container"
attr :kind, :atom, values: [:info, :error], doc: "used for styling and flash lookup"
attr :title, :string, default: nil, doc: "optional title for flash message"
attr :flash, :map, default: %{}, doc: "the map of flash messages to display"
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the flash container"
slot :inner_block, doc: "the optional inner block that renders the flash message"
def flash(assigns) do
assigns = assign_new(assigns, :id, fn -> "flash-#{assigns.kind}" end)
# IO.inspect(assigns.rest)
~H"""
<.hero
:if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)}
id={@id}
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
role="alert"
class={
Enum.join(
[
"is-small",
@kind == :info && "is-info",
@kind == :error && "is-warning"
],
" "
)
}
{@rest}
>
<.media>
<.media_left>
<Lucideicons.info :if={@kind == :info} class="icon-small" aria-hidden />
<Lucideicons.triangle_alert :if={@kind == :error} class="icon-small" aria-hidden />
</.media_left>
<.media_content>
<.content>
<.title :if={@title} is-4>
<%= @title %>
</.title>
<.subtitle is-6>
<%= msg %>
</.subtitle>
</.content>
</.media_content>
<.media_right is-hidden-touch>
<.button aria-label={gettext("close")} phx-click={hide("##{@id}")}>
<Lucideicons.circle_x class="h-10 w-10" aria-hidden />
</.button>
</.media_right>
</.media>
</.hero>
"""
end
@doc """
Shows the flash group with standard titles and content.
## Examples
<.flash_group flash={@flash} />
"""
attr :flash, :map, required: true, doc: "the map of flash messages"
attr :id, :string, default: "flash-group", doc: "the optional id of flash container"
def flash_group(assigns) do
~H"""
<div id={@id}>
<.flash kind={:info} title={gettext("Info")} flash={@flash} is-info />
<.flash kind={:error} title={gettext("Error")} flash={@flash} is-danger />
<%!-- <.flash
id="client-error"
kind={:error}
title={gettext("We can't find the internet")}
phx-disconnected={show("#client-error")}
phx-connected={hide("#client-error")}
is-hidden
is-warning
>
<%= gettext("Attempting to reconnect") %>
<Lucideicons.refresh_cw class="h-4 w-4 animate-spin is-inline-block" aria-hidden />
</.flash>
<.flash
id="server-error"
kind={:error}
title={gettext("Something went wrong!")}
phx-disconnected={show("#server-error")}
phx-connected={hide("#server-error")}
is-hidden
is-warning
>
<%= gettext("Hang in there while we get back on track") %>
<Lucideicons.refresh_cw class="h-4 w-4 animate-spin is-inline-block" aria-hidden />
</.flash> --%>
</div>
"""
end
## JS Commands
def show(js \\ %JS{}, selector) do
JS.remove_class(js, "is-hidden",
to: selector,
time: 100,
transition:
{"transition-all transform ease-out duration-300",
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
"opacity-100 translate-y-0 sm:scale-100"}
)
end
def hide(js \\ %JS{}, selector) do
JS.add_class(js, "is-hidden",
to: selector,
time: 200,
transition:
{"transition-all transform ease-in duration-200",
"opacity-100 translate-y-0 sm:scale-100",
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"}
)
end
end