list: show only the top ten by default
Assisted-by: Claude Sonnet 5.5 via Claude Code
diff --git a/lib/rank_king/views/list/show.rb b/lib/rank_king/views/list/show.rb
index 5b57ff7..302b85b 100644
--- a/lib/rank_king/views/list/show.rb
+++ b/lib/rank_king/views/list/show.rb
@@ -8,6 +8,8 @@ module RankKing
module Views
module ListViews
class Show < Phlex::HTML
+ VISIBLE = 10
+
def initialize(list:, csrf:, axis: nil)
@list = list
@csrf = csrf
@@ -85,20 +87,15 @@ module RankKing
def render_ranking(axis)
ranked, unranked = axis.ranking
+ rows = ranked.each.with_index(1).map { |item, rank| [item, format("%02d", rank), false] } +
+ unranked.map { |item| [item, "—", true] }
+ shown, hidden = rows.take(VISIBLE), rows.drop(VISIBLE)
- ol(class: "card") do
- ranked.each.with_index(1) do |item, rank|
- li do
- span(class: "type-label") { format("%02d", rank) }
- plain item.name
- end
- end
- unranked.each do |item|
- li do
- span(class: "type-label") { "—" }
- plain item.name
- span(class: "type-label") { "Unranked" }
- end
+ render_rows(shown)
+ unless hidden.empty?
+ details do
+ summary { "Show #{hidden.size} more" }
+ render_rows(hidden, start: VISIBLE + 1)
end
end
@@ -106,6 +103,18 @@ module RankKing
"Compare on #{axis.name}"
end
end
+
+ def render_rows(rows, start: nil)
+ ol(class: "card", start: start) do
+ rows.each do |item, label, unranked|
+ li do
+ span(class: "type-label") { label }
+ plain item.name
+ span(class: "type-label") { "Unranked" } if unranked
+ end
+ end
+ end
+ end
end
end
end
diff --git a/public/css/app.css b/public/css/app.css
index e5c8867..4dcf274 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -174,6 +174,13 @@ main > header [popovertarget] { anchor-name: --rk-list-actions; }
gap: var(--gl-space-s);
}
+/* The rest of a long ranking, spaced like the tabpanel's other children. */
+[role="tabpanel"] details[open] {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gl-space-s);
+}
+
/* The rank sits in a fixed gutter; "Unranked" sits at the far end. */
.card > li:has(> .type-label:first-child) { align-items: baseline; }
diff --git a/test/test_web.rb b/test/test_web.rb
index cbbf488..0d7a994 100644
--- a/test/test_web.rb
+++ b/test/test_web.rb
@@ -240,6 +240,34 @@ class TestWeb < Minitest::Test
assert_includes body, "Compare on Taste"
end
+ def test_show_list_folds_everything_past_ten_into_a_disclosure
+ list, axis = create_list_with_axis(items: (1..12).map { |n| "Item#{n}" }.join("\n"))
+ record_result(list, axis, winner: list.items.first, loser: list.items.last)
+
+ get "/lists/#{list.id}"
+ body = last_response.body[/role="tabpanel".*/m]
+ assert_includes body, "<summary>Show 2 more</summary>"
+ assert_includes body, '<ol class="card" start="11">'
+ visible, hidden = body.split("<details>")
+ assert_equal 10, visible.scan("<li>").size
+ assert_equal 2, hidden.scan("<li>").size
+ assert_includes hidden, "Unranked"
+ end
+
+ def test_show_list_folds_a_single_extra_item
+ list, = create_list_with_axis(items: (1..11).map { |n| "Item#{n}" }.join("\n"))
+
+ get "/lists/#{list.id}"
+ assert_includes last_response.body, "<summary>Show 1 more</summary>"
+ end
+
+ def test_show_list_has_no_disclosure_for_ten_or_fewer
+ list, = create_list_with_axis(items: (1..10).map { |n| "Item#{n}" }.join("\n"))
+
+ get "/lists/#{list.id}"
+ refute_includes last_response.body, "<details>"
+ end
+
def test_show_list_selects_the_requested_axis
create_list(name: "Foods", items: "Pizza\nSushi", axes: %w[Taste Value])
list = RankKing::List.first