2024-05-13 11:21:05 +02:00
|
|
|
defmodule Liliform.Components do
|
|
|
|
use Phoenix.Component, global_prefixes: ["is-", "has-", "flex-", "justify-", "align-"]
|
|
|
|
alias Phoenix.LiveView.JS
|
|
|
|
import FreediveWeb.Gettext
|
2024-05-09 22:14:54 +02:00
|
|
|
import PhxComponentHelpers
|
2024-05-13 11:21:05 +02:00
|
|
|
require Logger
|
2024-05-09 22:14:54 +02:00
|
|
|
|
|
|
|
@doc """
|
2024-05-13 11:21:05 +02:00
|
|
|
Translates an error message using gettext.
|
2024-05-09 22:14:54 +02:00
|
|
|
"""
|
2024-05-13 11:21:05 +02:00
|
|
|
def translate_error({msg, opts}) do
|
|
|
|
# When using gettext, we typically pass the strings we want
|
|
|
|
# to translate as a static argument:
|
|
|
|
#
|
|
|
|
# # Translate the number of files with plural rules
|
|
|
|
# dngettext("errors", "1 file", "%{count} files", count)
|
|
|
|
#
|
|
|
|
# However the error messages in our forms and APIs are generated
|
|
|
|
# dynamically, so we need to translate them by calling Gettext
|
|
|
|
# with our gettext backend as first argument. Translations are
|
|
|
|
# available in the errors.po file (as we use the "errors" domain).
|
|
|
|
if count = opts[:count] do
|
|
|
|
Gettext.dngettext(FreediveWeb.Gettext, "errors", msg, msg, count, opts)
|
|
|
|
else
|
|
|
|
Gettext.dgettext(FreediveWeb.Gettext, "errors", msg, opts)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Translates the errors for a field from a keyword list of errors.
|
|
|
|
"""
|
|
|
|
def translate_errors(errors, field) when is_list(errors) do
|
|
|
|
for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts})
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders a label.
|
|
|
|
"""
|
|
|
|
attr :for, :string, default: nil, doc: "the for attribute of the label"
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the label"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the label"
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the label content"
|
|
|
|
|
|
|
|
def label(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("label")
|
|
|
|
|> set_attributes([:for])
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<label {@heex_for} {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</label>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders an input with label and error messages.
|
|
|
|
|
|
|
|
A `Phoenix.HTML.FormField` may be passed as argument,
|
|
|
|
which is used to retrieve the input name, id, and values.
|
|
|
|
Otherwise all attributes may be passed explicitly.
|
|
|
|
|
|
|
|
## Types
|
|
|
|
|
|
|
|
This function accepts all HTML input types, considering that:
|
|
|
|
|
|
|
|
* You may also set `type="select"` to render a `<select>` tag
|
|
|
|
|
|
|
|
* `type="checkbox"` is used exclusively to render boolean values
|
|
|
|
|
|
|
|
* For live file uploads, see `Phoenix.Component.live_file_input/1`
|
|
|
|
|
|
|
|
See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
|
|
|
|
for more information.
|
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
|
|
|
<.input field={@form[:email]} type="email" />
|
|
|
|
<.input name="my-input" errors={["oh no!"]} />
|
|
|
|
"""
|
|
|
|
attr :id, :any, default: nil
|
|
|
|
attr :name, :any
|
|
|
|
attr :label, :string, default: nil
|
|
|
|
attr :value, :any
|
|
|
|
|
|
|
|
attr :type, :string,
|
|
|
|
default: "text",
|
|
|
|
values: ~w(checkbox color date datetime-local email file hidden month number password
|
|
|
|
range radio search select tel text textarea time url week)
|
|
|
|
|
|
|
|
attr :field, Phoenix.HTML.FormField,
|
|
|
|
doc: "a form field struct retrieved from the form, for example: @form[:email]"
|
|
|
|
|
|
|
|
attr :errors, :list, default: []
|
|
|
|
attr :checked, :boolean, doc: "the checked flag for checkbox inputs"
|
|
|
|
attr :prompt, :string, default: nil, doc: "the prompt for select inputs"
|
|
|
|
attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2"
|
|
|
|
attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs"
|
|
|
|
|
|
|
|
attr :rest, :global,
|
|
|
|
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
|
|
|
|
multiple pattern placeholder readonly required rows size step)
|
|
|
|
|
|
|
|
slot :inner_block
|
|
|
|
|
|
|
|
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
|
|
|
|
assigns
|
|
|
|
|> assign(field: nil, id: assigns.id || field.id)
|
|
|
|
|> assign(:errors, Enum.map(field.errors, &translate_error(&1)))
|
|
|
|
|> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end)
|
|
|
|
|> assign_new(:value, fn -> field.value end)
|
|
|
|
|> input()
|
|
|
|
end
|
|
|
|
|
|
|
|
def input(%{type: "checkbox"} = assigns) do
|
|
|
|
assigns =
|
|
|
|
assign_new(assigns, :checked, fn ->
|
|
|
|
Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value])
|
|
|
|
end)
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div class="field" phx-feedback-for={@name}>
|
|
|
|
<label class="label">
|
|
|
|
<input type="hidden" name={@name} value="false" />
|
|
|
|
<input
|
|
|
|
type="checkbox"
|
|
|
|
id={@id}
|
|
|
|
name={@name}
|
|
|
|
value="true"
|
|
|
|
checked={@checked}
|
|
|
|
class="checkbox focus:ring-0"
|
|
|
|
{@rest}
|
|
|
|
/>
|
|
|
|
<%!-- todo: is focus:ring-0 part of tailwind? if yes, find alternative/remove --%>
|
|
|
|
<%= @label %>
|
|
|
|
</label>
|
|
|
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
def input(%{type: "select"} = assigns) do
|
|
|
|
~H"""
|
|
|
|
<div class="field" phx-feedback-for={@name}>
|
|
|
|
<.label for={@id}><%= @label %></.label>
|
|
|
|
<select
|
|
|
|
id={@id}
|
|
|
|
name={@name}
|
|
|
|
class="select focus:border-zinc-400 focus:ring-0 sm:text-sm"
|
|
|
|
multiple={@multiple}
|
|
|
|
{@rest}
|
|
|
|
>
|
|
|
|
<option :if={@prompt} value=""><%= @prompt %></option>
|
|
|
|
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
|
|
|
|
</select>
|
|
|
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
def input(%{type: "textarea"} = assigns) do
|
|
|
|
~H"""
|
|
|
|
<div class="field" phx-feedback-for={@name}>
|
|
|
|
<.label for={@id}><%= @label %></.label>
|
|
|
|
<textarea
|
|
|
|
id={@id}
|
|
|
|
name={@name}
|
|
|
|
class={[
|
|
|
|
"textarea focus:ring-0",
|
|
|
|
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
|
|
|
|
@errors == [] && "border-zinc-300 focus:border-zinc-400",
|
|
|
|
@errors != [] && "border-rose-400 focus:border-rose-400"
|
|
|
|
]}
|
|
|
|
{@rest}
|
|
|
|
><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea>
|
|
|
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
# All other inputs text, datetime-local, url, password, etc. are handled here...
|
|
|
|
def input(assigns) do
|
|
|
|
~H"""
|
|
|
|
<div class="field" phx-feedback-for={@name}>
|
|
|
|
<.label for={@id}><%= @label %></.label>
|
|
|
|
<input
|
|
|
|
type={@type}
|
|
|
|
name={@name}
|
|
|
|
id={@id}
|
|
|
|
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
|
|
|
class={[
|
|
|
|
"input focus:ring-0",
|
|
|
|
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
|
|
|
|
@errors == [] && "border-zinc-300 focus:border-zinc-400",
|
|
|
|
@errors != [] && "border-rose-400 focus:border-rose-400"
|
|
|
|
]}
|
|
|
|
{@rest}
|
|
|
|
/>
|
|
|
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders section.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the section"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the section"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the section content"
|
|
|
|
|
|
|
|
def section(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("section")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<section {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</section>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders box.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the box"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the box"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the box content"
|
|
|
|
|
|
|
|
def box(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("box")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders container.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the container"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the container"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the container content"
|
|
|
|
|
|
|
|
def container(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("container")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders footer.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the footer"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the footer"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the footer content"
|
|
|
|
|
|
|
|
def footer(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("footer")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<footer {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</footer>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders media object.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the media object"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the media object"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the media object content"
|
|
|
|
|
|
|
|
def media(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("media")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<article {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</article>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders media-left.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the media-left"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the media-left"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the media-left content"
|
|
|
|
|
|
|
|
def media_left(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("media-left")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<figure {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</figure>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders media-content.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the media-content"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the media-content"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the media-content content"
|
|
|
|
|
|
|
|
def media_content(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("media-content")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders media-right.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the media-right"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the media-right"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the media-right content"
|
|
|
|
|
|
|
|
def media_right(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("media-right")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders content.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the content"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the content"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the content"
|
|
|
|
|
|
|
|
def content(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("content")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders a level.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the level"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the level"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the level content"
|
|
|
|
|
|
|
|
def level(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("level")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<nav {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</nav>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders level-left.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the level-left"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the level-left"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the level-left content"
|
|
|
|
|
|
|
|
def level_left(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("level-left")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders level-right.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the level-right"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the level-right"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the level-right content"
|
|
|
|
|
|
|
|
def level_right(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("level-right")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders level-item.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the level-item"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the level-item"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the level-item content"
|
|
|
|
|
|
|
|
def level_item(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("level-item")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders columns.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the columns"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the column"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the columns content"
|
|
|
|
|
|
|
|
def columns(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("columns")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders column.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the column"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the column"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the column content"
|
|
|
|
|
|
|
|
def column(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("column")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders button.
|
|
|
|
"""
|
|
|
|
attr :id, :string, required: false, doc: "the id of the button"
|
|
|
|
attr :type, :string, default: "button", doc: "the type of the button"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the button"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the button content"
|
2024-05-09 22:14:54 +02:00
|
|
|
|
|
|
|
def button(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
2024-05-13 11:21:05 +02:00
|
|
|
|> extend_class("button")
|
|
|
|
|> set_attributes([:type, :id])
|
2024-05-09 22:14:54 +02:00
|
|
|
|> set_phx_attributes()
|
2024-05-13 11:21:05 +02:00
|
|
|
|> set_bulma_classes()
|
2024-05-09 22:14:54 +02:00
|
|
|
|
|
|
|
~H"""
|
2024-05-13 11:21:05 +02:00
|
|
|
<button {@heex_id} {@heex_type} {@heex_phx_attributes} {@heex_class} {@rest}>
|
2024-05-09 22:14:54 +02:00
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</button>
|
|
|
|
"""
|
|
|
|
end
|
2024-05-13 11:21:05 +02:00
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders hero section.
|
|
|
|
"""
|
|
|
|
attr :id, :string, required: false, doc: "the id of the hero section"
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the hero section"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the hero section"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the hero content"
|
|
|
|
|
|
|
|
def hero(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("hero")
|
|
|
|
|> set_attributes([:id])
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<section {@heex_id} {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<div class="hero-body">
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
</section>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders title.
|
|
|
|
"""
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the button"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the title content"
|
|
|
|
|
|
|
|
def title(assigns) do
|
|
|
|
assigns
|
|
|
|
|> extend_class("title")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|> render_bulma_heading()
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders subtitle.
|
|
|
|
"""
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the button"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the subtitle content"
|
|
|
|
|
|
|
|
def subtitle(assigns) do
|
|
|
|
assigns
|
|
|
|
|> extend_class("subtitle")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|> render_bulma_heading()
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar content"
|
|
|
|
|
|
|
|
def navbar(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<nav {@heex_class} {@heex_phx_attributes} {@rest} role="navigation" aria-label="main navigation">
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</nav>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-brand.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-brand"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-brand"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar-brand content"
|
|
|
|
|
|
|
|
def navbar_brand(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-brand")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-menu.
|
|
|
|
"""
|
|
|
|
attr :id, :string, required: true, doc: "the id of the navbar-menu"
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-menu"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-menu"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar-menu content"
|
|
|
|
|
|
|
|
def navbar_menu(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-menu")
|
|
|
|
|> set_attributes([:id])
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_id} {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-start.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-start"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-start"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar-start content"
|
|
|
|
|
|
|
|
def navbar_start(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-start")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-end.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-end"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-end"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar-end content"
|
|
|
|
|
|
|
|
def navbar_end(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-end")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-item.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-item"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-item"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar-item content"
|
|
|
|
|
|
|
|
def navbar_item(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-item")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-dropdown.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-dropdown"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-dropdown"
|
|
|
|
|
|
|
|
slot :inner_block,
|
|
|
|
required: true,
|
|
|
|
doc: "the inner block that renders the navbar-dropdown content"
|
|
|
|
|
|
|
|
def navbar_dropdown(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-dropdown")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-link.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-link"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-link"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the navbar-link content"
|
|
|
|
|
|
|
|
def navbar_link(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-link")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<a {@heex_class} {@heex_phx_attributes} {@rest}>
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</a>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-divider.
|
|
|
|
"""
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-divider"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-divider"
|
|
|
|
|
|
|
|
def navbar_divider(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-divider")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<hr {@heex_class} {@heex_phx_attributes} {@rest} />
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders navbar-burger.
|
|
|
|
"""
|
|
|
|
attr :target, :string, required: true, doc: "the target of the navbar-burger"
|
|
|
|
attr :size, :string, default: "1.6rem", doc: "the size of the navbar-burger"
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the navbar-burger"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the navbar-burger"
|
|
|
|
|
|
|
|
def navbar_burger(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("navbar-burger")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<a
|
|
|
|
role="button"
|
|
|
|
aria-label="menu"
|
|
|
|
aria-expanded="false"
|
|
|
|
data-target={@target}
|
|
|
|
{@heex_class}
|
|
|
|
{@heex_phx_attributes}
|
|
|
|
{@rest}
|
|
|
|
>
|
|
|
|
<Lucideicons.menu height={@size} width={@size} />
|
|
|
|
</a>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders search input.
|
|
|
|
"""
|
|
|
|
attr :id, :string, required: true, doc: "the id of the search input"
|
|
|
|
attr :name, :string, required: true, doc: "the name of the search input"
|
|
|
|
attr :value, :string, default: nil, doc: "the value of the search input"
|
|
|
|
attr :placeholder, :string, default: nil, doc: "the placeholder of the search input"
|
|
|
|
attr :class, :string, default: nil, doc: "the optional class of the search input"
|
|
|
|
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the search input"
|
|
|
|
|
|
|
|
slot :inner_block, required: true, doc: "the inner block that renders the search input content"
|
|
|
|
slot :icon_left, doc: "the slot for the left icon"
|
|
|
|
slot :icon_right, doc: "the slot for the right icon"
|
|
|
|
|
|
|
|
def search_input(assigns) do
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> extend_class("control has-icons-left has-icons-right")
|
|
|
|
|> set_phx_attributes()
|
|
|
|
|> set_bulma_classes()
|
|
|
|
|
|
|
|
~H"""
|
|
|
|
<div {@heex_class} {@rest}>
|
|
|
|
<input
|
|
|
|
id={@id}
|
|
|
|
name={@name}
|
|
|
|
class="input"
|
|
|
|
type="text"
|
|
|
|
value={@value}
|
|
|
|
placeholder={@placeholder}
|
|
|
|
{@heex_phx_attributes}
|
|
|
|
/>
|
|
|
|
<%= if @icon_left != [] do %>
|
|
|
|
<span class="icon is-left">
|
|
|
|
<%= render_slot(@icon_left) %>
|
|
|
|
</span>
|
|
|
|
<% end %>
|
|
|
|
<%= if @icon_right != [] do %>
|
|
|
|
<span class="icon is-right">
|
|
|
|
<%= render_slot(@icon_right) %>
|
|
|
|
</span>
|
|
|
|
<% end %>
|
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
# @doc """
|
|
|
|
# Renders a header with title.
|
|
|
|
# """
|
|
|
|
# attr :class, :string, default: nil
|
|
|
|
|
|
|
|
# slot :inner_block, required: true
|
|
|
|
# slot :subtitle
|
|
|
|
# slot :actions
|
|
|
|
|
|
|
|
# def header(assigns) do
|
|
|
|
# ~H"""
|
|
|
|
# <header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
|
|
|
# <div>
|
|
|
|
# <h1 class="text-lg font-semibold leading-8 text-zinc-800">
|
|
|
|
# <%= render_slot(@inner_block) %>
|
|
|
|
# </h1>
|
|
|
|
# <p :if={@subtitle != []} class="mt-2 text-sm leading-6 text-zinc-600">
|
|
|
|
# <%= render_slot(@subtitle) %>
|
|
|
|
# </p>
|
|
|
|
# </div>
|
|
|
|
# <div class="flex-none"><%= render_slot(@actions) %></div>
|
|
|
|
# </header>
|
|
|
|
# """
|
|
|
|
# end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Generates a generic error message.
|
|
|
|
"""
|
|
|
|
slot :inner_block, required: true
|
|
|
|
|
|
|
|
def error(assigns) do
|
|
|
|
~H"""
|
|
|
|
<p class="mt-3 flex gap-3 text-sm leading-6 text-rose-600 phx-no-feedback:hidden">
|
|
|
|
<%!-- <.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> --%>
|
|
|
|
<Lucideicons.circle_alert class="ison-small flex-none" aria-hidden />
|
|
|
|
<%= render_slot(@inner_block) %>
|
|
|
|
</p>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Renders a simple form.
|
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
|
|
|
<.simple_form for={@form} phx-change="validate" phx-submit="save">
|
|
|
|
<.input field={@form[:email]} label="Email"/>
|
|
|
|
<.input field={@form[:username]} label="Username" />
|
|
|
|
<:actions>
|
|
|
|
<.button>Save</.button>
|
|
|
|
</:actions>
|
|
|
|
</.simple_form>
|
|
|
|
"""
|
|
|
|
attr :for, :any, required: true, doc: "the datastructure for the form"
|
|
|
|
attr :as, :any, default: nil, doc: "the server side parameter to collect all input under"
|
|
|
|
|
|
|
|
attr :rest, :global,
|
|
|
|
include: ~w(autocomplete name rel action enctype method novalidate target multipart),
|
|
|
|
doc: "the arbitrary HTML attributes to apply to the form tag"
|
|
|
|
|
|
|
|
slot :inner_block, required: true
|
|
|
|
slot :actions, doc: "the slot for form actions, such as a submit button"
|
|
|
|
|
|
|
|
def simple_form(assigns) do
|
|
|
|
~H"""
|
|
|
|
<.form :let={f} for={@for} as={@as} {@rest}>
|
|
|
|
<div class="box">
|
|
|
|
<%= render_slot(@inner_block, f) %>
|
|
|
|
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
|
|
|
<%= render_slot(action, f) %>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</.form>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
|
|
|
## Private functions
|
|
|
|
|
|
|
|
defp set_bulma_classes(assigns, opts \\ []) do
|
|
|
|
opts = Keyword.put_new(opts, :from, :rest)
|
|
|
|
|
|
|
|
assigns =
|
|
|
|
assigns
|
|
|
|
|> set_prefixed_attributes(["is-"], Keyword.put_new(opts, :into, :bulma_is))
|
|
|
|
|> set_prefixed_attributes(["has-"], Keyword.put_new(opts, :into, :bulma_has))
|
|
|
|
|> set_prefixed_attributes(["flex-"], Keyword.put_new(opts, :into, :bulma_flex))
|
|
|
|
|> set_prefixed_attributes(["justify-"], Keyword.put_new(opts, :into, :bulma_justify))
|
|
|
|
|> set_prefixed_attributes(["align-"], Keyword.put_new(opts, :into, :bulma_align))
|
|
|
|
|
|
|
|
bulma_classes =
|
|
|
|
[]
|
|
|
|
|> Enum.concat(for({is, _} <- assigns.heex_bulma_is, do: to_string(is)))
|
|
|
|
|> Enum.concat(for({has, _} <- assigns.heex_bulma_has, do: to_string(has)))
|
|
|
|
|> Enum.concat(for({flex, _} <- assigns.heex_bulma_flex, do: to_string(flex)))
|
|
|
|
|> Enum.concat(for({justify, _} <- assigns.heex_bulma_justify, do: to_string(justify)))
|
|
|
|
|> Enum.concat(for({align, _} <- assigns.heex_bulma_align, do: to_string(align)))
|
|
|
|
|
|
|
|
if assigns.heex_class do
|
|
|
|
class =
|
|
|
|
assigns.heex_class[:class]
|
|
|
|
|> String.split(" ")
|
|
|
|
|> Enum.concat(bulma_classes)
|
|
|
|
# todo: where is this coming from?
|
|
|
|
|> Enum.reject(&(&1 == "false"))
|
|
|
|
|> Enum.join(" ")
|
|
|
|
|
|
|
|
assigns |> Map.put(:heex_class, class: class)
|
|
|
|
else
|
|
|
|
assigns |> Map.put(:heex_class, class: bulma_classes |> Enum.join(" "))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
slot :inner_block, required: true
|
|
|
|
|
|
|
|
defp render_bulma_heading(assigns) do
|
|
|
|
level =
|
|
|
|
assigns
|
|
|
|
|> Map.filter(fn assign ->
|
|
|
|
case assign do
|
|
|
|
{:"is-1", _} -> true
|
|
|
|
{:"is-2", _} -> true
|
|
|
|
{:"is-3", _} -> true
|
|
|
|
{:"is-4", _} -> true
|
|
|
|
{:"is-5", _} -> true
|
|
|
|
{:"is-6", _} -> true
|
|
|
|
_ -> false
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|> Map.keys()
|
|
|
|
|> List.first()
|
|
|
|
|> Atom.to_string()
|
|
|
|
|> String.split("-")
|
|
|
|
|> List.last()
|
|
|
|
|
|
|
|
level =
|
|
|
|
case level do
|
|
|
|
# todo: where is this coming from?
|
|
|
|
"nil" -> 3
|
|
|
|
_ -> String.to_integer(level)
|
|
|
|
end
|
|
|
|
|
|
|
|
case level do
|
|
|
|
1 ->
|
|
|
|
~H"<h1 {@heex_class} {@heex_phx_attributes} {@rest}><%= render_slot(@inner_block) %></h1>"
|
|
|
|
|
|
|
|
2 ->
|
|
|
|
~H"<h2 {@heex_class} {@heex_phx_attributes} {@rest}><%= render_slot(@inner_block) %></h2>"
|
|
|
|
|
|
|
|
3 ->
|
|
|
|
~H"<h3 {@heex_class} {@heex_phx_attributes} {@rest}><%= render_slot(@inner_block) %></h3>"
|
|
|
|
|
|
|
|
4 ->
|
|
|
|
~H"<h4 {@heex_class} {@heex_phx_attributes} {@rest}><%= render_slot(@inner_block) %></h4>"
|
|
|
|
|
|
|
|
5 ->
|
|
|
|
~H"<h5 {@heex_class} {@heex_phx_attributes} {@rest}><%= render_slot(@inner_block) %></h5>"
|
|
|
|
|
|
|
|
6 ->
|
|
|
|
~H"<h6 {@heex_class} {@heex_phx_attributes} {@rest}><%= render_slot(@inner_block) %></h6>"
|
|
|
|
end
|
|
|
|
end
|
2024-05-09 22:14:54 +02:00
|
|
|
end
|