diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 01:57:43 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 01:57:43 +0200 |
| commit | 65c7c40f74c315c1a39fb15da8ce341fb8b9b05e (patch) | |
| tree | adeea832d7d808b58015f8f4e7964b86ad857939 | |
| parent | 6730af4b33b207a7a1880cef2706e67313a7e5cd (diff) | |
Wavy-underline: allowlist to default; destroy-button and search polish
Flips the plain-link underline from an opt-in list (growing every time
a new context needed it) to the default a rule, with opt-outs living
as more specific overrides where something shouldn't look like plain
content -- .action_button, the icon nav, the search dropdown's bold
results. The allowlist's own history made the case for this: three of
its entries were already hand-copied duplicates of the same five
properties, and two of those had already silently drifted.
form.button_to's icon+text buttons (Destroy, currently) get the same
inline-flex/gap treatment .action_button already had -- they were
never included in that fix, so they still baseline-aligned an SVG
against text instead of centering it, plus an explicit icon size
they'd never had either.
Dashboard search results: tags render as a wrapped row of pills
instead of one-per-line, for visual distinction from page results.
The public-preview link and its Revoke button get their own row
rather than loose inline flow, which wrapped unpredictably next to a
long token URL -- aligned by box-top rather than center or baseline,
since a <button> doesn't reliably expose a text baseline the way a
plain link does, with a small compensating offset for the button's
own internal padding.
| -rw-r--r-- | app/views/nodes/show.html.erb | 6 | ||||
| -rw-r--r-- | public/javascripts/admin_search.js | 4 | ||||
| -rw-r--r-- | public/stylesheets/admin.css | 72 |
3 files changed, 48 insertions, 34 deletions
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb index 6e20258..280e492 100644 --- a/app/views/nodes/show.html.erb +++ b/app/views/nodes/show.html.erb | |||
| @@ -122,8 +122,10 @@ | |||
| 122 | <div class="node_info_item"> | 122 | <div class="node_info_item"> |
| 123 | <span class="node_info_label">Public Preview</span> | 123 | <span class="node_info_label">Public Preview</span> |
| 124 | <% if @node.draft.preview_token.present? %> | 124 | <% if @node.draft.preview_token.present? %> |
| 125 | <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %> | 125 | <div class="preview_link_row"> |
| 126 | <%= button_to 'Revoke', revoke_shared_preview_node_path(@node), method: :put, form: { data: { confirm: "Revoke this preview link? Anyone currently using it will immediately lose access." }, class: 'button_to state_changing' } %> | 126 | <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %> |
| 127 | <%= button_to 'Revoke', revoke_shared_preview_node_path(@node), method: :put, form: { data: { confirm: "Revoke this preview link? Anyone currently using it will immediately lose access." }, class: 'button_to state_changing' } %> | ||
| 128 | </div> | ||
| 127 | <% else %> | 129 | <% else %> |
| 128 | <%= button_to 'Create public preview link', generate_shared_preview_node_path(@node), method: :put, form: { class: 'button_to state_changing' } %> | 130 | <%= button_to 'Create public preview link', generate_shared_preview_node_path(@node), method: :put, form: { class: 'button_to state_changing' } %> |
| 129 | <% end %> | 131 | <% end %> |
diff --git a/public/javascripts/admin_search.js b/public/javascripts/admin_search.js index 53bcb5e..0c768a3 100644 --- a/public/javascripts/admin_search.js +++ b/public/javascripts/admin_search.js | |||
| @@ -137,10 +137,12 @@ dashboard_search = { | |||
| 137 | 137 | ||
| 138 | if (data.tags.length) { | 138 | if (data.tags.length) { |
| 139 | results.append("<p class='search_group_label'>Tags</p>"); | 139 | results.append("<p class='search_group_label'>Tags</p>"); |
| 140 | var tag_row = $("<div class='search_tag_row'></div>"); | ||
| 140 | data.tags.forEach(function(tag) { | 141 | data.tags.forEach(function(tag) { |
| 141 | results.append("<p><a href='" + tag.tag_path + "'>" + tag.name + "</a></p>"); | 142 | tag_row.append("<a class='search_tag_pill' href='" + tag.tag_path + "'>" + tag.name + "</a>"); |
| 142 | found = true; | 143 | found = true; |
| 143 | }); | 144 | }); |
| 145 | results.append(tag_row); | ||
| 144 | } | 146 | } |
| 145 | 147 | ||
| 146 | if (data.nodes.length) { | 148 | if (data.nodes.length) { |
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css index d85e61e..a58a061 100644 --- a/public/stylesheets/admin.css +++ b/public/stylesheets/admin.css | |||
| @@ -8,38 +8,10 @@ body { | |||
| 8 | margin: 0px; | 8 | margin: 0px; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | /* Plain link visibility: a light, desaturated squiggly underline | ||
| 12 | signals "clickable" at rest without the weight of a solid line. */ | ||
| 11 | a { | 13 | a { |
| 12 | color: #000000; | 14 | color: #000000; |
| 13 | text-decoration: none; | ||
| 14 | } | ||
| 15 | |||
| 16 | a:hover { | ||
| 17 | color: #ff9600; | ||
| 18 | } | ||
| 19 | |||
| 20 | /* Scoped link visibility: a light, desaturated squiggly underline | ||
| 21 | signals "clickable" at rest without the weight of a solid line. | ||
| 22 | Hover still relies on the global a:hover color change above -- this | ||
| 23 | only adds an at-rest affordance for plain content links that would | ||
| 24 | otherwise be indistinguishable from body text. Covers: page editor | ||
| 25 | body content, node listing tables, the child-creation shortcuts on | ||
| 26 | nodes#show, and the dashboard draft list's Show/Revisions links. */ | ||
| 27 | #page_editor a, | ||
| 28 | .dashboard_widget a, | ||
| 29 | .search_results_list a, | ||
| 30 | #sitemap a, | ||
| 31 | #flash a, | ||
| 32 | div.pagination a, | ||
| 33 | #menu_item_list td a, | ||
| 34 | table.node_table a, | ||
| 35 | table.assets_table a, | ||
| 36 | table.events_table a, | ||
| 37 | table.user_table a, | ||
| 38 | table.revisions_table a, | ||
| 39 | .add_child_links a, | ||
| 40 | .standalone_action_bar a, | ||
| 41 | .diff_view_toggle a, | ||
| 42 | div#draft_list table td.actions a { | ||
| 43 | text-decoration: underline; | 15 | text-decoration: underline; |
| 44 | -webkit-text-decoration-style: wavy; | 16 | -webkit-text-decoration-style: wavy; |
| 45 | text-decoration-style: wavy; | 17 | text-decoration-style: wavy; |
| @@ -48,6 +20,10 @@ div#draft_list table td.actions a { | |||
| 48 | text-underline-offset: 2px; | 20 | text-underline-offset: 2px; |
| 49 | } | 21 | } |
| 50 | 22 | ||
| 23 | a:hover { | ||
| 24 | color: #ff9600; | ||
| 25 | } | ||
| 26 | |||
| 51 | th { | 27 | th { |
| 52 | text-transform: lowercase; | 28 | text-transform: lowercase; |
| 53 | } | 29 | } |
| @@ -264,6 +240,9 @@ form.button_to { | |||
| 264 | 240 | ||
| 265 | form.button_to input[type="submit"], | 241 | form.button_to input[type="submit"], |
| 266 | form.button_to button[type="submit"] { | 242 | form.button_to button[type="submit"] { |
| 243 | display: inline-flex; | ||
| 244 | align-items: center; | ||
| 245 | gap: 0.5rem; | ||
| 267 | -webkit-appearance: none; | 246 | -webkit-appearance: none; |
| 268 | appearance: none; | 247 | appearance: none; |
| 269 | background: none; | 248 | background: none; |
| @@ -356,6 +335,7 @@ input[type="submit"]:hover { | |||
| 356 | #main_navigation a, | 335 | #main_navigation a, |
| 357 | #main_navigation form.button_to button { | 336 | #main_navigation form.button_to button { |
| 358 | display: inline-flex; | 337 | display: inline-flex; |
| 338 | text-decoration: none; | ||
| 359 | align-items: center; | 339 | align-items: center; |
| 360 | background-color: #f7f7f7; | 340 | background-color: #f7f7f7; |
| 361 | justify-content: center; | 341 | justify-content: center; |
| @@ -372,7 +352,8 @@ input[type="submit"]:hover { | |||
| 372 | } | 352 | } |
| 373 | 353 | ||
| 374 | #main_navigation svg, | 354 | #main_navigation svg, |
| 375 | .action_button svg { | 355 | .action_button svg, |
| 356 | form.button_to svg { | ||
| 376 | width: 1.25rem; | 357 | width: 1.25rem; |
| 377 | height: 1.25rem; | 358 | height: 1.25rem; |
| 378 | } | 359 | } |
| @@ -853,6 +834,17 @@ form.button_to button[type="submit"] { | |||
| 853 | font-weight: bold; | 834 | font-weight: bold; |
| 854 | } | 835 | } |
| 855 | 836 | ||
| 837 | .preview_link_row { | ||
| 838 | display: flex; | ||
| 839 | flex-wrap: wrap; | ||
| 840 | align-items: start; | ||
| 841 | gap: 0.5rem; | ||
| 842 | } | ||
| 843 | |||
| 844 | .preview_link_row form.button_to { | ||
| 845 | margin-top: -5px; | ||
| 846 | } | ||
| 847 | |||
| 856 | /* ============================================================ | 848 | /* ============================================================ |
| 857 | Page editor / metadata forms | 849 | Page editor / metadata forms |
| 858 | ============================================================ */ | 850 | ============================================================ */ |
| @@ -1060,6 +1052,23 @@ div#draft_list table td.actions a { | |||
| 1060 | border-bottom: 1px solid #f1f1f1; | 1052 | border-bottom: 1px solid #f1f1f1; |
| 1061 | } | 1053 | } |
| 1062 | 1054 | ||
| 1055 | .search_tag_row { | ||
| 1056 | display: flex; | ||
| 1057 | flex-wrap: wrap; | ||
| 1058 | gap: 0.4rem; | ||
| 1059 | padding: 4px 4px 8px; | ||
| 1060 | border-bottom: 1px solid #e8e8e8; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | .search_tag_pill { | ||
| 1064 | display: inline-block; | ||
| 1065 | padding: 2px 10px; | ||
| 1066 | border-radius: 999px; | ||
| 1067 | background-color: #f1f1f1; | ||
| 1068 | font-size: 0.85rem; | ||
| 1069 | text-decoration: none; | ||
| 1070 | } | ||
| 1071 | |||
| 1063 | /* ============================================================ | 1072 | /* ============================================================ |
| 1064 | Search widgets | 1073 | Search widgets |
| 1065 | ============================================================ */ | 1074 | ============================================================ */ |
| @@ -1093,6 +1102,7 @@ div#draft_list table td.actions a { | |||
| 1093 | } | 1102 | } |
| 1094 | 1103 | ||
| 1095 | .search_results p a { | 1104 | .search_results p a { |
| 1105 | text-decoration: none; | ||
| 1096 | display: block; | 1106 | display: block; |
| 1097 | font-weight: bold; | 1107 | font-weight: bold; |
| 1098 | font-size: 0.95rem; | 1108 | font-size: 0.95rem; |
