contacts edit: a handle's two fields on one line
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U77d1jrGYSKCTjsYWetd5d
diff --git a/lib/pro_tacts/admin/contacts_edit.rb b/lib/pro_tacts/admin/contacts_edit.rb
index 011d117..3661d2c 100644
--- a/lib/pro_tacts/admin/contacts_edit.rb
+++ b/lib/pro_tacts/admin/contacts_edit.rb
@@ -73,7 +73,8 @@ module ProTacts
# A handle row's two fields, the service first because it says
# what the handle is (docs/plans/2026-10-18-signal-handles.md,
- # "The service is the row's"). Field name to placeholder, the
+ # "The service is the row's"), side by side on one line as a
+ # birthday's are (admin.css). Field name to placeholder, the
# address fields' shape.
HANDLE_FIELDS = [
["service", "service"],
@@ -344,7 +345,7 @@ module ProTacts
# The handle kind: the standing row's two fields, named by
# the add index for the address's reason.
template("x-if": "kind === 'handle'") do
- div(class: "field-stack") do
+ div(class: "handle-row") do
HANDLE_FIELDS.each_with_index do |(field, label), index|
input(type: "text", ":name": "`new_handle[${i}][#{field}]`",
placeholder: label, aria_label: label,
@@ -524,7 +525,7 @@ module ProTacts
def handle_row(handle)
div(class: "field", data: {blank_removes: true}) do
span { "handle" }
- div(class: "field-stack") do
+ div(class: "handle-row") do
HANDLE_FIELDS.each do |field, label|
input(type: "text", name: "handle[#{handle.line.digest}][#{field}]",
value: handle.public_send(field), placeholder: label, aria_label: label)
diff --git a/public/admin.css b/public/admin.css
index a0e0bd2..a94ae28 100644
--- a/public/admin.css
+++ b/public/admin.css
@@ -250,6 +250,24 @@
color: var(--gl-color-danger);
}
+/* A handle row's two fields — service and handle — on one line in
+ the value column: the service names what the handle is, so the two
+ read as one value, the birthday row's reading. The service is the
+ shorter word and takes the narrower share; both shed their floor so
+ the pair fits a phone's value column rather than widening it. */
+.card-body form.field-stack .field > .handle-row {
+ display: flex;
+ gap: var(--gl-space-2xs);
+}
+.card-body form.field-stack .field > .handle-row > input {
+ flex: 1 1 0;
+ min-width: 0;
+ padding-block: var(--gl-space-3xs);
+}
+.card-body form.field-stack .field > .handle-row > input:last-child {
+ flex-grow: 2;
+}
+
/* The date line breaks in two when its row cannot hold a whole
date: a month name, two year boxes, and the two icon buttons need
~20rem side by side, and on a phone the value column has a
diff --git a/test/pro_tacts/admin/test_contacts_pages.rb b/test/pro_tacts/admin/test_contacts_pages.rb
index 5850c00..5c4ea78 100644
--- a/test/pro_tacts/admin/test_contacts_pages.rb
+++ b/test/pro_tacts/admin/test_contacts_pages.rb
@@ -2171,7 +2171,7 @@ class AdminContactsPagesTest < Minitest::Test
digest = store.contact("ada").handles.first.line.digest
assert_includes last_response.body,
- '<div class="field" data-blank-removes><span>handle</span><div class="field-stack">' \
+ '<div class="field" data-blank-removes><span>handle</span><div class="handle-row">' \
'<input type="text" name="handle[' + digest + '][service]" value="signal" placeholder="service" aria-label="service">' \
'<input type="text" name="handle[' + digest + '][value]" value="ada.42" placeholder="handle" aria-label="handle">' \
'</div></div>'
@@ -2781,7 +2781,7 @@ class AdminContactsPagesTest < Minitest::Test
# The handle kind: the standing row's two fields, named by the
# add index as the address's are.
assert_includes body,
- '<template x-if="kind === \'handle\'"><div class="field-stack">' \
+ '<template x-if="kind === \'handle\'"><div class="handle-row">' \
'<input type="text" :name="`new_handle[${i}][service]`" placeholder="service" aria-label="service" x-init="$el.focus()">' \
'<input type="text" :name="`new_handle[${i}][value]`" placeholder="handle" aria-label="handle">' \
'</div></template>'