updates
All checks were successful
Build and Deploy / Build & Push Image (push) Successful in 34s

This commit is contained in:
2026-03-25 21:17:21 -06:00
parent 694a10bdbe
commit 8a3b5fd14f
2 changed files with 65 additions and 208 deletions

View File

@@ -27,8 +27,7 @@ defmodule CobblemonUiWeb.DashboardLive do
species_info: %{}, species_info: %{},
view_mode: :party, view_mode: :party,
loading: false, loading: false,
error: nil, error: nil
selected_type: nil
)} )}
end end
@@ -101,14 +100,6 @@ defmodule CobblemonUiWeb.DashboardLive do
{:noreply, assign(socket, view_mode: String.to_existing_atom(mode), selected_pokemon: nil)} {:noreply, assign(socket, view_mode: String.to_existing_atom(mode), selected_pokemon: nil)}
end end
def handle_event("select_type", %{"type" => ""}, socket) do
{:noreply, assign(socket, selected_type: nil)}
end
def handle_event("select_type", %{"type" => type}, socket) do
{:noreply, assign(socket, selected_type: type)}
end
@impl true @impl true
def handle_info(:tick, socket) do def handle_info(:tick, socket) do
{:noreply, do_refresh(socket)} {:noreply, do_refresh(socket)}
@@ -326,7 +317,7 @@ defmodule CobblemonUiWeb.DashboardLive do
/> />
<%!-- Type Chart --%> <%!-- Type Chart --%>
<.type_chart selected_type={@selected_type} /> <.type_chart />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -355,14 +355,11 @@ defmodule CobblemonUiWeb.PokemonComponents do
alias CobblemonUi.TypeChart alias CobblemonUi.TypeChart
attr :selected_type, :string, default: nil
def type_chart(assigns) do def type_chart(assigns) do
chart = TypeChart.defensive_chart() chart = TypeChart.defensive_chart()
offense = TypeChart.offensive_chart()
types = TypeChart.types() types = TypeChart.types()
assigns = assign(assigns, chart: chart, offense: offense, types: types) assigns = assign(assigns, chart: chart, types: types)
~H""" ~H"""
<div class="mt-8 rounded-xl border border-base-300/40 bg-base-200/30 overflow-hidden"> <div class="mt-8 rounded-xl border border-base-300/40 bg-base-200/30 overflow-hidden">
@@ -372,215 +369,84 @@ defmodule CobblemonUiWeb.PokemonComponents do
</div> </div>
<div> <div>
<h3 class="font-bold text-base-content text-lg">Type Chart</h3> <h3 class="font-bold text-base-content text-lg">Type Chart</h3>
<p class="text-xs text-base-content/40"> <p class="text-xs text-base-content/40">Weaknesses & Resistances</p>
Tap a type to see its matchups
</p>
</div> </div>
</div> </div>
<%!-- Type picker grid --%> <div class="p-4 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
<div class="px-5 pt-4 pb-2"> <.type_chart_card :for={t <- @types} type_name={t} matchups={@chart[t]} />
<div class="flex flex-wrap gap-1.5">
<button
:for={t <- @types}
phx-click="select_type"
phx-value-type={t}
class={[
"inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-semibold capitalize transition-all duration-150 border cursor-pointer",
if(@selected_type == t,
do: "ring-2 ring-primary/60 border-primary/40 bg-base-100 shadow-md scale-105",
else:
"border-base-300/30 bg-base-200/40 hover:bg-base-200/70 hover:border-base-300/50 hover:shadow-sm"
)
]}
>
<span class={[
"inline-flex items-center justify-center w-5 h-5 rounded-full shrink-0 p-0.5",
TypeChart.type_color(t)
]}>
<img src={TypeChart.type_icon_path(t)} alt={t} class="w-3.5 h-3.5" />
</span>
{t}
</button>
</div> </div>
</div> </div>
"""
end
<%!-- Selected type detail --%> attr :type_name, :string, required: true
<%= if @selected_type do %> attr :matchups, :map, required: true
<div class="px-5 py-4 animate-in fade-in duration-200">
<div class="flex items-center gap-3 mb-5"> def type_chart_card(assigns) do
~H"""
<div class="flex items-start gap-3 rounded-xl bg-base-200/40 border border-base-300/20 px-3.5 py-3 hover:bg-base-200/60 transition-colors">
<%!-- Type icon circle --%>
<div class={[ <div class={[
"w-12 h-12 rounded-xl flex items-center justify-center shrink-0 shadow-sm", "w-11 h-11 rounded-full flex items-center justify-center shrink-0 shadow-sm mt-0.5",
TypeChart.type_color(@selected_type) TypeChart.type_color(@type_name)
]}> ]}>
<img <img src={TypeChart.type_icon_path(@type_name)} alt={@type_name} class="w-6 h-6" />
src={TypeChart.type_icon_path(@selected_type)}
alt={@selected_type}
class="w-7 h-7 drop-shadow"
/>
</div> </div>
<div> <%!-- Weakness / Resistance rows --%>
<h4 class="font-bold text-base-content capitalize text-xl">{@selected_type}</h4> <div class="flex-1 min-w-0">
<p class="text-xs text-base-content/40">Defensive & Offensive matchups</p> <p class="text-xs font-bold text-base-content/80 capitalize mb-1.5">{@type_name}</p>
</div> <%!-- Weakness row --%>
<button <div class="flex items-center gap-1.5 mb-1">
phx-click="select_type" <span class="text-[9px] text-error/70 font-semibold uppercase tracking-wider w-[52px] shrink-0">
phx-value-type="" Weak
class="ml-auto btn btn-ghost btn-sm btn-circle hover:bg-base-300/50" </span>
> <div class="flex flex-wrap gap-0.5">
<.icon name="hero-x-mark" class="size-4" /> <.type_mini_icon :for={t <- @matchups.weak_to} type_name={t} />
</button> <span :if={@matchups.weak_to == []} class="text-[9px] text-base-content/20 italic">
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
<%!-- Defensive --%>
<div class="space-y-4">
<h5 class="text-xs font-semibold text-base-content/40 uppercase tracking-wider flex items-center gap-1.5">
<.icon name="hero-shield-check" class="size-3.5" /> Defensive
</h5>
<%!-- Weak to --%>
<div>
<p class="text-[11px] text-error/80 font-semibold uppercase tracking-wider mb-1.5 flex items-center gap-1">
<.icon name="hero-exclamation-triangle" class="size-3" /> Weak to (2×)
</p>
<div class="flex flex-wrap gap-1.5">
<.type_pill
:for={t <- @chart[@selected_type].weak_to}
type_name={t}
/>
<span
:if={@chart[@selected_type].weak_to == []}
class="text-xs text-base-content/25 italic"
>
None
</span> </span>
</div> </div>
</div> </div>
<%!-- Resistance row --%>
<%!-- Resists --%> <div class="flex items-center gap-1.5 mb-1">
<div> <span class="text-[9px] text-success/70 font-semibold uppercase tracking-wider w-[52px] shrink-0">
<p class="text-[11px] text-success/80 font-semibold uppercase tracking-wider mb-1.5 flex items-center gap-1"> Resist
<.icon name="hero-shield-check" class="size-3" /> Resists (½×) </span>
</p> <div class="flex flex-wrap gap-0.5">
<div class="flex flex-wrap gap-1.5"> <.type_mini_icon :for={t <- @matchups.resists} type_name={t} />
<.type_pill <span :if={@matchups.resists == []} class="text-[9px] text-base-content/20 italic">
:for={t <- @chart[@selected_type].resists}
type_name={t}
/>
<span
:if={@chart[@selected_type].resists == []}
class="text-xs text-base-content/25 italic"
>
None
</span> </span>
</div> </div>
</div> </div>
<%!-- Immune row (only if applicable) --%>
<%!-- Immune to --%> <div :if={@matchups.immune_to != []} class="flex items-center gap-1.5">
<div :if={@chart[@selected_type].immune_to != []}> <span class="text-[9px] text-info/70 font-semibold uppercase tracking-wider w-[52px] shrink-0">
<p class="text-[11px] text-info/80 font-semibold uppercase tracking-wider mb-1.5 flex items-center gap-1"> Immune
<.icon name="hero-no-symbol" class="size-3" /> Immune to (0×)
</p>
<div class="flex flex-wrap gap-1.5">
<.type_pill
:for={t <- @chart[@selected_type].immune_to}
type_name={t}
/>
</div>
</div>
</div>
<%!-- Offensive --%>
<div class="space-y-4">
<h5 class="text-xs font-semibold text-base-content/40 uppercase tracking-wider flex items-center gap-1.5">
<.icon name="hero-bolt" class="size-3.5" /> Offensive
</h5>
<%!-- Super effective --%>
<div>
<p class="text-[11px] text-error/80 font-semibold uppercase tracking-wider mb-1.5 flex items-center gap-1">
<.icon name="hero-bolt" class="size-3" /> Super effective (2×)
</p>
<div class="flex flex-wrap gap-1.5">
<.type_pill
:for={t <- @offense[@selected_type].strong_against}
type_name={t}
/>
<span
:if={@offense[@selected_type].strong_against == []}
class="text-xs text-base-content/25 italic"
>
None
</span> </span>
</div> <div class="flex flex-wrap gap-0.5">
</div> <.type_mini_icon :for={t <- @matchups.immune_to} type_name={t} />
<%!-- Not very effective --%>
<div>
<p class="text-[11px] text-warning/80 font-semibold uppercase tracking-wider mb-1.5 flex items-center gap-1">
<.icon name="hero-shield-exclamation" class="size-3" /> Not very effective (½×)
</p>
<div class="flex flex-wrap gap-1.5">
<.type_pill
:for={t <- @offense[@selected_type].not_effective}
type_name={t}
/>
<span
:if={@offense[@selected_type].not_effective == []}
class="text-xs text-base-content/25 italic"
>
None
</span>
</div>
</div>
<%!-- No effect --%>
<div :if={@offense[@selected_type].no_effect != []}>
<p class="text-[11px] text-base-content/40 font-semibold uppercase tracking-wider mb-1.5 flex items-center gap-1">
<.icon name="hero-no-symbol" class="size-3" /> No effect (0×)
</p>
<div class="flex flex-wrap gap-1.5">
<.type_pill
:for={t <- @offense[@selected_type].no_effect}
type_name={t}
/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<% else %>
<%!-- Compact overview when no type selected --%>
<div class="px-5 pb-4">
<p class="text-xs text-base-content/30 italic">Select a type above to view matchups</p>
</div>
<% end %>
</div>
""" """
end end
attr :type_name, :string, required: true attr :type_name, :string, required: true
def type_pill(assigns) do def type_mini_icon(assigns) do
~H""" ~H"""
<button <span
phx-click="select_type"
phx-value-type={@type_name}
class={[ class={[
"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-semibold capitalize", "inline-flex items-center justify-center w-5 h-5 rounded-full shadow-sm",
"border transition-all duration-150 cursor-pointer hover:scale-105 hover:shadow-sm", TypeChart.type_color(@type_name)
TypeChart.type_color(@type_name),
"text-white border-white/10"
]} ]}
title={@type_name}
> >
<img <img src={TypeChart.type_icon_path(@type_name)} alt={@type_name} class="w-3 h-3" />
src={TypeChart.type_icon_path(@type_name)} </span>
alt={@type_name}
class="w-3.5 h-3.5 drop-shadow"
/>
{@type_name}
</button>
""" """
end end