defmodule CanneryWeb.CoreComponents do @moduledoc """ Provides core UI components. """ use Phoenix.Component import CanneryWeb.{Gettext, ViewHelpers} alias Cannery.{Accounts, Ammo, Ammo.AmmoGroup} alias Cannery.Accounts.{Invite, Invites, User} alias Cannery.{Containers, Containers.Container, Tags.Tag} alias CanneryWeb.{Endpoint, HomeLive} alias CanneryWeb.Router.Helpers, as: Routes alias Phoenix.LiveView.{JS, Rendered} embed_templates "core_components/*" attr :title_content, :string, default: nil attr :current_user, User, default: nil def topbar(assigns) attr :return_to, :string, required: true slot(:inner_block) @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(Endpoint, :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(Endpoint, :index)} <%= schema.singular %>: @<%= schema.singular %> /> """ def modal(assigns) defp hide_modal(js \\ %JS{}) do js |> JS.hide(to: "#modal", transition: "fade-out") |> JS.hide(to: "#modal-bg", transition: "fade-out") |> JS.hide(to: "#modal-content", transition: "fade-out-scale") end attr :action, :string, required: true attr :value, :boolean, required: true attr :id, :string, default: nil slot(:inner_block) @doc """ A toggle button element that can be directed to a liveview or a live_component's `handle_event/3`. ## Examples <.toggle_button action="my_liveview_action" value={@some_value}> Toggle me! <.toggle_button action="my_live_component_action" target={@myself} value={@some_value}> Whatever you want """ def toggle_button(assigns) attr :container, Container, required: true slot(:tag_actions) slot(:inner_block) @spec container_card(assigns :: map()) :: Rendered.t() def container_card(assigns) attr :tag, Tag, required: true slot(:inner_block, required: true) def tag_card(assigns) attr :tag, Tag, required: true def simple_tag_card(assigns) attr :ammo_group, AmmoGroup, required: true attr :show_container, :boolean, default: false slot(:inner_block) def ammo_group_card(assigns) attr :user, User, required: true slot(:inner_block, required: true) def user_card(assigns) attr :invite, Invite, required: true attr :current_user, User, required: true slot(:inner_block) slot(:code_actions) def invite_card(%{invite: invite, current_user: current_user} = assigns) do assigns = assigns |> assign(:use_count, Invites.get_use_count(invite, current_user)) ~H"""

<%= @invite.name %>

<%= if @invite.disabled_at |> is_nil() do %>

<%= if @invite.uses_left do %> <%= gettext( "Uses Left: %{uses_left_count}", uses_left_count: @invite.uses_left ) %> <% else %> <%= gettext("Uses Left: Unlimited") %> <% end %>

<% else %>

<%= gettext("Invite Disabled") %>

<% end %> <.qr_code content={Routes.user_registration_url(Endpoint, :new, invite: @invite.token)} filename={@invite.name} />

<%= gettext("Uses: %{uses_count}", uses_count: @use_count) %>

<%= Routes.user_registration_url(Endpoint, :new, invite: @invite.token) %> <%= if @code_actions, do: render_slot(@code_actions) %>
<%= render_slot(@inner_block) %>
""" end attr :content, :string, required: true attr :filename, :string, default: "qrcode", doc: "filename without .png extension" attr :image_class, :string, default: "w-64 h-max" attr :width, :integer, default: 384, doc: "width of png to generate" @doc """ Creates a downloadable QR Code element """ def qr_code(assigns) attr :date, :any, required: true, doc: "A `Date` struct or nil" @doc """ Phoenix.Component for a element that renders the Date in the user's local timezone with Alpine.js """ def date(assigns) attr :datetime, :any, required: true, doc: "A `DateTime` struct or nil" @doc """ Phoenix.Component for a