summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-05 21:52:11 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-05 21:52:11 +0200
commit9a7ce465b06462443ee82e8418f3c070de080ab2 (patch)
treebf68ecc1536af990604cd58e75417073a07f0d1a
parent51d491a3d67e8c9efde8019ecb8a8e1a8195ec99 (diff)
Surface node-kind conventions in the admin UI
nodes#new: each kind's radio button now shows a label plus a smaller, muted .field_hint explaining what happens automatically (parent, tags, template) - previously a single undifferentiated string mixing a short label with a long parenthetical, cluttering the smaller kinds (erfa/chaostreff) worst. Title field gets the same hint treatment, telling editors up front that the slug is auto-generated and where to adjust it later - the previous silence here meant editors only discovered slug generation after already committing to a title, with no visible way to fix it. New "Resulting path" row live-previews the full URL (origin + kind's path prefix + a debounced call to the new parameterize_preview route, reusing the exact same slug_for helper "create" now calls, so the preview can never diverge from what actually gets created) as the editor types, plus a copy-to-clipboard button. For "generic", the prefix comes from whichever parent gets chosen via the search widget, not the registry - parent_search.link_closure now stashes the chosen node's unique_name as a data attribute for exactly this. New read-only admin/conventions view dumps the NODE_KINDS registry as a reference table for whoever's confused later about how a given kind behaves - deliberately just renders the same label/hint text used on nodes#new rather than re-describing parent/tags/template separately, since decomposing the parent Proc would mean either invoking it (Update's has a real side effect - creates the year folder) or re-stating its logic a second time in a different shape, either of which risks drifting from the actual behavior. nodes#edit's Template field gets a one-line hint noting the value may already be pre-filled based on how the node was created - the one place the previous commit's new inheritance mechanism actually surfaces on this view.
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/views/nodes/edit.html.erb5
-rw-r--r--app/views/nodes/new.html.erb34
-rw-r--r--config/routes.rb1
-rw-r--r--public/stylesheets/admin.css12
5 files changed, 40 insertions, 16 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 0be66e9..87aa82c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -11,4 +11,8 @@ module ApplicationHelper
11 end 11 end
12 end 12 end
13 end 13 end
14
15 def resolve_kind_text(value)
16 value.respond_to?(:call) ? value.call : value
17 end
14end 18end
diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb
index 31f585c..2d0edc1 100644
--- a/app/views/nodes/edit.html.erb
+++ b/app/views/nodes/edit.html.erb
@@ -44,7 +44,10 @@
44 <div class="node_content"><%= d.datetime_select :published_at, :value => @draft.published_at %></div> 44 <div class="node_content"><%= d.datetime_select :published_at, :value => @draft.published_at %></div>
45 45
46 <div class="node_description">Template</div> 46 <div class="node_description">Template</div>
47 <div class="node_content"><%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %></div> 47 <div class="node_content">
48 <%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %>
49 <span class="field_hint">Set automatically based on how this node was created - change it if needed.</span>
50 </div>
48 51
49 <div class="node_description">Author</div> 52 <div class="node_description">Author</div>
50 <div class="node_content"><%= d.select :user_id, user_list %></div> 53 <div class="node_content"><%= d.select :user_id, user_list %></div>
diff --git a/app/views/nodes/new.html.erb b/app/views/nodes/new.html.erb
index 028d727..f557454 100644
--- a/app/views/nodes/new.html.erb
+++ b/app/views/nodes/new.html.erb
@@ -13,27 +13,23 @@
13 <tr> 13 <tr>
14 <td class="description">Type</td> 14 <td class="description">Type</td>
15 <td> 15 <td>
16 <div> 16 <% CccConventions::NODE_KINDS.each do |kind, config| %>
17 <%= radio_button_tag :kind, "top_level" %>
18 Top Level
19 </div>
20 <p>
21 <%= radio_button_tag :kind, "generic", :selected => true %>
22 Generic ( can be created anywhere )
23 </p>
24 <p>
25 <%= radio_button_tag :kind, "update" %>
26 Update ( is automatically created in /updates/<%= Time.now.year.to_s %>/ and gets tag "update" )
27 </p>
28 <p> 17 <p>
29 <%= radio_button_tag :kind, "press_release" %> 18 <%= radio_button_tag :kind, kind, kind == "generic",
30 Pressemitteilung ( is automatically created in /updates/<%= Time.now.year.to_s %>/ and gets tags "update, pressemitteilung" ) 19 data: { path_prefix: resolve_kind_text(config[:path_prefix]) } %>
20 <%= resolve_kind_text(config[:label]) %>
21 <% if config[:hint] %>
22 <span class="field_hint"><%= resolve_kind_text(config[:hint]) %></span>
23 <% end %>
31 </p> 24 </p>
25 <% end %>
32 </td> 26 </td>
33 </tr> 27 </tr>
34 <tr> 28 <tr>
35 <td class="description">Title</td> 29 <td class="description">Title</td>
36 <td><%= text_field_tag :title %></td> 30 <td><%= text_field_tag :title %>
31 <span class="field_hint">A URL slug will be generated from this automatically. You can review or adjust it afterward under the "metadata" section's Slug field.</span>
32 </td>
37 </tr> 33 </tr>
38 <tr id="parent_search_field"> 34 <tr id="parent_search_field">
39 <td class="description">Parent</td> 35 <td class="description">Parent</td>
@@ -46,6 +42,14 @@
46 </td> 42 </td>
47 </tr> 43 </tr>
48 <tr> 44 <tr>
45 <td class="description">Resulting path</td>
46 <td>
47 <span id="resulting_path">—</span>
48 <button type="button" id="copy_resulting_path" class="unselected">copy</button>
49 <span class="field_hint">This preview updates as you type. The final path can still be changed afterward by editing the title (for the last segment) or moving the node to a different parent (for everything before it).</span>
50 </td>
51 </tr>
52 <tr>
49 <td></td> 53 <td></td>
50 <td class="right"><%= submit_tag "Create" %></td> 54 <td class="right"><%= submit_tag "Create" %></td>
51 </tr> 55 </tr>
diff --git a/config/routes.rb b/config/routes.rb
index cf4733c..6c07414 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -59,6 +59,7 @@ Cccms::Application.routes.draw do
59 match 'admin' => 'admin#index', :as => :admin, :via => :get 59 match 'admin' => 'admin#index', :as => :admin, :via => :get
60 match 'admin/search' => 'admin#search', :as => :admin_search, :via => :get 60 match 'admin/search' => 'admin#search', :as => :admin_search, :via => :get
61 match 'admin/menu_search' => 'admin#menu_search', :as => :admin_menu_search, :via => :get 61 match 'admin/menu_search' => 'admin#menu_search', :as => :admin_menu_search, :via => :get
62 match 'admin/conventions' => 'admin#conventions', :as => :admin_conventions, :via => :get
62 match 'search' => 'search#index', :as => :search, :via => :get 63 match 'search' => 'search#index', :as => :search, :via => :get
63 64
64 resources :users 65 resources :users
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css
index a02bd61..f240bb2 100644
--- a/public/stylesheets/admin.css
+++ b/public/stylesheets/admin.css
@@ -508,6 +508,14 @@ table tr.header {
508 text-align: left; 508 text-align: left;
509} 509}
510 510
511.field_hint {
512 display: block;
513 margin-top: 2px;
514 font-size: 0.75rem;
515 color: #969696;
516 padding-bottom: 4px;
517}
518
511#search_widget { 519#search_widget {
512 position: absolute; 520 position: absolute;
513 top: 20px; 521 top: 20px;
@@ -527,18 +535,21 @@ table tr.header {
527 font-size: 18px; 535 font-size: 18px;
528} 536}
529 537
538#menu_search_results p,
530#search_results p { 539#search_results p {
531 margin: 0; 540 margin: 0;
532 padding: 4px 4px 0 4px; 541 padding: 4px 4px 0 4px;
533 border-bottom: 1px solid #e8e8e8; 542 border-bottom: 1px solid #e8e8e8;
534} 543}
535 544
545#menu_search_results p a,
536#search_results p a { 546#search_results p a {
537 display: block; 547 display: block;
538 font-weight: bold; 548 font-weight: bold;
539 font-size: 0.95rem; 549 font-size: 0.95rem;
540} 550}
541 551
552#menu_search_results p span.result_path,
542#search_results p span.result_path { 553#search_results p span.result_path {
543 display: block; 554 display: block;
544 margin-top: 2px; 555 margin-top: 2px;
@@ -548,6 +559,7 @@ table tr.header {
548 padding-bottom: 4px; 559 padding-bottom: 4px;
549} 560}
550 561
562#menu_search_results p.search_more,
551#search_results p.search_more { 563#search_results p.search_more {
552 margin: 0; 564 margin: 0;
553 padding: 6px 4px; 565 padding: 6px 4px;