Extract the card-list row into ListItem
Assisted-by: GLM-5.3 via pi
change kllwpukroqqkovuplzpptnmyxxwtqvsm
commit 6c36ef211e496a11a9e25f47c9c756adc30194a0
author Alpha Chen <alpha@kejadlen.dev>
date
parent ovtlplsw
diff --git a/Steepfile b/Steepfile
index 6be4ae5..e6911e1 100644
--- a/Steepfile
+++ b/Steepfile
@@ -22,7 +22,7 @@ target :lib do
   # the files stay checked.
   ignore(*%w[
     avatar contact_dialog contacts_edit contacts_index contacts_show dashboard device_setup format
-    group_dialog group_label groups_edit groups_index groups_show icons layout phlex upcoming_birthdays
+    group_dialog group_label groups_edit groups_index groups_show icons layout list_item phlex upcoming_birthdays
   ].map { "lib/pro_tacts/admin/#{it}.rb" }, inline: true)
   signature "sig"
 
diff --git a/lib/pro_tacts/admin/contacts_index.rb b/lib/pro_tacts/admin/contacts_index.rb
index 58b29da..3ec5f00 100644
--- a/lib/pro_tacts/admin/contacts_index.rb
+++ b/lib/pro_tacts/admin/contacts_index.rb
@@ -3,6 +3,7 @@ require "pro_tacts/admin/phlex"
 require "pro_tacts/admin/avatar"
 require "pro_tacts/admin/format"
 require "pro_tacts/admin/layout"
+require "pro_tacts/admin/list_item"
 
 module ProTacts
   module Admin
@@ -51,12 +52,10 @@ module ProTacts
 
       #: (Contact contact) -> void
       def render_row(contact)
-        li do
-          a(href: "/contacts/#{contact.id}") do
-            render Avatar.new(contact:, size: "lg")
-            div(style: "flex: 1; min-width: 0; font-weight: 550;") { Format.name_label(contact) }
-          end
-        end
+        render ListItem.new(
+          href: "/contacts/#{contact.id}",
+          avatar: Avatar.new(contact:, size: "lg"),
+        ) { Format.name_label(contact) }
       end
     end
   end
diff --git a/lib/pro_tacts/admin/dashboard.rb b/lib/pro_tacts/admin/dashboard.rb
index 8d0701f..048c18b 100644
--- a/lib/pro_tacts/admin/dashboard.rb
+++ b/lib/pro_tacts/admin/dashboard.rb
@@ -4,6 +4,7 @@ require "pro_tacts/admin/avatar"
 require "pro_tacts/admin/contact_dialog"
 require "pro_tacts/admin/format"
 require "pro_tacts/admin/group_label"
+require "pro_tacts/admin/list_item"
 require "pro_tacts/admin/layout"
 require "pro_tacts/admin/upcoming_birthdays"
 
@@ -101,24 +102,18 @@ module ProTacts
         end
         ul(class: "card") do
           @groups.each do |group|
-            li do
-              a(href: "/groups/#{group.id}") do
-                div(style: "flex: 1; min-width: 0; font-weight: 550;") { render GroupLabel.new(group:) }
-              end
-            end
+            render ListItem.new(href: "/groups/#{group.id}") { render GroupLabel.new(group:) }
           end
         end
       end
 
       #: (Store::RecentContact row) -> void
       def render_row(row)
-        li do
-          a(href: "/contacts/#{row.contact.id}") do
-            render Avatar.new(contact: row.contact, size: "lg")
-            div(style: "flex: 1; min-width: 0; font-weight: 550;") { Format.name_label(row.contact) }
-            span(class: "type-label") { Format.time_ago(row.updated_at) }
-          end
-        end
+        render ListItem.new(
+          href: "/contacts/#{row.contact.id}",
+          avatar: Avatar.new(contact: row.contact, size: "lg"),
+          trailing: Format.time_ago(row.updated_at),
+        ) { Format.name_label(row.contact) }
       end
     end
   end
diff --git a/lib/pro_tacts/admin/groups_index.rb b/lib/pro_tacts/admin/groups_index.rb
index 7039b2a..fe080d6 100644
--- a/lib/pro_tacts/admin/groups_index.rb
+++ b/lib/pro_tacts/admin/groups_index.rb
@@ -2,6 +2,7 @@ require "pro_tacts/admin/phlex"
 
 require "pro_tacts/admin/group_label"
 require "pro_tacts/admin/layout"
+require "pro_tacts/admin/list_item"
 
 module ProTacts
   module Admin
@@ -34,12 +35,10 @@ module ProTacts
             else
               ul(class: "card") do
                 @groups.each do |group|
-                  li do
-                    a(href: "/groups/#{group.id}") do
-                      div(style: "flex: 1; min-width: 0; font-weight: 550;") { render GroupLabel.new(group:) }
-                      span(class: "type-label") { members_label(group) }
-                    end
-                  end
+                  render ListItem.new(
+                    href: "/groups/#{group.id}",
+                    trailing: members_label(group),
+                  ) { render GroupLabel.new(group:) }
                 end
               end
             end
diff --git a/lib/pro_tacts/admin/list_item.rb b/lib/pro_tacts/admin/list_item.rb
new file mode 100644
index 0000000..7bacce2
--- /dev/null
+++ b/lib/pro_tacts/admin/list_item.rb
@@ -0,0 +1,35 @@
+require "pro_tacts/admin/phlex"
+
+module ProTacts
+  module Admin
+    # One row of a card list: an li holding a link, an optional avatar
+    # in front, the block's label in a bold column that flexes, and an
+    # optional muted label behind it — the row shape every browse
+    # screen shares (the dashboard's contacts and group results,
+    # /contacts, /groups). The middle column is the one piece of
+    # layout this owns: min-width 0 lets a long name shrink instead
+    # of pushing what trails it off the card.
+    class ListItem < Phlex::HTML
+      # @rbs @href: String
+      # @rbs @avatar: Phlex::HTML?
+      # @rbs @trailing: String?
+
+      #: (href: String, ?avatar: Phlex::HTML?, ?trailing: String?) -> void
+      def initialize(href:, avatar: nil, trailing: nil)
+        @href = href
+        @avatar = avatar
+        @trailing = trailing
+      end
+
+      def view_template
+        li do
+          a(href: @href) do
+            render @avatar if @avatar
+            div(style: "flex: 1; min-width: 0; font-weight: 550;") { yield }
+            span(class: "type-label") { @trailing } if @trailing
+          end
+        end
+      end
+    end
+  end
+end