defmodule PlausibleWeb.Components.Generic do @moduledoc """ Generic reusable components """ use Phoenix.Component, global_prefixes: ~w(x-) @notice_themes %{ yellow: %{ bg: "bg-yellow-50 dark:bg-yellow-100", icon: "text-yellow-400", title_text: "text-yellow-800 dark:text-yellow-900", body_text: "text-yellow-700 dark:text-yellow-800" }, red: %{ bg: "bg-red-100", icon: "text-red-700", title_text: "text-red-800 dark:text-red-900", body_text: "text-red-700 dark:text-red-800" } } @button_themes %{ "primary" => "bg-indigo-600 text-white hover:bg-indigo-700 focus-visible:outline-indigo-600", "bright" => "border border-gray-200 bg-gray-100 dark:bg-gray-300 text-gray-800 hover:bg-gray-200 focus-visible:outline-gray-100", "danger" => "border border-gray-300 dark:border-gray-500 text-red-700 bg-white dark:bg-gray-800 hover:text-red-500 dark:hover:text-red-400 focus:border-blue-300 active:text-red-800" } @button_base_class "inline-flex items-center justify-center gap-x-2 rounded-md px-3.5 py-2.5 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:bg-gray-400 dark:disabled:text-white dark:disabled:text-gray-400 dark:disabled:bg-gray-700" attr(:type, :string, default: "button") attr(:theme, :string, default: "primary") attr(:class, :string, default: "") attr(:disabled, :boolean, default: false) attr(:rest, :global) slot(:inner_block) def button(assigns) do assigns = assign(assigns, button_base_class: @button_base_class, theme_class: @button_themes[assigns.theme] ) ~H""" """ end attr(:href, :string, required: true) attr(:class, :string, default: "") attr(:theme, :string, default: "primary") attr(:disabled, :boolean, default: false) attr(:rest, :global) slot(:inner_block) def button_link(assigns) do theme_class = if assigns.disabled do "bg-gray-400 text-white dark:text-white dark:text-gray-400 dark:bg-gray-700 cursor-not-allowed" else @button_themes[assigns.theme] end onclick = if assigns.disabled do "return false;" else assigns[:onclick] end assigns = assign(assigns, onclick: onclick, button_base_class: @button_base_class, theme_class: theme_class ) ~H""" <.link href={@href} onclick={@onclick} class={[ @button_base_class, @theme_class, @class ]} {@rest} > <%= render_slot(@inner_block) %> """ end attr(:slug, :string, required: true) def docs_info(assigns) do ~H""" """ end attr(:title, :any, default: nil) attr(:size, :atom, default: :sm) attr(:theme, :atom, default: :yellow) attr(:dismissable_id, :any, default: nil) attr(:class, :string, default: "") attr(:rest, :global) slot(:inner_block) def notice(assigns) do assigns = assign(assigns, :theme, Map.fetch!(@notice_themes, assigns.theme)) ~H"""

<%= @title %>

<%= render_slot(@inner_block) %>

""" end attr :id, :any, default: nil attr :href, :string, default: "#" attr :new_tab, :boolean, default: false attr :class, :string, default: "" attr :rest, :global slot :inner_block def styled_link(assigns) do ~H""" <.unstyled_link new_tab={@new_tab} href={@href} class={"text-indigo-600 hover:text-indigo-700 dark:text-indigo-500 dark:hover:text-indigo-600 " <> @class} {@rest} > <%= render_slot(@inner_block) %> """ end slot :button, required: true do attr :class, :string end slot :panel, required: true do attr :class, :string end def dropdown(assigns) do ~H"""
""" end attr :href, :string, required: true attr :new_tab, :boolean, default: false attr :rest, :global slot :inner_block, required: true def dropdown_link(assigns) do class = "w-full inline-flex text-gray-700 dark:text-gray-300 px-3.5 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-100" class = if assigns.new_tab do "#{class} justify-between" else class end assigns = assign(assigns, :class, class) ~H""" <.unstyled_link new_tab={@new_tab} href={@href} x-on:click="close()" class={@class} {@rest}> <%= render_slot(@inner_block) %> """ end attr :href, :string, required: true attr :new_tab, :boolean, default: false attr :class, :string, default: "" attr :id, :any, default: nil attr :rest, :global slot :inner_block def unstyled_link(assigns) do if assigns[:new_tab] do assigns = assign(assigns, :icon_class, icon_class(assigns)) ~H""" <.link id={@id} class={[ "inline-flex items-center gap-x-0.5", @class ]} href={@href} target="_blank" rel="noopener noreferrer" {@rest} > <%= render_slot(@inner_block) %> """ else ~H""" <.link class={@class} href={@href} {@rest}> <%= render_slot(@inner_block) %> """ end end attr :class, :any, default: "" attr :rest, :global def spinner(assigns) do ~H""" """ end attr :wrapper_class, :any, default: "" attr :class, :any, default: "" slot :inner_block, required: true slot :tooltip_content, required: true def tooltip(assigns) do ~H"""

<%= render_slot(@inner_block) %>

<%= render_slot(List.first(@tooltip_content)) %>
""" end attr :rest, :global, include: ~w(fill stroke stroke-width) attr :name, :atom, required: true attr :outline, :boolean, default: true attr :solid, :boolean, default: false attr :mini, :boolean, default: false def dynamic_icon(assigns) do apply(Heroicons, assigns.name, [assigns]) end attr :width, :integer, default: 100 attr :height, :integer, default: 100 attr :id, :string, default: "shuttle" def shuttle(assigns) do ~H""" """ end defp icon_class(link_assigns) do if String.contains?(link_assigns[:class], "text-sm") or String.contains?(link_assigns[:class], "text-xs") do ["w-3 h-3"] else ["w-4 h-4"] end end end