Packages
phoenix_kit
1.7.53
1.7.210
1.7.209
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit_web/components/dashboard/badge.ex
defmodule PhoenixKitWeb.Components.Dashboard.Badge do
@moduledoc """
Badge component for dashboard tab indicators.
Renders various badge types with support for:
- Count badges (numeric)
- Dot indicators
- Status badges
- "New" indicators
- Custom text badges
- Pulse and other animations
"""
use Phoenix.Component
alias PhoenixKit.Dashboard.Badge, as: BadgeStruct
@doc """
Renders a dashboard badge.
## Attributes
- `badge` - The Badge struct or nil
- `class` - Additional CSS classes
## Examples
<.dashboard_badge badge={@tab.badge} />
<.dashboard_badge badge={Badge.count(5)} />
"""
attr :badge, :any, default: nil
attr :class, :string, default: ""
def dashboard_badge(assigns) do
~H"""
<%= if @badge && BadgeStruct.visible?(@badge) do %>
<%= case @badge.type do %>
<% :dot -> %>
<.dot_badge badge={@badge} class={@class} />
<% :count -> %>
<.count_badge badge={@badge} class={@class} />
<% :status -> %>
<.status_badge badge={@badge} class={@class} />
<% :new -> %>
<.new_badge badge={@badge} class={@class} />
<% :text -> %>
<.text_badge badge={@badge} class={@class} />
<% :compound -> %>
<.compound_badge badge={@badge} class={@class} />
<% _ -> %>
<.count_badge badge={@badge} class={@class} />
<% end %>
<% end %>
"""
end
@doc """
Renders a count badge with optional max value display.
"""
attr :badge, :any, required: true
attr :class, :string, default: ""
def count_badge(assigns) do
value = BadgeStruct.display_value(assigns.badge)
color_class = BadgeStruct.color_class(assigns.badge)
assigns =
assigns
|> assign(:value, value)
|> assign(:color_class, color_class)
~H"""
<span
class={[
"badge badge-sm",
@color_class,
@badge.pulse && "animate-pulse",
@badge.animate && "transition-all duration-300",
@class
]}
data-badge-id={@badge.metadata[:tab_id]}
data-badge-type="count"
>
{@value}
</span>
"""
end
@doc """
Renders a dot indicator badge.
"""
attr :badge, :any, required: true
attr :class, :string, default: ""
def dot_badge(assigns) do
color_class = BadgeStruct.dot_color_class(assigns.badge)
assigns = assign(assigns, :color_class, color_class)
~H"""
<span
class={[
"w-2.5 h-2.5 rounded-full",
@color_class,
@badge.pulse && "animate-pulse",
@class
]}
data-badge-type="dot"
>
</span>
"""
end
@doc """
Renders a status badge with value and color.
"""
attr :badge, :any, required: true
attr :class, :string, default: ""
def status_badge(assigns) do
value = BadgeStruct.display_value(assigns.badge)
color_class = BadgeStruct.color_class(assigns.badge)
assigns =
assigns
|> assign(:value, value)
|> assign(:color_class, color_class)
~H"""
<span
class={[
"inline-flex items-center gap-1 text-xs font-medium",
@badge.pulse && "animate-pulse",
@class
]}
data-badge-type="status"
>
<span class={["w-2 h-2 rounded-full", BadgeStruct.dot_color_class(@badge)]}></span>
<span class={@color_class |> String.replace("badge-", "text-")}>
{String.capitalize(to_string(@value))}
</span>
</span>
"""
end
@doc """
Renders a "New" indicator badge.
"""
attr :badge, :any, required: true
attr :class, :string, default: ""
def new_badge(assigns) do
color_class = BadgeStruct.color_class(assigns.badge)
assigns = assign(assigns, :color_class, color_class)
~H"""
<span
class={[
"badge badge-sm",
@color_class,
@badge.pulse && "animate-pulse",
@class
]}
data-badge-type="new"
>
New
</span>
"""
end
@doc """
Renders a custom text badge.
"""
attr :badge, :any, required: true
attr :class, :string, default: ""
def text_badge(assigns) do
value = BadgeStruct.display_value(assigns.badge)
color_class = BadgeStruct.color_class(assigns.badge)
assigns =
assigns
|> assign(:value, value)
|> assign(:color_class, color_class)
~H"""
<span
class={[
"badge badge-sm",
@color_class,
@badge.pulse && "animate-pulse",
@class
]}
data-badge-type="text"
>
{@value}
</span>
"""
end
@doc """
Renders a compound badge with multiple colored segments.
Supports three styles:
- `:text` - Colored text values with separator (default)
- `:blocks` - Colored background pills side by side
- `:dots` - Colored dots with numbers
"""
attr :badge, :any, required: true
attr :class, :string, default: ""
def compound_badge(assigns) do
segments = BadgeStruct.visible_segments(assigns.badge)
style = assigns.badge.compound_style || :text
separator = assigns.badge.separator || "/"
assigns =
assigns
|> assign(:segments, segments)
|> assign(:style, style)
|> assign(:separator, separator)
~H"""
<span
class={[
"inline-flex items-center gap-1",
@badge.pulse && "animate-pulse",
@class
]}
data-badge-type="compound"
data-badge-style={@style}
>
<%= case @style do %>
<% :text -> %>
<.compound_text_style segments={@segments} separator={@separator} />
<% :blocks -> %>
<.compound_blocks_style segments={@segments} />
<% :dots -> %>
<.compound_dots_style segments={@segments} />
<% _ -> %>
<.compound_text_style segments={@segments} separator={@separator} />
<% end %>
</span>
"""
end
# Text style: "10 / 5 / 2" with colored text
defp compound_text_style(assigns) do
~H"""
<%= for {segment, index} <- Enum.with_index(@segments) do %>
<%= if index > 0 do %>
<span class="text-base-content/40 text-xs">{@separator}</span>
<% end %>
<span class={["text-xs font-medium", text_color_class(segment[:color] || segment["color"])]}>
{segment[:value] || segment["value"]}
<%= if segment[:label] || segment["label"] do %>
<span class="opacity-70 ml-0.5">{segment[:label] || segment["label"]}</span>
<% end %>
</span>
<% end %>
"""
end
# Blocks style: colored background pills
defp compound_blocks_style(assigns) do
~H"""
<span class="inline-flex items-center rounded-lg overflow-hidden">
<%= for segment <- @segments do %>
<span class={[
"px-1.5 py-0.5 text-xs font-medium",
block_color_class(segment[:color] || segment["color"])
]}>
{segment[:value] || segment["value"]}
</span>
<% end %>
</span>
"""
end
# Dots style: colored dots with numbers
defp compound_dots_style(assigns) do
~H"""
<%= for segment <- @segments do %>
<span class="inline-flex items-center gap-0.5">
<span class={[
"w-2 h-2 rounded-full",
dot_color_class_for_segment(segment[:color] || segment["color"])
]}>
</span>
<span class="text-xs text-base-content/70">
{segment[:value] || segment["value"]}
</span>
</span>
<% end %>
"""
end
# Text color classes for compound badge text style
defp text_color_class(:primary), do: "text-primary"
defp text_color_class(:secondary), do: "text-secondary"
defp text_color_class(:accent), do: "text-accent"
defp text_color_class(:info), do: "text-info"
defp text_color_class(:success), do: "text-success"
defp text_color_class(:warning), do: "text-warning"
defp text_color_class(:error), do: "text-error"
defp text_color_class(:neutral), do: "text-neutral"
defp text_color_class(:base), do: "text-base-content"
defp text_color_class("primary"), do: "text-primary"
defp text_color_class("secondary"), do: "text-secondary"
defp text_color_class("accent"), do: "text-accent"
defp text_color_class("info"), do: "text-info"
defp text_color_class("success"), do: "text-success"
defp text_color_class("warning"), do: "text-warning"
defp text_color_class("error"), do: "text-error"
defp text_color_class("neutral"), do: "text-neutral"
defp text_color_class("base"), do: "text-base-content"
defp text_color_class(_), do: "text-base-content"
# Block color classes (background + text) for compound badge blocks style
defp block_color_class(:primary), do: "bg-primary text-primary-content"
defp block_color_class(:secondary), do: "bg-secondary text-secondary-content"
defp block_color_class(:accent), do: "bg-accent text-accent-content"
defp block_color_class(:info), do: "bg-info text-info-content"
defp block_color_class(:success), do: "bg-success text-success-content"
defp block_color_class(:warning), do: "bg-warning text-warning-content"
defp block_color_class(:error), do: "bg-error text-error-content"
defp block_color_class(:neutral), do: "bg-neutral text-neutral-content"
defp block_color_class(:base), do: "bg-base-300 text-base-content"
defp block_color_class("primary"), do: "bg-primary text-primary-content"
defp block_color_class("secondary"), do: "bg-secondary text-secondary-content"
defp block_color_class("accent"), do: "bg-accent text-accent-content"
defp block_color_class("info"), do: "bg-info text-info-content"
defp block_color_class("success"), do: "bg-success text-success-content"
defp block_color_class("warning"), do: "bg-warning text-warning-content"
defp block_color_class("error"), do: "bg-error text-error-content"
defp block_color_class("neutral"), do: "bg-neutral text-neutral-content"
defp block_color_class("base"), do: "bg-base-300 text-base-content"
defp block_color_class(_), do: "bg-base-300 text-base-content"
# Dot color classes for compound badge dots style
defp dot_color_class_for_segment(:primary), do: "bg-primary"
defp dot_color_class_for_segment(:secondary), do: "bg-secondary"
defp dot_color_class_for_segment(:accent), do: "bg-accent"
defp dot_color_class_for_segment(:info), do: "bg-info"
defp dot_color_class_for_segment(:success), do: "bg-success"
defp dot_color_class_for_segment(:warning), do: "bg-warning"
defp dot_color_class_for_segment(:error), do: "bg-error"
defp dot_color_class_for_segment(:neutral), do: "bg-neutral"
defp dot_color_class_for_segment(:base), do: "bg-base-300"
defp dot_color_class_for_segment("primary"), do: "bg-primary"
defp dot_color_class_for_segment("secondary"), do: "bg-secondary"
defp dot_color_class_for_segment("accent"), do: "bg-accent"
defp dot_color_class_for_segment("info"), do: "bg-info"
defp dot_color_class_for_segment("success"), do: "bg-success"
defp dot_color_class_for_segment("warning"), do: "bg-warning"
defp dot_color_class_for_segment("error"), do: "bg-error"
defp dot_color_class_for_segment("neutral"), do: "bg-neutral"
defp dot_color_class_for_segment("base"), do: "bg-base-300"
defp dot_color_class_for_segment(_), do: "bg-base-300"
@doc """
Renders a presence indicator showing user count.
"""
attr :count, :integer, default: 0
attr :show_text, :boolean, default: false
attr :class, :string, default: ""
def presence_indicator(assigns) do
~H"""
<%= if @count > 0 do %>
<span
class={[
"inline-flex items-center gap-1 text-xs text-base-content/60",
@class
]}
title={"#{@count} #{if @count == 1, do: "user", else: "users"} viewing"}
>
<span class="w-1.5 h-1.5 rounded-full bg-success animate-pulse"></span>
<%= if @show_text do %>
<span>{@count}</span>
<% end %>
</span>
<% end %>
"""
end
end