From 02e8746afb3808a547d42625e60be7b323cc103e Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 15:18:13 +0000 Subject: [PATCH] Replace the unicode toggle with Redmine's sprite icon Fixes #3 The trigger used the unicode characters U+25B6 / U+25BC, which render differently across browsers and platforms and do not follow the theme. Redmine 6 ships an icon sprite; 'angle-right' is the shape the core uses for the same purpose. The icon is now rendered once in the partial and the state is expressed purely by the existing css class: `.trigger.opened svg` is rotated by 90 degrees. JavaScript no longer rewrites the element's content, so the class is the single source of truth. That also fixes a latent inconsistency: when a level was collapsed, the nested triggers below it had their glyph replaced but kept the `opened` class. They now get `closed` like the element the user actually clicked, so a subsequent click on them behaves as expected instead of collapsing something that already looks collapsed. `slides.js` shrinks by four lines and no longer knows about presentation. --- app/views/workloads/_trigger.erb | 6 ++++-- assets/javascripts/slides.js | 6 +----- assets/stylesheets/style.css | 9 +++++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/views/workloads/_trigger.erb b/app/views/workloads/_trigger.erb index 8916689..4ab231c 100644 --- a/app/views/workloads/_trigger.erb +++ b/app/views/workloads/_trigger.erb @@ -3,7 +3,9 @@ # Parameters: # trigger_for: set as "data-for"-attribute # -# ▶ is a right-pointing filled triangle. +# The icon is rendered once as 'angle-right'. The opened state is expressed by +# the 'opened' css class, which rotates it by 90 degrees. Do not swap the icon +# in JavaScript; the class is the single source of truth for the state. %> - +<%= sprite_icon('angle-right') %> diff --git a/assets/javascripts/slides.js b/assets/javascripts/slides.js index 9fbe50e..c922ed9 100644 --- a/assets/javascripts/slides.js +++ b/assets/javascripts/slides.js @@ -6,8 +6,6 @@ $(document).ready(function() { $('.trigger').click(function() { - var OPENED = '▼' - var CLOSED = '▶' $(this).toggleClass('closed opened'); identifier = $(this).attr('data-for'); @@ -44,7 +42,6 @@ $(document).ready(function() { $(this).show(); // but keep its 'children' closed if any $(this).siblings('.invisible-issues-summary.' + identifierClasses).show(); }); - $(this).html(OPENED); } else { lowerHierarchieLevelClasses = bottomUpHierarchieChain.get(currentHierarchieLevel); @@ -54,11 +51,10 @@ $(document).ready(function() { $(css).hide(); $(css).siblings('.invisible-issues-summary.' + identifierClasses).hide(); currentHierarchieLevel = $(css).find('span.trigger.opened'); - currentHierarchieLevel.html(CLOSED); + currentHierarchieLevel.removeClass('opened').addClass('closed'); currentHierarchieLevel.siblings('dl').hide(); }) $(this).siblings().hide(); - $(this).html(CLOSED); } }); }); diff --git a/assets/stylesheets/style.css b/assets/stylesheets/style.css index 61504d8..4b7231e 100644 --- a/assets/stylesheets/style.css +++ b/assets/stylesheets/style.css @@ -146,6 +146,15 @@ margin-right: 4px; } +.controller-workloads .data .trigger svg { + vertical-align: middle; + transition: transform 0.15s ease-in-out; +} + +.controller-workloads .data .trigger.opened svg { + transform: rotate(90deg); +} + .controller-workloads table dt.mt-5, .controller-workloads table dd.mt-5 { margin-top: 5px;