From 1384756b81c719f899359efc9125e80fae8614c0 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Sat, 1 Aug 2026 14:46:04 +0200 Subject: Allow aggregate to order by slug and paint chapters list more nicely --- app/helpers/content_helper.rb | 3 +++ app/helpers/link_helper.rb | 5 ++-- app/models/page.rb | 5 ++++ app/views/custom/partials/_chapter.html.erb | 38 ++++++++++++++--------------- public/stylesheets/ccc.css | 23 ++++++++++------- test/controllers/users_controller_test.rb | 4 +-- test/models/page_test.rb | 13 ++++++++++ 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/app/helpers/content_helper.rb b/app/helpers/content_helper.rb index 9d52c110..b2603481 100644 --- a/app/helpers/content_helper.rb +++ b/app/helpers/content_helper.rb @@ -98,6 +98,9 @@ module ContentHelper # order_by="published_at" # order_direction="DESC" # ] + # + # order_by currently takes id, published_at, created_at, updated_at, title + # and slug def aggregate? content diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb index 2121133e..21e4da59 100644 --- a/app/helpers/link_helper.rb +++ b/app/helpers/link_helper.rb @@ -21,8 +21,9 @@ module LinkHelper active = (page_path == path.sub(/^\//, "")) end - active_class = active ? {:class => 'active'} : {:class => 'inactive'} - html_options = html_options.merge(active_class) + html_options = html_options.merge( + :class => [html_options[:class], active ? "active" : "inactive"].compact.join(" ") + ) locale = (params[:locale] || I18n.locale).to_sym == I18n.default_locale ? nil : (params[:locale] || I18n.locale) link_to( diff --git a/app/models/page.rb b/app/models/page.rb index a66527da..8313b1d4 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -92,6 +92,11 @@ class Page < ApplicationRecord .paginate(:page => page, :per_page => options[:limit]) end + if options[:order_by] == "slug" + return scope.order(Arel.sql("MIN(LOWER(nodes.slug)) #{direction}")) + .paginate(:page => page, :per_page => options[:limit]) + end + column = options[:order_by].to_s.sub(/\Apages\./, "") column = "id" unless %w[id published_at created_at updated_at].include?(column) diff --git a/app/views/custom/partials/_chapter.html.erb b/app/views/custom/partials/_chapter.html.erb index 5d47679e..8a92b46f 100644 --- a/app/views/custom/partials/_chapter.html.erb +++ b/app/views/custom/partials/_chapter.html.erb @@ -1,26 +1,24 @@
<% if page.headline_asset %> - <%= link_to_path image_tag(page.headline_asset.upload.url(:thumb), :alt => ""), page.node.unique_name, class: "chapter_thumbnail" %> + <%= link_to_path image_tag(page.headline_asset.upload.url(:medium), :alt => ""), page.node.unique_name, class: "chapter_thumbnail" %> <% end %> -
-

<%= link_to_path page.title, page.node.unique_name %>

- <% if page.abstract.present? %> -
<%= page.abstract %>
- <% end %> - <% if page.node.external_url.present? %> -
<%= link_to page.node.external_url, page.node.external_url, target: '_blank', rel: 'noopener' %>
- <% end %> - <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %> - <% if open_days.any? %> -
- <%= t(:open_days_label) %>: - <% open_days.each do |event| %> - <%= event_schedule_text(event) %> - <% end %> -
- <% end %> -

<%= sanitize page.body %>

-
+

<%= link_to_path page.title, page.node.unique_name %>

+ <% if page.abstract.present? %> +
<%= page.abstract %>
+ <% end %> + <% if page.node.external_url.present? %> +
<%= link_to page.node.external_url, page.node.external_url, target: '_blank', rel: 'noopener' %>
+ <% end %> + <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %> + <% if open_days.any? %> +
+ <%= t(:open_days_label) %>: + <% open_days.each do |event| %> + <%= event_schedule_text(event) %> + <% end %> +
+ <% end %> +

<%= sanitize page.body %>

diff --git a/public/stylesheets/ccc.css b/public/stylesheets/ccc.css index f018d2b2..9bd9f965 100644 --- a/public/stylesheets/ccc.css +++ b/public/stylesheets/ccc.css @@ -752,25 +752,30 @@ div.author_and_date { } .chapter_partial_layout { - display: flex; - gap: 12px; - align-items: flex-start; + display: flow-root; } .chapter_thumbnail { - flex-shrink: 0; + float: right; + margin: 0.5rem 0 8px 12px; } .chapter_thumbnail img { - width: 64px; - height: 64px; - object-fit: cover; + max-width: 150px; + height: auto; border-radius: 4px; display: block; } -.chapter_partial_content { - min-width: 0; +div#center_column .chapter_partial h2.headline { + border-top: none; + padding-top: 0; +} + +div#center_column .chapter_partial + .chapter_partial { + border-top: 1px solid color-mix(in srgb, CanvasText, Canvas 70%); + margin-top: 1.5rem; + padding-top: 1.5rem; } .article_partial_layout { diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index d7d8b9a6..2dd0759a 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -13,8 +13,8 @@ class UsersControllerTest < ActionController::TestCase login_as :aaron get :index assert_response :success - assert_select "button[type=submit]", I18n.t("users.user.deactivate") - assert_select "a", I18n.t("admin.common.show") + assert_select "button[type=submit][aria-label=?]", I18n.t("users.user.deactivate") + assert_select "a[aria-label=?]", I18n.t("admin.common.show") end test "get new when logged in as admin" do diff --git a/test/models/page_test.rb b/test/models/page_test.rb index 395b6315..b737e8b0 100644 --- a/test/models/page_test.rb +++ b/test/models/page_test.rb @@ -425,4 +425,17 @@ class PageTest < ActiveSupport::TestCase assert_includes names, "updates/inside-post" assert_not_includes names, "outside-post" end + + test "an aggregate can order by node slug" do + parent = Node.root.children.create!(:slug => "slug_order_parent") + %w[zulu alpha Mike].each do |slug| + node = parent.children.create!(:slug => slug) + node.reload.draft.update!(:title => "T-#{slug}", :tag_list => "slug-order-test") + node.publish_draft! + end + + names = Page.aggregate({ :tags => "slug-order-test", + :order_by => "slug" }).map { |p| p.node.slug } + assert_equal %w[alpha Mike zulu], names + end end -- cgit v1.3