neiam /gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Packages
⭐
Log in to mark this repository.
Collapse the version pager behind a chevron
cab81d0 · Gabriel Morell · 2026-09-09 20:26
Message
{commit_body(@commit)}
Files changed
modified
lib/git_gud_web/live/repo_live/blob.ex
+40
−11
@@ -42,6 +42,7 @@ defmodule GitGudWeb.RepoLive.Blob do
| 42 | 42 | |> assign(:path_segs, path_segs) |
| 43 | 43 | |> assign(:head_sha, head_sha) |
| 44 | 44 | |> assign(:from_ref, from_ref) |
| 45 | + |> assign(:show_pager?, params["pager"] == "1") | |
| 45 | 46 | |> assign_versions(versions, idx) |
| 46 | 47 | |> assign(:page_title, "#{owner}/#{name}: #{path}") |
| 47 | 48 |
@@ -142,8 +143,12 @@ defmodule GitGudWeb.RepoLive.Blob do
| 142 | 143 | |
| 143 | 144 | defp version_count(versions), do: length(versions) |
| 144 | 145 | |
| 145 | − defp version_path(handle, repo, segs, sha, from), | |
| 146 | − do: ~p"/r/#{handle}/#{repo.name}/blob/#{sha}/#{segs}?#{[from: from]}" | |
| 146 | + # `pager` rides along so stepping through versions doesn't collapse the | |
| 147 | + # pager you just opened. | |
| 148 | + defp version_path(handle, repo, segs, sha, from, pager?) do | |
| 149 | + query = [from: from] ++ if pager?, do: [pager: "1"], else: [] | |
| 150 | + ~p"/r/#{handle}/#{repo.name}/blob/#{sha}/#{segs}?#{query}" | |
| 151 | + end | |
| 147 | 152 | |
| 148 | 153 | defp load_text(repo, sha, name, theme) do |
| 149 | 154 | case Repositories.get_blob_bytes(repo, sha) do |
@@ -162,6 +167,11 @@ defmodule GitGudWeb.RepoLive.Blob do
| 162 | 167 | end |
| 163 | 168 | end |
| 164 | 169 | |
| 170 | + @impl true | |
| 171 | + def handle_event("toggle_pager", _params, socket) do | |
| 172 | + {:noreply, assign(socket, :show_pager?, !socket.assigns.show_pager?)} | |
| 173 | + end | |
| 174 | + | |
| 165 | 175 | @impl true |
| 166 | 176 | def render(assigns) do |
| 167 | 177 | ~H""" |
@@ -191,23 +201,40 @@ defmodule GitGudWeb.RepoLive.Blob do
| 191 | 201 | </span> |
| 192 | 202 | <span :if={!@meta}>not present at this version</span> |
| 193 | 203 | <span class="flex items-center gap-3"> |
| 194 | − <.link | |
| 195 | − navigate={~p"/r/#{@handle}/#{@repo.name}/commits/#{@from_ref}/#{@path_segs}"} | |
| 196 | − class="link link-hover" | |
| 197 | − > | |
| 198 | − History | |
| 199 | − </.link> | |
| 204 | + <span class="join"> | |
| 205 | + <.link | |
| 206 | + navigate={~p"/r/#{@handle}/#{@repo.name}/commits/#{@from_ref}/#{@path_segs}"} | |
| 207 | + class="btn btn-xs join-item" | |
| 208 | + > | |
| 209 | + History | |
| 210 | + </.link> | |
| 211 | + <button | |
| 212 | + :if={@current_version} | |
| 213 | + type="button" | |
| 214 | + phx-click="toggle_pager" | |
| 215 | + aria-expanded={to_string(@show_pager?)} | |
| 216 | + aria-label="Toggle version pager" | |
| 217 | + class="btn btn-xs join-item" | |
| 218 | + > | |
| 219 | + <.icon | |
| 220 | + name={if @show_pager?, do: "hero-chevron-up", else: "hero-chevron-down"} | |
| 221 | + class="size-3" | |
| 222 | + /> | |
| 223 | + </button> | |
| 224 | + </span> | |
| 200 | 225 | <span class="font-mono">{Git.short(@head_sha)}</span> |
| 201 | 226 | </span> |
| 202 | 227 | </div> |
| 203 | 228 | |
| 204 | 229 | <div |
| 205 | − :if={@current_version} | |
| 230 | + :if={@current_version && @show_pager?} | |
| 206 | 231 | class="flex items-center justify-between gap-3 border border-base-300 rounded-md px-3 py-2" |
| 207 | 232 | > |
| 208 | 233 | <.link |
| 209 | 234 | :if={@older_version} |
| 210 | − navigate={version_path(@handle, @repo, @path_segs, @older_version.id, @from_ref)} | |
| 235 | + navigate={ | |
| 236 | + version_path(@handle, @repo, @path_segs, @older_version.id, @from_ref, @show_pager?) | |
| 237 | + } | |
| 211 | 238 | class="btn btn-xs" |
| 212 | 239 | > |
| 213 | 240 | ← Older |
@@ -232,7 +259,9 @@ defmodule GitGudWeb.RepoLive.Blob do
| 232 | 259 | |
| 233 | 260 | <.link |
| 234 | 261 | :if={@newer_version} |
| 235 | − navigate={version_path(@handle, @repo, @path_segs, @newer_version.id, @from_ref)} | |
| 262 | + navigate={ | |
| 263 | + version_path(@handle, @repo, @path_segs, @newer_version.id, @from_ref, @show_pager?) | |
| 264 | + } | |
| 236 | 265 | class="btn btn-xs" |
| 237 | 266 | > |
| 238 | 267 | Newer → |
modified
test/git_gud_web/live/repo_live/log_path_test.exs
+21
−6
@@ -44,11 +44,13 @@ defmodule GitGudWeb.RepoLive.LogPathTest do
| 44 | 44 | |
| 45 | 45 | [deleted_at, added_at] = versions_of(repo, "a.txt") |
| 46 | 46 | |
| 47 | − {:ok, _lv, html} = live(conn, "#{base}/blob/#{deleted_at}/a.txt?from=#{repo.default_branch}") | |
| 47 | + {:ok, _lv, html} = | |
| 48 | + live(conn, "#{base}/blob/#{deleted_at}/a.txt?from=#{repo.default_branch}&pager=1") | |
| 49 | + | |
| 48 | 50 | assert html =~ "not present at this version" |
| 49 | 51 | assert html =~ "version 1 of 2" |
| 50 | 52 | # The pager is the point: you can still step back to when it existed. |
| 51 | − assert html =~ "/blob/#{added_at}/a.txt?from=#{repo.default_branch}" | |
| 53 | + assert html =~ "/blob/#{added_at}/a.txt?from=#{repo.default_branch}&pager=1" | |
| 52 | 54 | end |
| 53 | 55 | |
| 54 | 56 | defp write_blob(path, body) do |
@@ -116,23 +118,36 @@ defmodule GitGudWeb.RepoLive.LogPathTest do
| 116 | 118 | assert html =~ "/blob/#{oldest}/a.txt?from=#{repo.default_branch}" |
| 117 | 119 | end |
| 118 | 120 | |
| 121 | + test "the pager is hidden until the chevron is clicked", %{conn: conn, repo: repo, base: base} do | |
| 122 | + {:ok, lv, html} = live(conn, "#{base}/blob/#{repo.default_branch}/a.txt") | |
| 123 | + refute html =~ "version 1 of 2" | |
| 124 | + | |
| 125 | + html = lv |> element("button[phx-click='toggle_pager']") |> render_click() | |
| 126 | + assert html =~ "version 1 of 2" | |
| 127 | + | |
| 128 | + html = lv |> element("button[phx-click='toggle_pager']") |> render_click() | |
| 129 | + refute html =~ "version 1 of 2" | |
| 130 | + end | |
| 131 | + | |
| 119 | 132 | test "the blob pager walks back and forward through versions", %{ |
| 120 | 133 | conn: conn, |
| 121 | 134 | repo: repo, |
| 122 | 135 | base: base |
| 123 | 136 | } do |
| 124 | 137 | [newest, oldest] = versions_of(repo, "a.txt") |
| 138 | + branch = repo.default_branch | |
| 125 | 139 | |
| 126 | 140 | # Branch view sits at the newest version; there is nothing newer. |
| 127 | − {:ok, _lv, html} = live(conn, "#{base}/blob/#{repo.default_branch}/a.txt") | |
| 141 | + {:ok, _lv, html} = live(conn, "#{base}/blob/#{branch}/a.txt?pager=1") | |
| 128 | 142 | assert html =~ "version 1 of 2" |
| 129 | − assert html =~ "/blob/#{oldest}/a.txt?from=#{repo.default_branch}" | |
| 143 | + # The open state rides along so paging doesn't collapse it. | |
| 144 | + assert html =~ "/blob/#{oldest}/a.txt?from=#{branch}&pager=1" | |
| 130 | 145 | |
| 131 | 146 | # Step back. |
| 132 | − {:ok, _lv, html} = live(conn, "#{base}/blob/#{oldest}/a.txt?from=#{repo.default_branch}") | |
| 147 | + {:ok, _lv, html} = live(conn, "#{base}/blob/#{oldest}/a.txt?from=#{branch}&pager=1") | |
| 133 | 148 | assert html =~ "version 2 of 2" |
| 134 | 149 | refute html =~ "/blob/#{oldest}/a.txt?from" |
| 135 | − assert html =~ "/blob/#{newest}/a.txt?from=#{repo.default_branch}" | |
| 150 | + assert html =~ "/blob/#{newest}/a.txt?from=#{branch}&pager=1" | |
| 136 | 151 | end |
| 137 | 152 | |
| 138 | 153 | test "a commit outside the file's history gets no pager", %{ |
Parents: 01eb20a