Skip to content

Commit

Permalink
Handle color modes in status button
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverguenther committed Mar 6, 2025
1 parent 1fb6c87 commit b712463
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 88 deletions.
12 changes: 1 addition & 11 deletions app/components/op_primer/status_button_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,7 @@
item.with_leading_visual_icon(icon: option.icon) if option.icon
item.with_description.with_content(option.description) if option.description

flex_layout(align_items: :center) do |flex|
if option.icon.nil? && option.color
flex.with_column(mr: 1) do
helpers.icon_for_color(option.color, style: "display: block")
end
end

flex.with_column do
render(Primer::Beta::Text.new) { option.name }
end
end
render(Primer::Beta::Text.new) { option.name }
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/components/op_primer/status_button_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
module OpPrimer
class StatusButtonComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include Primer::ClassNameHelper

def initialize(current_status:, items:, readonly: false, disabled: false, button_arguments: {}, menu_arguments: {})
super
Expand Down Expand Up @@ -70,8 +71,7 @@ def button_arguments
disabled: disabled?,
aria: {
label: title
},
style: @current_status.color&.color_styles_css
}
}.compact.deep_merge(@button_arguments)
end
end
Expand Down
6 changes: 3 additions & 3 deletions app/components/op_primer/status_button_option.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@

module OpPrimer
class StatusButtonOption # rubocop:disable OpenProject/AddPreviewForViewComponent
attr_reader :name, :color, :icon, :item_arguments, :description
attr_reader :name, :id, :icon, :item_arguments, :description

def initialize(name:, color: nil, icon: nil, description: nil, **item_arguments)
def initialize(name:, id: nil, icon: nil, description: nil, **item_arguments)
@name = name
@color = color
@id = id
@icon = icon
@description = description
@item_arguments = item_arguments
Expand Down
30 changes: 28 additions & 2 deletions app/components/work_packages/status_button_component.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
# frozen_string_literal: true

class WorkPackages::StatusButtonComponent < OpPrimer::StatusButtonComponent
include Primer::ClassNameHelper
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class WorkPackages::StatusButtonComponent < OpPrimer::StatusButtonComponent
attr_reader :work_package, :user

def initialize(work_package:, user:, readonly: false, button_arguments: {}, menu_arguments: {})
Expand Down
37 changes: 21 additions & 16 deletions app/helpers/colors_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,27 @@ def color_css
#
# Styles to display the color of attributes (type, status etc.) for example in the WP view
##
def resource_color_css(name, scope, inline_foreground: false)
def resources_scope_color_css(name, scope, inline_foreground: false)
scope.includes(:color).find_each do |entry|
color = entry.color
resource_color_css(name, entry, inline_foreground: inline_foreground)
end
end

if color.nil?
concat ".#{hl_inline_class(name, entry)}::before { display: none }\n"
next
end
def resource_color_css(name, entry, inline_foreground: false)
color = entry.color

if inline_foreground
set_foreground_colors_for(class_name: ".#{hl_inline_class(name, entry)}", color:)
else
set_background_colors_for(class_name: ".#{hl_inline_class(name, entry)}::before", color:)
end
if color.nil?
concat ".#{hl_inline_class(name, entry)}::before { display: none }\n"
return
end

set_background_colors_for(class_name: ".#{hl_background_class(name, entry)}", color:)
if inline_foreground
set_foreground_colors_for(class_name: ".#{hl_inline_class(name, entry)}", color:)
else
set_background_colors_for(class_name: ".#{hl_inline_class(name, entry)}::before", color:)
end

set_background_colors_for(class_name: ".#{hl_background_class(name, entry)}", color:)
end

def hl_inline_class(name, model)
Expand Down Expand Up @@ -171,10 +175,10 @@ def highlighted_background_light
mode = User.current.pref.theme

style += if mode == "light_high_contrast"
"border: 1px solid hsla(var(--color-h), calc(var(--color-s) * 1%), calc((var(--color-l) - 75) * 1%), 1) !important;"
else
"border: 1px solid hsl(var(--color-h), calc(var(--color-s) * 1%), calc((var(--color-l) - 15) * 1%)) !important;"
end
"border: 1px solid hsla(var(--color-h), calc(var(--color-s) * 1%), calc((var(--color-l) - 75) * 1%), 1) !important;"

Check notice on line 178 in app/helpers/colors_helper.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] app/helpers/colors_helper.rb#L178 <Layout/IndentationWidth>

Use 2 (not -7) spaces for indentation.
Raw output
app/helpers/colors_helper.rb:178:7: C: Layout/IndentationWidth: Use 2 (not -7) spaces for indentation.
else

Check notice on line 179 in app/helpers/colors_helper.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] app/helpers/colors_helper.rb#L179 <Layout/ElseAlignment>

Align `else` with `if`.
Raw output
app/helpers/colors_helper.rb:179:5: C: Layout/ElseAlignment: Align `else` with `if`.
"border: 1px solid hsl(var(--color-h), calc(var(--color-s) * 1%), calc((var(--color-l) - 15) * 1%)) !important;"
end

Check warning on line 181 in app/helpers/colors_helper.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] app/helpers/colors_helper.rb#L181 <Layout/EndAlignment>

`end` at 181, 4 is not aligned with `if` at 177, 13.
Raw output
app/helpers/colors_helper.rb:181:5: W: Layout/EndAlignment: `end` at 181, 4 is not aligned with `if` at 177, 13.

style
end
Expand All @@ -192,5 +196,6 @@ def highlighted_foreground_light
"color: hsla(var(--color-h), calc(var(--color-s) * 1%), calc((var(--color-l) - (var(--color-l) * 0.22)) * 1%), 1) !important;"
end
end

# rubocop:enable Layout/LineLength
end
12 changes: 8 additions & 4 deletions app/views/highlighting/styles.css.erb
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<%# Highlightable resources %>
<%= resource_color_css("status", ::Status) %>
<%= resource_color_css("priority", ::IssuePriority) %>
<%= resource_color_css("type", ::Type, inline_foreground: true) %>
<%= resources_scope_color_css("status", ::Status) %>
<%= resources_scope_color_css("priority", ::IssuePriority) %>
<%= resources_scope_color_css("type", ::Type, inline_foreground: true) %>
<%# Color coded icons %>
<%= resource_color_css("life_cycle_step_definition", Project::LifeCycleStepDefinition, inline_foreground: true) %>
<%= resources_scope_color_css("life_cycle_step_definition", Project::LifeCycleStepDefinition, inline_foreground: true) %>

<% Meetings::Statuses::AVAILABLE.each do |meeting_status| %>
<%= resource_color_css("meeting_status", meeting_status) %>
<% end %>

<%= color_css %>

Expand Down
24 changes: 15 additions & 9 deletions lookbook/previews/op_primer/status_button_component_preview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,41 @@ class StatusButtonComponentPreview < ViewComponent::Preview
# @param size [Symbol] select [small, medium, large]
def playground(readonly: false, disabled: false, size: :medium)
status = OpPrimer::StatusButtonOption.new(name: "Open",
color: FactoryBot.build(:color_maroon),
tag: :a,
content_arguments: {
classes: "__hl_inline_meeting_status_open",

Check notice on line 15 in lookbook/previews/op_primer/status_button_component_preview.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] lookbook/previews/op_primer/status_button_component_preview.rb#L15 <Style/TrailingCommaInHashLiteral>

Avoid comma after the last item of a hash.
Raw output
lookbook/previews/op_primer/status_button_component_preview.rb:15:93: C: Style/TrailingCommaInHashLiteral: Avoid comma after the last item of a hash.
},
href: "/some/test")
items = [
status,
OpPrimer::StatusButtonOption.new(name: "Closed",
color: FactoryBot.build(:color_green),
tag: :a,
content_arguments: {
classes: "__hl_inline_meeting_status_closed",

Check notice on line 23 in lookbook/previews/op_primer/status_button_component_preview.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] lookbook/previews/op_primer/status_button_component_preview.rb#L23 <Style/TrailingCommaInHashLiteral>

Avoid comma after the last item of a hash.
Raw output
lookbook/previews/op_primer/status_button_component_preview.rb:23:88: C: Style/TrailingCommaInHashLiteral: Avoid comma after the last item of a hash.
},
href: "/some/other/action")
]
component = OpPrimer::StatusButtonComponent.new(current_status: status,
items:,
readonly:,
disabled:,
button_arguments: { title: "Edit", size: })
button_arguments: {
title: "Edit",
size:,
classes: "__hl_background_meeting_status_open",

Check notice on line 34 in lookbook/previews/op_primer/status_button_component_preview.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] lookbook/previews/op_primer/status_button_component_preview.rb#L34 <Style/TrailingCommaInHashLiteral>

Avoid comma after the last item of a hash.
Raw output
lookbook/previews/op_primer/status_button_component_preview.rb:34:103: C: Style/TrailingCommaInHashLiteral: Avoid comma after the last item of a hash.
})

render(component)
end

# See the [component documentation](/lookbook/pages/components/status_button) for more details.
# @display min_height 200px
def with_icon(size: :medium)
status = OpPrimer::StatusButtonOption.new(name: "Open", icon: :unlock, color: Color.new(hexcode: "#FF0000"))
status = OpPrimer::StatusButtonOption.new(name: "Open", icon: :unlock)

items = [
status,
OpPrimer::StatusButtonOption.new(name: "Closed", icon: :lock, color: Color.new(hexcode: "#00FF00"))
OpPrimer::StatusButtonOption.new(name: "Closed", icon: :lock)
]

component = OpPrimer::StatusButtonComponent.new(current_status: status,
Expand All @@ -52,15 +60,13 @@ def with_icon(size: :medium)
def with_description(size: :medium)
status = OpPrimer::StatusButtonOption.new(name: "Open",
icon: :unlock,
description: "The status is open",
color: Color.new(hexcode: "#FF0000"))
description: "The status is open")

items = [
status,
OpPrimer::StatusButtonOption.new(name: "Closed",
icon: :lock,
description: "The status is closed",
color: Color.new(hexcode: "#00FF00"))
description: "The status is closed")
]

component = OpPrimer::StatusButtonComponent.new(current_status: status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,19 @@ def initialize(meeting:, size: :medium)
end

def call
render(OpPrimer::StatusButtonComponent.new(current_status: current_status,
items: [open_status, in_progress_status, closed_status],
readonly: !edit_enabled?,
disabled: !edit_enabled?,
button_arguments: { title: t("label_meeting_state"), size: @size }))
render(
OpPrimer::StatusButtonComponent.new(
current_status: current_status,
items: [open_status, in_progress_status, closed_status],
readonly: !edit_enabled?,
disabled: !edit_enabled?,
button_arguments: {
classes: helpers.hl_background_class("meeting_status", current_status),
title: t("label_meeting_state"),
size: @size
}
)
)
end

private
Expand All @@ -68,8 +76,8 @@ def current_status
end

def open_status
OpPrimer::StatusButtonOption.new(name: t("label_meeting_state_open"),
color: Color.new(hexcode: "#1F883D"),
OpPrimer::StatusButtonOption.new(id: Meetings::Statuses::OPEN.id,
name: t("label_meeting_state_open"),
icon: :"issue-opened",
tag: :a,
description: t("text_meeting_open_dropdown_description"),
Expand All @@ -80,8 +88,8 @@ def open_status
end

def in_progress_status
OpPrimer::StatusButtonOption.new(name: t("label_meeting_state_in_progress"),
color: Color.new(hexcode: "#9A6700"),
OpPrimer::StatusButtonOption.new(id: Meetings::Statuses::IN_PROGRESS.id,
name: t("label_meeting_state_in_progress"),
icon: :play,
tag: :a,
description: t("text_meeting_in_progress_dropdown_description"),
Expand All @@ -92,8 +100,8 @@ def in_progress_status
end

def closed_status
OpPrimer::StatusButtonOption.new(name: t("label_meeting_state_closed"),
color: Color.new(hexcode: "#6E7781 "),
OpPrimer::StatusButtonOption.new(id: Meetings::Statuses::CLOSED.id,
name: t("label_meeting_state_closed"),
icon: :"issue-closed",
tag: :a,
description: t("text_meeting_closed_dropdown_description"),
Expand Down
45 changes: 45 additions & 0 deletions modules/meeting/app/constants/meetings/statuses.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Meetings
module Statuses
RECORD = Struct.new(:id, :color, keyword_init: true)

OPEN = RECORD.new(id: "open", color: Color.new(hexcode: "#1F883D"))
IN_PROGRESS = RECORD.new(id: "in_progress", color: Color.new(hexcode: "#9A6700"))
CLOSED = RECORD.new(id: "closed", color: Color.new(hexcode: "#565c63"))

AVAILABLE = [
OPEN,
IN_PROGRESS,
CLOSED
].freeze
end
end
30 changes: 0 additions & 30 deletions spec/components/op_primer/status_button_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,36 +85,6 @@
end
end

context "when rendering with color status" do
let(:current_status) do
OpPrimer::StatusButtonOption.new(
name: "High Priority",
icon: nil,
color: Color.new(hexcode: "#FF0000")
)
end

let(:items) do
[
OpPrimer::StatusButtonOption.new(
name: "Low Priority",
icon: nil,
color: Color.new(hexcode: "#00FF00")
)
]
end

it "renders the status with color styles" do
render_inline(component)

expect(page).to have_css("[style*='background-color: #FF0000']")
expect(page).to have_text("High Priority")

expect(page).to have_css("[style*='background-color: #00FF00']", visible: :all)
expect(page).to have_text("Low Priority")
end
end

context "when readonly" do
let(:readonly) { true }

Expand Down

0 comments on commit b712463

Please sign in to comment.