Collapse the version pager behind a chevron

cab81d0 · Gabriel Morell · 2026-09-09 20:26

2 files +61 -17
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}&amp;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}&amp;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}&amp;pager=1"
136 151 end
137 152
138 153 test "a commit outside the file's history gets no pager", %{

Parents: 01eb20a