From 4cc0338d3469ba8aa54e03247d91d3b52756000a Mon Sep 17 00:00:00 2001 From: MDreW Date: Wed, 24 Sep 2025 17:52:44 +0200 Subject: [PATCH 1/6] Added option aria-busy --- app/components/itacomp/turbo_frame_component.rb | 2 ++ .../turbo_frame_component/turbo_frame_component.html.erb | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/components/itacomp/turbo_frame_component.rb b/app/components/itacomp/turbo_frame_component.rb index dfd63a8..5aa5857 100644 --- a/app/components/itacomp/turbo_frame_component.rb +++ b/app/components/itacomp/turbo_frame_component.rb @@ -40,7 +40,9 @@ class TurboFrameComponent < BaseComponent # * * [Symbol], each key going as tag option # * yield optional turbo frame content def initialize(**keys) + @busy = keys[:href].present? && content.blank? @keys = keys + @keys[:aria] = {busy: true} if @busy end end end diff --git a/app/components/itacomp/turbo_frame_component/turbo_frame_component.html.erb b/app/components/itacomp/turbo_frame_component/turbo_frame_component.html.erb index fdbd888..e2759b0 100644 --- a/app/components/itacomp/turbo_frame_component/turbo_frame_component.html.erb +++ b/app/components/itacomp/turbo_frame_component/turbo_frame_component.html.erb @@ -1,7 +1,3 @@ <%= tag.turbo_frame **@keys do %> - <% if @keys[:href].present? && content.blank? %> - <%= ita_spinner t('.loading') %> - <% else %> - <%= content %> - <% end %> + <%= @busy ? ita_spinner(t('.loading')) : content %> <% end %> From a010014fed39075f7135758ffb47b49c9a36d473 Mon Sep 17 00:00:00 2001 From: MDreW Date: Wed, 24 Sep 2025 17:53:59 +0200 Subject: [PATCH 2/6] removed text option, only content is accepted --- app/components/itacomp/alert_component.rb | 7 +------ .../itacomp/alert_component/alert_component.html.erb | 2 +- test/components/itacomp/alert_component_test.rb | 7 +------ 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/app/components/itacomp/alert_component.rb b/app/components/itacomp/alert_component.rb index 6cfea9f..28256bb 100644 --- a/app/components/itacomp/alert_component.rb +++ b/app/components/itacomp/alert_component.rb @@ -6,9 +6,6 @@ module Itacomp # @example with no options # <%= render ItacompAlertComponent.new %> # - # @example with text as params - # <%= render ItacompAlertComponent.new('text') %> - # # @example with text as block # <%= render ItacompAlertComponent.new do %> # text @@ -31,19 +28,17 @@ module Itacomp # <%= render ItacompAlertComponent.new(id: 'my-id', data: {test: 'test'}) %> # class AlertComponent < BaseComponent - # @param [String] text content for alert component, default nil # @param [String,Sym] :type of alert, default 'primary' # @param [Boolean] :close if true is added close button # @param [String] :class add other class after "alsert alert-#{type}" classes # @param [Hash] **opts each other oprion is delegated to container tag # @yield [optional] turbo frame content - def initialize(text = nil, type: :primary, close: false, **opts) + def initialize(type: :primary, close: false, **opts) @close = close @opts = opts @opts[:class] = [ "alert", "alert-#{ITA_TYPES[type]}", @opts[:class] ] @opts[:class] << "alert-dismissible fade show" if close @opts[:role] = "alert" - @text = text end # @return html for close button if @close is true diff --git a/app/components/itacomp/alert_component/alert_component.html.erb b/app/components/itacomp/alert_component/alert_component.html.erb index 82b30ae..dfaa71a 100644 --- a/app/components/itacomp/alert_component/alert_component.html.erb +++ b/app/components/itacomp/alert_component/alert_component.html.erb @@ -1,4 +1,4 @@ <%= tag.div **@opts do %> - <%= content || @text%> + <%= content %> <%= close_button %> <% end %> diff --git a/test/components/itacomp/alert_component_test.rb b/test/components/itacomp/alert_component_test.rb index f992f70..733ec60 100644 --- a/test/components/itacomp/alert_component_test.rb +++ b/test/components/itacomp/alert_component_test.rb @@ -8,12 +8,7 @@ class Itacomp::AlertComponentTest < ViewComponent::TestCase assert_selector "div.alert.alert-primary[role='alert']", text: nil end - test "render text as params" do - render_inline Itacomp::AlertComponent.new("test") - assert_selector "div.alert.alert-primary[role='alert']", text: "test" - end - - test "render text as block" do + test "render with content" do render_inline Itacomp::AlertComponent.new.with_content("test") assert_selector "div.alert.alert-primary[role='alert']", text: "test" end From c04e0f12faad5a7c5193634f56522960c52d289e Mon Sep 17 00:00:00 2001 From: MDreW Date: Wed, 24 Sep 2025 17:54:35 +0200 Subject: [PATCH 3/6] removed text option --- test/components/previews/itacomp/alert_component_preview.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/previews/itacomp/alert_component_preview.rb b/test/components/previews/itacomp/alert_component_preview.rb index 01d9040..031da4f 100644 --- a/test/components/previews/itacomp/alert_component_preview.rb +++ b/test/components/previews/itacomp/alert_component_preview.rb @@ -3,7 +3,7 @@ module Itacomp class AlertComponentPreview < ViewComponent::Preview def default - render(AlertComponent.new(text: "text", type: "type", close: "close")) + render(AlertComponent.new( type: "primary", close: true)) end end end From 73c377c0a5a77a03d56750cab9659146f982cf35 Mon Sep 17 00:00:00 2001 From: MDreW Date: Wed, 24 Sep 2025 20:26:12 +0200 Subject: [PATCH 4/6] add notification component --- .../itacomp/notification_component.rb | 44 +++++++++++++++++++ .../notification_component.html.erb | 10 +++++ .../notification_component.yml | 7 +++ .../itacomp/notification_component_test.rb | 23 ++++++++++ .../itacomp/notification_component_preview.rb | 9 ++++ 5 files changed, 93 insertions(+) create mode 100644 app/components/itacomp/notification_component.rb create mode 100644 app/components/itacomp/notification_component/notification_component.html.erb create mode 100644 app/components/itacomp/notification_component/notification_component.yml create mode 100644 test/components/itacomp/notification_component_test.rb create mode 100644 test/components/previews/itacomp/notification_component_preview.rb diff --git a/app/components/itacomp/notification_component.rb b/app/components/itacomp/notification_component.rb new file mode 100644 index 0000000..3274708 --- /dev/null +++ b/app/components/itacomp/notification_component.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Itacomp + # make a strcture for [notification component](https://italia.github.io/bootstrap-italia/docs/componenti/notification/) + # ==== Example + # With only required title (default show and dismissable) + # <%= render Itacomp::NotificationComponent.new(title: 'test') %> + # + # Mo dismissable and no show + # <%= render Itacomp::NotificationComponent.new(title: 'test', dismissable: false, show: false) %> + # + class NotificationComponent < BaseComponent + # Initialize notification component + # + # ==== Options + # * title [String], mandatory, default: nil, Notification title; + # * show [Boolean], default true, if true set notification visible + # * icon [String] default nil if present is add nontification icon + # * dismissable [Boolean] default true if true add dismiss button + # * **opts each key is delegated as tag options. Default: {class: 'notification', id: Time.now.strftime("%H%M%S%L"), aria: {role: 'alert'}} + # * yield notification content (content is automarically added in a `p` tag) + def initialize(title:, show: true, icon: nil , dismissable: true, **opts) + opts[:class] = ["notification", opts[:class]] + opts[:class] << 'with-icon' if icon.present? + opts[:class] << 'dismissable' if dismissable == true + opts[:id] = "not-#{Time.now.strftime("%H%M%S%L")}" if opts[:id].blank? + opts[:aria] = {labelledby: "#{opts[:id]}-title"} if opts[:aria].blank? + opts[:role] = 'alert' + if show == true + opts[:class] << "show" + opts[:style] = "display: block;" + end + @title = title + @icon = icon + @dismissable = dismissable + @opts = opts + end + + # return full title: text and optional icon + def full_title + @icon.present? ? safe_join([ita_icon(@icon), @title]) : @title + end + end +end diff --git a/app/components/itacomp/notification_component/notification_component.html.erb b/app/components/itacomp/notification_component/notification_component.html.erb new file mode 100644 index 0000000..4b17f4e --- /dev/null +++ b/app/components/itacomp/notification_component/notification_component.html.erb @@ -0,0 +1,10 @@ +<%= tag.div **@opts do %> + <%= tag.h2 full_title, id: @opts[:aria][:labelledby], class: 'h5' %> + <%= tag.p content if content.present? %> + <% if @dismissable == true %> + <%= tag.button class: "btn notification-close", data: {bs_toggle: "notification", bs_target: "##{@opts[:id]}"} do %> + <%= ita_icon "it-close" %> + <%= ita_visually_hidden "#{t(".close")} #{@title}" %> + <% end %> + <% end %> +<% end %> diff --git a/app/components/itacomp/notification_component/notification_component.yml b/app/components/itacomp/notification_component/notification_component.yml new file mode 100644 index 0000000..1be780c --- /dev/null +++ b/app/components/itacomp/notification_component/notification_component.yml @@ -0,0 +1,7 @@ +--- +en: + close: "close notification:" +fr: + close: "fermer la notification:" +it: + close: "Chiudi la notifica:" diff --git a/test/components/itacomp/notification_component_test.rb b/test/components/itacomp/notification_component_test.rb new file mode 100644 index 0000000..65cb75d --- /dev/null +++ b/test/components/itacomp/notification_component_test.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "test_helper" + +class Itacomp::NotificationComponentTest < ViewComponent::TestCase + test "only required title" do + render_inline Itacomp::NotificationComponent.new(title: 'test') + assert_selector "div.notification.dismissable.show[role='alert']", text: 'test' + assert_selector "div.notification.dismissable.show h2.h5", text: 'test' + assert_selector "div.notification.dismissable.show button.btn.notification-close svg.icon" + assert_selector "div.notification.dismissable.show button.btn.notification-close span.visually-hidden", text: 'close notification: test' + end + + test "with id can be set ids and aria-labelledid" do + render_inline Itacomp::NotificationComponent.new(title: 'test', id: 'test') + assert_selector "div.notification.dismissable.show#test[aria-labelledby='test-title'] h2.h5#test-title", text: 'test' + end + + test "can render with icon" do + render_inline Itacomp::NotificationComponent.new(title: 'test', icon: 'test') + assert_selector "div.notification.dismissable.show.with-icon h2.h5 svg.icon" + end +end diff --git a/test/components/previews/itacomp/notification_component_preview.rb b/test/components/previews/itacomp/notification_component_preview.rb new file mode 100644 index 0000000..26c396f --- /dev/null +++ b/test/components/previews/itacomp/notification_component_preview.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Itacomp + class NotificationComponentPreview < ViewComponent::Preview + def default + render(NotificationComponent.new(title: 'text')) + end + end +end From 4b6bebbb7b762929ffdc412abb1c9ee5c7f88246 Mon Sep 17 00:00:00 2001 From: MDreW Date: Wed, 24 Sep 2025 20:33:39 +0200 Subject: [PATCH 5/6] Add comment --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e56dd8..dd5b657 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,15 @@ Itacomp is a [View Component](https://viewcomponent.org/) and [Helper](https://a * [ita_progress](app/helpers/itacomp/common_helper.rb) * [ita_spinner](app/helpers/itacomp/common_helper.rb) * [ita_visually_hidden](app/helpers/itacomp/common_helper.rb) +* [ita_size](app/helpers/itacomp/common_helper.rb) +* [ita_bg](app/helpers/itacomp/common_helper.rb) +* [ita_text](app/helpers/itacomp/common_helper.rb) ### Components -* [TurboFrameComponent](app/components/itacomp/turbo_frame_component.rb) * [AlertComponent](app/components/itacomp/alert_component.rb) +* [AvatorComponent](app/components/itacomp/avator_component.rb) +* [NotificationComponent](app/components/itacomp/notification_component.rb) +* [TurboFrameComponent](app/components/itacomp/turbo_frame_component.rb) ## Installation Itacomp is in a rapid development phase and the gem will not be released on Rubygem until the [first project](https://github.com/orgs/isprambiente/projects/1) will be completed. From 4107dc6ec5264085a5f091c52d222e07a496fe91 Mon Sep 17 00:00:00 2001 From: MDreW Date: Wed, 24 Sep 2025 20:37:18 +0200 Subject: [PATCH 6/6] rubocop fix --- app/components/itacomp/avatar_component.rb | 8 ++++---- .../itacomp/notification_component.rb | 14 +++++++------- .../itacomp/turbo_frame_component.rb | 4 ++-- app/helpers/itacomp/common_helper.rb | 6 +++--- lib/itacomp.rb | 4 ++-- .../itacomp/avatar_component_test.rb | 18 +++++++++--------- .../itacomp/notification_component_test.rb | 14 +++++++------- .../itacomp/alert_component_preview.rb | 2 +- .../itacomp/notification_component_preview.rb | 2 +- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/app/components/itacomp/avatar_component.rb b/app/components/itacomp/avatar_component.rb index fcd9c48..6b6970b 100644 --- a/app/components/itacomp/avatar_component.rb +++ b/app/components/itacomp/avatar_component.rb @@ -4,7 +4,7 @@ module Itacomp # Make a bootstrap-italia compatible [Avatar](https://italia.github.io/bootstrap-italia/docs/componenti/avatar/) tag. # # ==== Example - # With no params + # With no params # <%= render Itacomp::Avatar.new %> #
# With content @@ -33,7 +33,7 @@ module Itacomp #
a
# With other options # <%= render itacomp::avatar(id: "my_avatar", data: {turbo_frame: 'main'}).new.with_content('a') %> - #
a
+ #
a
class AvatarComponent < BaseComponent # Initialize avatar component # @@ -43,8 +43,8 @@ class AvatarComponent < BaseComponent # * class [String,Array] default nil if present is add class style after avatar # * **opts each key is delegated as tag options # * yield avatar content - def initialize(size: nil, bg: nil, class: nil ,**opts) - opts[:class] = ["avatar", opts[:class]] + def initialize(size: nil, bg: nil, class: nil, **opts) + opts[:class] = [ "avatar", opts[:class] ] opts[:class] << ita_size(size) if size.present? opts[:class] << avatar_bg(bg) if bg.present? @opts = opts diff --git a/app/components/itacomp/notification_component.rb b/app/components/itacomp/notification_component.rb index 3274708..f79da83 100644 --- a/app/components/itacomp/notification_component.rb +++ b/app/components/itacomp/notification_component.rb @@ -19,13 +19,13 @@ class NotificationComponent < BaseComponent # * dismissable [Boolean] default true if true add dismiss button # * **opts each key is delegated as tag options. Default: {class: 'notification', id: Time.now.strftime("%H%M%S%L"), aria: {role: 'alert'}} # * yield notification content (content is automarically added in a `p` tag) - def initialize(title:, show: true, icon: nil , dismissable: true, **opts) - opts[:class] = ["notification", opts[:class]] - opts[:class] << 'with-icon' if icon.present? - opts[:class] << 'dismissable' if dismissable == true + def initialize(title:, show: true, icon: nil, dismissable: true, **opts) + opts[:class] = [ "notification", opts[:class] ] + opts[:class] << "with-icon" if icon.present? + opts[:class] << "dismissable" if dismissable == true opts[:id] = "not-#{Time.now.strftime("%H%M%S%L")}" if opts[:id].blank? - opts[:aria] = {labelledby: "#{opts[:id]}-title"} if opts[:aria].blank? - opts[:role] = 'alert' + opts[:aria] = { labelledby: "#{opts[:id]}-title" } if opts[:aria].blank? + opts[:role] = "alert" if show == true opts[:class] << "show" opts[:style] = "display: block;" @@ -38,7 +38,7 @@ def initialize(title:, show: true, icon: nil , dismissable: true, **opts) # return full title: text and optional icon def full_title - @icon.present? ? safe_join([ita_icon(@icon), @title]) : @title + @icon.present? ? safe_join([ ita_icon(@icon), @title ]) : @title end end end diff --git a/app/components/itacomp/turbo_frame_component.rb b/app/components/itacomp/turbo_frame_component.rb index 5aa5857..c070496 100644 --- a/app/components/itacomp/turbo_frame_component.rb +++ b/app/components/itacomp/turbo_frame_component.rb @@ -3,7 +3,7 @@ module Itacomp # Make a bootstrap-italia compatible structure for a [turbo Frame](https://turbo.hotwired.dev/handbook/frames) tag. # - # ==== Example + # ==== Example # Empty turbo frame # = render Itacomp::TurboFrameComponent.new # @@ -42,7 +42,7 @@ class TurboFrameComponent < BaseComponent def initialize(**keys) @busy = keys[:href].present? && content.blank? @keys = keys - @keys[:aria] = {busy: true} if @busy + @keys[:aria] = { busy: true } if @busy end end end diff --git a/app/helpers/itacomp/common_helper.rb b/app/helpers/itacomp/common_helper.rb index 30c137c..f018589 100644 --- a/app/helpers/itacomp/common_helper.rb +++ b/app/helpers/itacomp/common_helper.rb @@ -148,7 +148,7 @@ def ita_progress(value = nil, type: nil) # with invalid params # ira_size(:other) # # => "size-md" - def ita_size(type=nil) + def ita_size(type = nil) "size-#{ITA_SIZES[type]}" end @@ -167,7 +167,7 @@ def ita_size(type=nil) # with invalid params # ira_size(:other) # # => "size-primary" - def ita_bg(type=nil) + def ita_bg(type = nil) "bg-#{ITA_TYPES[type]}" end @@ -186,7 +186,7 @@ def ita_bg(type=nil) # with invalid params # ira_text(:other) # # => "text-primary" - def ita_text(type=nil) + def ita_text(type = nil) "text-#{ITA_TYPES[type]}" end end diff --git a/lib/itacomp.rb b/lib/itacomp.rb index a0e54e9..d77e1e0 100644 --- a/lib/itacomp.rb +++ b/lib/itacomp.rb @@ -3,6 +3,6 @@ module Itacomp # this constant define available bootstrap-italia type - ITA_TYPES = Hash.new { :primary }.with_indifferent_access.merge(primary: "primary", secondary: "secondary", info: "info", success: "success", warning: "warning", danger: "danger", white: "white", dark: "dark", black: 'black') - ITA_SIZES = Hash.new { :md}.with_indifferent_access.merge(xs: "xs", sm: "sm", md: "md", lg: "md", xl: "xl", xxl: "xxl") + ITA_TYPES = Hash.new { :primary }.with_indifferent_access.merge(primary: "primary", secondary: "secondary", info: "info", success: "success", warning: "warning", danger: "danger", white: "white", dark: "dark", black: "black") + ITA_SIZES = Hash.new { :md }.with_indifferent_access.merge(xs: "xs", sm: "sm", md: "md", lg: "md", xl: "xl", xxl: "xxl") end diff --git a/test/components/itacomp/avatar_component_test.rb b/test/components/itacomp/avatar_component_test.rb index b4a710c..f8f389c 100644 --- a/test/components/itacomp/avatar_component_test.rb +++ b/test/components/itacomp/avatar_component_test.rb @@ -9,27 +9,27 @@ class Itacomp::AvatarComponentTest < ViewComponent::TestCase end test "avatar with content" do - render_inline Itacomp::AvatarComponent.new.with_content('test') - assert_selector "div.avatar", text: 'test' + render_inline Itacomp::AvatarComponent.new.with_content("test") + assert_selector "div.avatar", text: "test" end test "set size" do - render_inline Itacomp::AvatarComponent.new(size: 'md') - assert_selector "div.avatar.size-md", text: nil + render_inline Itacomp::AvatarComponent.new(size: "md") + assert_selector "div.avatar.size-md", text: nil end test "set bg" do - render_inline Itacomp::AvatarComponent.new(bg: 'md') - assert_selector "div.avatar.avatar-primary", text: nil + render_inline Itacomp::AvatarComponent.new(bg: "md") + assert_selector "div.avatar.avatar-primary", text: nil end test "add id" do - render_inline Itacomp::AvatarComponent.new(id: 'test') + render_inline Itacomp::AvatarComponent.new(id: "test") assert_selector "div#test.avatar", text: nil end test "add data" do - render_inline Itacomp::AvatarComponent.new(data: {test: 'tost'}) - assert_selector "div.avatar[data-test='tost']", text: nil + render_inline Itacomp::AvatarComponent.new(data: { test: "tost" }) + assert_selector "div.avatar[data-test='tost']", text: nil end end diff --git a/test/components/itacomp/notification_component_test.rb b/test/components/itacomp/notification_component_test.rb index 65cb75d..b3ec466 100644 --- a/test/components/itacomp/notification_component_test.rb +++ b/test/components/itacomp/notification_component_test.rb @@ -4,20 +4,20 @@ class Itacomp::NotificationComponentTest < ViewComponent::TestCase test "only required title" do - render_inline Itacomp::NotificationComponent.new(title: 'test') - assert_selector "div.notification.dismissable.show[role='alert']", text: 'test' - assert_selector "div.notification.dismissable.show h2.h5", text: 'test' + render_inline Itacomp::NotificationComponent.new(title: "test") + assert_selector "div.notification.dismissable.show[role='alert']", text: "test" + assert_selector "div.notification.dismissable.show h2.h5", text: "test" assert_selector "div.notification.dismissable.show button.btn.notification-close svg.icon" - assert_selector "div.notification.dismissable.show button.btn.notification-close span.visually-hidden", text: 'close notification: test' + assert_selector "div.notification.dismissable.show button.btn.notification-close span.visually-hidden", text: "close notification: test" end test "with id can be set ids and aria-labelledid" do - render_inline Itacomp::NotificationComponent.new(title: 'test', id: 'test') - assert_selector "div.notification.dismissable.show#test[aria-labelledby='test-title'] h2.h5#test-title", text: 'test' + render_inline Itacomp::NotificationComponent.new(title: "test", id: "test") + assert_selector "div.notification.dismissable.show#test[aria-labelledby='test-title'] h2.h5#test-title", text: "test" end test "can render with icon" do - render_inline Itacomp::NotificationComponent.new(title: 'test', icon: 'test') + render_inline Itacomp::NotificationComponent.new(title: "test", icon: "test") assert_selector "div.notification.dismissable.show.with-icon h2.h5 svg.icon" end end diff --git a/test/components/previews/itacomp/alert_component_preview.rb b/test/components/previews/itacomp/alert_component_preview.rb index 031da4f..6b47088 100644 --- a/test/components/previews/itacomp/alert_component_preview.rb +++ b/test/components/previews/itacomp/alert_component_preview.rb @@ -3,7 +3,7 @@ module Itacomp class AlertComponentPreview < ViewComponent::Preview def default - render(AlertComponent.new( type: "primary", close: true)) + render(AlertComponent.new(type: "primary", close: true)) end end end diff --git a/test/components/previews/itacomp/notification_component_preview.rb b/test/components/previews/itacomp/notification_component_preview.rb index 26c396f..8f0cd2d 100644 --- a/test/components/previews/itacomp/notification_component_preview.rb +++ b/test/components/previews/itacomp/notification_component_preview.rb @@ -3,7 +3,7 @@ module Itacomp class NotificationComponentPreview < ViewComponent::Preview def default - render(NotificationComponent.new(title: 'text')) + render(NotificationComponent.new(title: "text")) end end end