2.7 KiB · text History 6280797
defmodule GitGudWeb.SymsComponent do
@moduledoc """
The syms dropdown that sits beside the Fork button.
A `live_component` rather than a function component because it handles
its own clicks: the repo header renders on ~30 different LiveViews and
none of them should need a `toggle_sym` clause.
Collapsed it shows the instance's first symbol; opening it lists the
rest with counts. Renders nothing at all when no symbols are
configured.
"""
use GitGudWeb, :live_component
alias GitGud.Syms
@impl true
def update(assigns, socket) do
viewer = assigns[:current_scope] && assigns.current_scope.user
{:ok,
socket
|> assign(assigns)
|> assign(:viewer, viewer)
|> load(assigns.repo, viewer)}
end
defp load(socket, repo, viewer) do
socket
|> assign(:symbols, Syms.symbols())
|> assign(:counts, Syms.counts(repo))
|> assign(:mine, Syms.marks(viewer, repo))
end
@impl true
def handle_event("toggle_sym", %{"sym" => sym}, socket) do
case socket.assigns.viewer do
nil ->
{:noreply, socket}
user ->
_ = Syms.toggle(user, socket.assigns.repo, sym)
{:noreply, load(socket, socket.assigns.repo, user)}
end
end
@impl true
def render(assigns) do
~H"""
<div>
<div :if={@symbols != []} class="dropdown dropdown-end">
<div
tabindex="0"
role="button"
class="btn btn-sm gap-1"
aria-label="Mark this repository"
title="Mark this repository"
>
<span class="text-base leading-none">{hd(@symbols)}</span>
<span :if={total(@counts) > 0} class="opacity-70">{total(@counts)}</span>
<.icon name="hero-chevron-down" class="size-3 opacity-60" />
</div>
<div
tabindex="0"
class="dropdown-content z-10 mt-1 w-56 p-2 shadow-lg bg-base-200 border border-base-300 rounded-box space-y-1"
>
<button
:for={sym <- @symbols}
type="button"
phx-click="toggle_sym"
phx-value-sym={sym}
phx-target={@myself}
disabled={is_nil(@viewer)}
aria-pressed={to_string(sym in @mine)}
class={[
"btn btn-xs btn-block justify-between",
sym in @mine && "btn-primary"
]}
>
<span class="text-base leading-none">{sym}</span>
<span class="opacity-70">{Map.get(@counts, sym, 0)}</span>
</button>
<p :if={is_nil(@viewer)} class="text-xs opacity-60 px-1 pt-1">
Log in to mark this repository.
</p>
</div>
</div>
</div>
"""
end
defp total(counts), do: counts |> Map.values() |> Enum.sum()
end