2.9 KiB · text 5af55d9
defmodule GitGudWeb.PinnedReposGrid do
@moduledoc """
Renders a row of pinned-repo cards on a user or org profile.
Cards are CSS-grid columns that wrap on narrow screens; each card
shows the repo path, description, and the top language (if any
language stats have been computed). The handle is needed for the
link URL because the repository row alone doesn't carry namespace.
"""
use Phoenix.Component
use Phoenix.VerifiedRoutes,
endpoint: GitGudWeb.Endpoint,
router: GitGudWeb.Router
alias GitGud.LanguageColors
alias GitGud.Repositories
alias GitGud.Repositories.Storage
attr :pins, :list, required: true, doc: "List of `%GitGud.Profiles.Pin{}` with :repository preloaded"
attr :reorderable?, :boolean, default: false
def grid(assigns) do
~H"""
<ul
:if={@pins != []}
id="pinned-repos-grid"
phx-hook={@reorderable? && "PinReorder"}
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3"
>
<.card :for={pin <- @pins} pin={pin} reorderable?={@reorderable?} />
</ul>
"""
end
attr :pin, :map, required: true
attr :reorderable?, :boolean, default: false
defp card(assigns) do
repo = assigns.pin.repository
handle = Storage.repo_handle(repo)
top = top_language(repo)
assigns =
assigns
|> assign(:repo, repo)
|> assign(:handle, handle)
|> assign(:top_language, top)
~H"""
<li
data-pin-id={@pin.id}
class={[
"rounded-lg border border-base-300 bg-base-200/40 p-3 flex flex-col gap-2 min-h-28",
@reorderable? && "cursor-grab active:cursor-grabbing"
]}
>
<header class="flex items-baseline justify-between gap-2">
<.link
navigate={~p"/r/#{@handle}/#{@repo.name}"}
class="font-mono text-sm link link-hover truncate"
>
{@handle}/{@repo.name}
</.link>
<span :if={@repo.visibility != "public"} class="badge badge-xs badge-ghost">
{@repo.visibility}
</span>
</header>
<p :if={@repo.description} class="text-xs opacity-80 line-clamp-2">{@repo.description}</p>
<footer class="text-xs opacity-70 mt-auto flex items-center gap-1.5">
<%= if @top_language do %>
<span
class="inline-block size-2.5 rounded-full"
style={"background-color: " <> LanguageColors.for(@top_language) <> ";"}
/>
<span class="font-mono">{@top_language}</span>
<% else %>
<span class="opacity-50"></span>
<% end %>
</footer>
</li>
"""
end
defp top_language(repo) do
case repo.default_branch && Repositories.resolve(repo, repo.default_branch) do
{:ok, sha} ->
case Repositories.get_language_stats(repo, sha) do
{:ok, %{languages: [%{language: lang} | _]}} -> lang
_ -> nil
end
_ ->
nil
end
end
end