defmodule FlintUI.Badge do @moduledoc false use FlintUI.Component # -------------------------------------- # Badge # -------------------------------------- @doc """ Renders a badge component. A badge (also known as badge or badge) are used to display small bits of information (e.g. unread counts, status, etc). ## Examples <.badge>Badge <.badge size={:sm}>Badge <.badge variant={:outline}>Badge <.badge radius={:full}>Badge <.badge label="Badge" /> """ FlintAttr.size() FlintAttr.color() FlintAttr.radius() attr(:variant, :atom, values: ~w(subtle light outline dashed solid dot)a, default: theme(:badge).default.variant, doc: "The badge variant/style." ) attr(:uppercase, :boolean, default: false, doc: "Whether to render the badge text in uppercase." ) attr(:label, :string, default: nil, doc: "The label of the badge, rendered if no inner block is provided." ) attr(:show_remove_button, :boolean, default: false, doc: "Wether to render a remove button." ) attr(:on_remove, JS, default: %JS{}, doc: "The remove button on `phx-click` event handler." ) attr(:class, :string, default: nil, doc: "The class of the badge." ) attr(:rest, :global) slot(:inner_block, doc: "The inner block of the badge. If no content is provided, the value of the attr `label` is used instead." ) slot :left_addon, doc: "Render and addon (icon, etc.) in the left side of the badge content." do attr(:class, :any) end slot :right_addon, doc: "Render and addon (icon, etc.) in the right side of the badge content." do attr(:class, :any) end def badge(assigns) do assigns = assigns |> assign_classes() ~H"""
<%= render_slot(@left_addon) %> <%= render_slot(@inner_block) || @label %> <%= render_slot(@right_addon) %> <.badge_button on_remove={@on_remove} />
""" end defp assign_classes(assigns) do classes = badge_classes(assigns) assigns |> assign(:root_class, classes.root) |> assign(:inner_class, classes.inner) |> assign(:left_addon_class, classes.left_addon) |> assign(:right_addon_class, classes.right_addon) end # -------------------------------------- # Badge button # -------------------------------------- @doc """ Renders a badge button component. By default it shows a remove icon (x). """ FlintAttr.color(name: :badge_button) FlintAttr.size(name: :badge_button) attr(:variant, :atom, values: ~w(subtle light outline dashed solid dot gradient)a, default: theme(:badge).default.variant, doc: "The badge button variant/style." ) attr(:on_remove, JS, default: %JS{}, doc: "The on `phx-click` event handler." ) attr(:class, :string, default: nil, doc: "The class of the badge button." ) attr(:badge_radius, :atom, values: radius_variants(), default: :full, doc: "The radius of the badge to calculate radius to use on the button. Defaults to `:full`." ) attr(:sr_label, :string, default: "Remove", doc: "The screen reader label of the badge button." ) attr(:rest, :global) slot(:inner_block, doc: "The inner block of the button. If no content is provided, the default icon is used." ) def badge_button(assigns) do classes = badge_button_classes(assigns) assigns = assigns |> assign(:root_class, classes.root) |> assign(:overlay_class, classes.overlay) |> assign_badge_button_radius() ~H""" """ end # TODO: Adjust colors/style size, etc. to match the badge variant defp button_default_icon(assigns) do ~H""" """ end # The radius of the inner element should follow the rule: # outer_radius = inner_radius + distance_between_elements defp assign_badge_button_radius(assigns) do # radius = assigns.badge_radius assigns end # -------------------------------------- # Badge status dot # -------------------------------------- # TODO: badge status dot @doc """ Renders a badge status dot component. """ def badge_status_dot(assigns) do ~H"""
""" end # -------------------------------------- # Styles # -------------------------------------- def badge_classes(%{size: size, radius: radius, variant: variant, color: color} = assigns) do classes = theme(:badge) root = cx([ classes.base.root, classes.base.font, assigns.uppercase && "uppercase", classes.base.size[size], classes.base.radius[radius], classes.variants[variant][color], assigns.class ]) # TODO: Adjust margin to size left_addon = cx([ classes.base.addon, case size do :xs -> "-ml-1" :sm -> "-ml-1" :md -> "-ml-1" :lg -> "-ml-1" :xl -> "-ml-1" end ]) # TODO: Adjust margin to size right_addon = cx([ classes.base.addon, case size do :xs -> "-mr-1" :sm -> "-mr-1" :md -> "-mr-1" :lg -> "-mr-1" :xl -> "-mr-1" end ]) %{ root: root, inner: classes.base.inner, addon: classes.base.addon, left_addon: left_addon, right_addon: right_addon } end defp badge_button_classes( %{size: size, badge_radius: badge_radius, variant: variant, color: color} = assigns ) do root = cx([ "fl-badge-button group relative", "h-3.5 w-3.5", "rounded-full", "hover:bg-green-600/20" ]) overlay = cx([ "absolute", case size do :xs -> "-inset-0.5" :sm -> "-inset-0.5" :md -> "-inset-0.5" :lg -> "-inset-1" :xl -> "-inset-1" end ]) %{root: root, overlay: overlay} end end