summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-09 02:25:56 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-09 02:25:56 +0200
commit332ffbeed90cf07342925b82ed3fda1762346be2 (patch)
treef507b6af5f467fd0aeb89286561e6af3b78f8ce1
parent168ff3f8b6037bc3c2b5bce74adac37e48366dac (diff)
Restyle revisions#index: sticky diff bar, computation button style, pre-selected defaults
Adds a fourth button category, .computation -- teal, matching Preview's existing color -- for actions that compute a view without changing state, the first case in the app that didn't fit reversible/state-changing/ destructive. Diff revisions now starts disabled and only enables once two distinct revisions are selected, matching the disabled-state pattern already used for Unlock + Back. The header row is wrapped in a real <thead> (previously flat inside the table alongside data rows) so a sticky diff bar can sit above the fold on long revision lists -- selecting a comparison pair no longer requires scrolling back up to find the button, or back down to confirm what's selected, both surfaced live via one shared JS function. The two most recent revisions are pre-selected by default, covering the most common comparison (current against previous) with no extra clicks. Deliberately scoped to numbered revisions only -- comparing draft/head or autosave/draft was raised and set aside, since neither exists as a row in this table by design and extending the comparison to them is a separate feature, not a default on this one. Also drops the dead "Edit" subnav link, redundant with nodes#show's Status section covering the same action with state-aware labeling this static link could never have.
-rw-r--r--app/views/revisions/index.html.erb100
-rw-r--r--public/stylesheets/admin.css66
2 files changed, 114 insertions, 52 deletions
diff --git a/app/views/revisions/index.html.erb b/app/views/revisions/index.html.erb
index 26a9ff4..a6a981a 100644
--- a/app/views/revisions/index.html.erb
+++ b/app/views/revisions/index.html.erb
@@ -1,46 +1,70 @@
1<% content_for :subnavigation do %>
2 <%= link_to 'Edit', edit_node_path(@node) %>
3<% end %>
4
5<h2>Revisions for Node: <%= @node.unique_name %></h2> 1<h2>Revisions for Node: <%= @node.unique_name %></h2>
6 2
7<table id="revisions"> 3<table id="revisions" class="revisions_table">
8 <tr class="header"> 4 <thead>
9 <th>First</th> 5 <tr class="header">
10 <th>Last</th> 6 <th>First</th>
11 <th>Rev.</th> 7 <th>Last</th>
12 <th>Title</th> 8 <th>Rev.</th>
13 <th>Editor</th> 9 <th>Title</th>
14 <th>Date</th> 10 <th>Editor</th>
15 <th></th> 11 <th>Date</th>
16 <th></th> 12 <th></th>
17 </tr> 13 <th></th>
18<% (@pages || @node.pages.all).reverse.each do |page| %> 14 </tr>
19 <tr> 15 <tr class="no_hover diff_sticky_bar">
20 <td><%= radio_button_tag :start_revision, page.revision %></td> 16 <td colspan="8">
21 <td><%= radio_button_tag :end_revision, page.revision %></td> 17 <%= button_to 'Diff revisions', diff_node_revisions_path(@node),
22 <td class="revision"><%= page.revision %></td> 18 method: :post,
23 <td class="title"><%= page.title %></td> 19 form: { id: 'diff_form', class: 'button_to computation' },
24 <td class="user"><%= page.editor.try(:login) %></td> 20 disabled: true %>
25 <td class="date"><%= page.updated_at %></td> 21 <span id="diff_selection_label"></span>
26 <td><%= link_to 'show', node_revision_path(@node, page) %></td> 22 </td>
27 <td> 23 </tr>
28 <%= button_to 'restore', restore_node_revision_path(@node, page), 24 </thead>
29 method: :put, 25 <tbody>
30 form: { data: { confirm: "Restore this revision?" }, class: 'button_to state_changing' } %> 26 <% pages = (@pages || @node.pages.all).reverse %>
31 </td> 27 <% pages.each_with_index do |page, index| %>
32 </tr> 28 <tr>
33<% end %> 29 <td><%= radio_button_tag :start_revision, page.revision, index == 1 %></td>
34 <tr class="no_hover"> 30 <td><%= radio_button_tag :end_revision, page.revision, index == 0 %></td>
35 <td colspan="8" class="right"> 31 <td class="revision"><%= page.revision %></td>
36 <%= button_to 'Diff revisions', diff_node_revisions_path(@node), 32 <td class="title"><%= page.title %></td>
37 method: :post, 33 <td class="user"><%= page.editor.try(:login) %></td>
38 form: { id: 'diff_form' } %> 34 <td class="date"><%= page.updated_at %></td>
39 </td> 35 <td><%= link_to 'show', node_revision_path(@node, page) %></td>
40 </tr> 36 <td>
37 <%= button_to 'restore', restore_node_revision_path(@node, page),
38 method: :put,
39 form: { data: { confirm: "Restore this revision?" }, class: 'button_to state_changing' } %>
40 </td>
41 </tr>
42 <% end %>
43 </tbody>
41</table> 44</table>
42 45
43<script> 46<script>
47 function update_diff_button_state() {
48 var start = document.querySelector('input[name="start_revision"]:checked');
49 var end = document.querySelector('input[name="end_revision"]:checked');
50 var valid = start && end && start.value !== end.value;
51 document.querySelector('#diff_form button[type="submit"]').disabled = !valid;
52
53 var label = document.getElementById('diff_selection_label');
54 if (start && end) {
55 label.textContent = start.value + ' against ' + end.value;
56 } else if (start || end) {
57 label.textContent = (start || end).value + ' selected';
58 } else {
59 label.textContent = '';
60 }
61 }
62
63 document.querySelectorAll('input[name="start_revision"], input[name="end_revision"]')
64 .forEach(function(radio) { radio.addEventListener('change', update_diff_button_state); });
65
66 update_diff_button_state();
67
44 document.getElementById('diff_form').addEventListener('submit', function(e) { 68 document.getElementById('diff_form').addEventListener('submit', function(e) {
45 var start = document.querySelector('input[name="start_revision"]:checked'); 69 var start = document.querySelector('input[name="start_revision"]:checked');
46 var end = document.querySelector('input[name="end_revision"]:checked'); 70 var end = document.querySelector('input[name="end_revision"]:checked');
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css
index a6e8bf6..3607166 100644
--- a/public/stylesheets/admin.css
+++ b/public/stylesheets/admin.css
@@ -29,6 +29,7 @@ table.node_table a,
29table.assets_table a, 29table.assets_table a,
30table.events_table a, 30table.events_table a,
31table.user_table a, 31table.user_table a,
32table.revisions_table a,
32.add_child_links a, 33.add_child_links a,
33div#draft_list table td.actions a { 34div#draft_list table td.actions a {
34 text-decoration: underline; 35 text-decoration: underline;
@@ -297,6 +298,27 @@ form.button_to.destructive button[type="submit"]:hover {
297 background-color: #cc0000; 298 background-color: #cc0000;
298} 299}
299 300
301form.button_to.computation input[type="submit"],
302form.button_to.computation button[type="submit"] {
303 color: #00838f;
304 background-color: #e0f2f1;
305 border-radius: 2px;
306 padding: 2px 8px;
307}
308
309form.button_to.computation input[type="submit"]:hover,
310form.button_to.computation button[type="submit"]:hover {
311 color: #ffffff;
312 background-color: #00838f;
313}
314
315form.button_to.computation input[type="submit"]:disabled,
316form.button_to.computation button[type="submit"]:disabled {
317 opacity: 0.4;
318 cursor: not-allowed;
319 pointer-events: none;
320}
321
300/* Native (non-button_to) submit buttons -- Create/Save/Publish forms. 322/* Native (non-button_to) submit buttons -- Create/Save/Publish forms.
301 Lower specificity than form.button_to's own rule, so button_to forms 323 Lower specificity than form.button_to's own rule, so button_to forms
302 are correctly unaffected. If a button_to output ever loses its class 324 are correctly unaffected. If a button_to output ever loses its class
@@ -420,42 +442,58 @@ table.node_table tr:hover {
420 content: "• "; 442 content: "• ";
421} 443}
422 444
423table#revisions { 445table.revisions_table {
424 border-collapse: collapse; 446 border-collapse: collapse;
425} 447}
426 448
427table#revisions tr { 449table.revisions_table thead {
428 height: 45px; 450 position: sticky;
451 top: 0;
452 z-index: 1;
429} 453}
430 454
431/* Redundant with the generic table tr.header rule above (identical 455table.revisions_table th,
432 values) -- harmless, kept presumably for explicitness. */ 456table.revisions_table td {
433table#revisions tr.header { 457 padding: 0.4rem 0.75rem;
434 height: 20px;
435 text-align: left; 458 text-align: left;
436} 459}
437 460
438table#revisions td { 461table.revisions_table thead tr.header,
439 padding-right: 25px; 462table.revisions_table thead tr.diff_sticky_bar {
463 background-color: #ffffff;
464}
465
466table.revisions_table .diff_sticky_bar td {
467 padding-top: 0.5rem;
468 padding-bottom: 0.5rem;
469 border-bottom: 1px solid #e8e8e8;
440} 470}
441 471
442table#revisions td.title { 472#diff_selection_label {
473 margin-left: 0.75rem;
474 color: #969696;
475}
476table.revisions_table td.title {
443 width: 450px; 477 width: 450px;
444} 478}
445 479
446table#revisions td.date { 480table.revisions_table td.date {
447 width: 175px; 481 width: 175px;
448} 482}
449 483
450table#revisions tr.header:hover { 484table.revisions_table tr:not(.header):not(.no_hover) {
485 border-bottom: 1px solid #e8e8e8;
486}
487
488table.revisions_table tr.header:hover {
451 background-color: #ffffff; 489 background-color: #ffffff;
452} 490}
453 491
454table#revisions tr.no_hover:hover { 492table.revisions_table tr.no_hover:hover {
455 background-color: #ffffff; 493 background-color: #ffffff;
456} 494}
457 495
458table#revisions tr:hover { 496table.revisions_table tr:hover {
459 background-color: #f1f1f1; 497 background-color: #f1f1f1;
460} 498}
461 499