fluxbit_view_components 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -0
- data/app/assets/javascripts/fluxbit_view_components/assigner_controller.js +49 -0
- data/app/assets/javascripts/fluxbit_view_components/auto_submit_controller.js +39 -0
- data/app/assets/javascripts/fluxbit_view_components/drawer_controller.js +135 -0
- data/app/assets/javascripts/fluxbit_view_components/index.js +56 -0
- data/app/assets/javascripts/fluxbit_view_components/method_link_controller.js +143 -0
- data/app/assets/javascripts/fluxbit_view_components/modal_controller.js +118 -0
- data/app/assets/javascripts/fluxbit_view_components/password_controller.js +170 -0
- data/app/assets/javascripts/fluxbit_view_components/progress_controller.js +374 -0
- data/app/assets/javascripts/fluxbit_view_components/row_click_controller.js +32 -0
- data/app/assets/javascripts/fluxbit_view_components/select_all_controller.js +122 -0
- data/app/assets/javascripts/fluxbit_view_components/spinner_percent_controller.js +174 -0
- data/app/assets/javascripts/fluxbit_view_components/theme_button_controller.js +90 -0
- data/app/assets/javascripts/fluxbit_view_components.js +1175 -0
- data/app/components/fluxbit/accordion_component.rb +125 -0
- data/app/components/fluxbit/alert_component.rb +8 -8
- data/app/components/fluxbit/avatar_component.rb +11 -12
- data/app/components/fluxbit/avatar_group_component.rb +1 -1
- data/app/components/fluxbit/badge_component.rb +8 -7
- data/app/components/fluxbit/banner_component.rb +139 -0
- data/app/components/fluxbit/bottom_navigation_component.rb +437 -0
- data/app/components/fluxbit/breadcrumb_component.rb +66 -0
- data/app/components/fluxbit/button_component.rb +39 -11
- data/app/components/fluxbit/button_group_component.rb +1 -1
- data/app/components/fluxbit/card_component.rb +26 -23
- data/app/components/fluxbit/carousel_component.rb +154 -0
- data/app/components/fluxbit/component.rb +24 -3
- data/app/components/fluxbit/drawer_component.html.erb +30 -0
- data/app/components/fluxbit/drawer_component.rb +125 -0
- data/app/components/fluxbit/dropdown_component.rb +41 -0
- data/app/components/fluxbit/dropdown_item_component.rb +68 -0
- data/app/components/fluxbit/flex_component.rb +1 -1
- data/app/components/fluxbit/form/component.rb +15 -8
- data/app/components/fluxbit/form/dropzone_component.rb +3 -3
- data/app/components/fluxbit/form/field_component.rb +4 -2
- data/app/components/fluxbit/form/help_text_component.rb +1 -1
- data/app/components/fluxbit/form/label_component.rb +10 -3
- data/app/components/fluxbit/form/password_component.rb +247 -0
- data/app/components/fluxbit/form/radio_group_button_component.rb +126 -0
- data/app/components/fluxbit/form/select_component.rb +108 -11
- data/app/components/fluxbit/form/text_field_component.rb +40 -23
- data/app/components/fluxbit/form/toggle_component.rb +2 -2
- data/app/components/fluxbit/form/upload_image_component.html.erb +3 -3
- data/app/components/fluxbit/form/upload_image_component.rb +12 -1
- data/app/components/fluxbit/gravatar_component.rb +7 -0
- data/app/components/fluxbit/icon_helpers.rb +167 -0
- data/app/components/fluxbit/link_component.rb +42 -0
- data/app/components/fluxbit/modal_component.rb +28 -31
- data/app/components/fluxbit/pagination_component.rb +206 -0
- data/app/components/fluxbit/popover_component.rb +14 -14
- data/app/components/fluxbit/progress_component.rb +196 -0
- data/app/components/fluxbit/skeleton_component.rb +237 -0
- data/app/components/fluxbit/speed_dial_action_component.html.erb +30 -0
- data/app/components/fluxbit/speed_dial_action_component.rb +59 -0
- data/app/components/fluxbit/speed_dial_component.html.erb +33 -0
- data/app/components/fluxbit/speed_dial_component.rb +73 -0
- data/app/components/fluxbit/spinner_component.rb +71 -0
- data/app/components/fluxbit/spinner_percent_component.rb +174 -0
- data/app/components/fluxbit/stepper_component.rb +223 -0
- data/app/components/fluxbit/tab_component.rb +44 -25
- data/app/components/fluxbit/table_component.rb +186 -0
- data/app/components/fluxbit/table_group_component.rb +28 -0
- data/app/components/fluxbit/theme_button_component.rb +64 -0
- data/app/components/fluxbit/timeline_component.rb +63 -0
- data/app/components/fluxbit/timeline_item_component.html.erb +64 -0
- data/app/components/fluxbit/timeline_item_component.rb +78 -0
- data/app/components/fluxbit/tooltip_component.rb +2 -2
- data/app/helpers/fluxbit/components_helper.rb +74 -4
- data/app/helpers/fluxbit/form_builder.rb +64 -15
- data/app/helpers/fluxbit/view_helper.rb +71 -0
- data/config/locales/en.yml +37 -4
- data/config/locales/pt-BR.yml +36 -0
- data/lib/fluxbit/config/accordion_component.rb +73 -0
- data/lib/fluxbit/config/avatar_component.rb +11 -11
- data/lib/fluxbit/config/badge_component.rb +14 -11
- data/lib/fluxbit/config/banner_component.rb +60 -0
- data/lib/fluxbit/config/bottom_navigation_component.rb +74 -0
- data/lib/fluxbit/config/breadcrumb_component.rb +24 -0
- data/lib/fluxbit/config/button_component.rb +6 -4
- data/lib/fluxbit/config/card_component.rb +23 -12
- data/lib/fluxbit/config/carousel_component.rb +33 -0
- data/lib/fluxbit/config/drawer_component.rb +48 -0
- data/lib/fluxbit/config/dropdown_component.rb +29 -0
- data/lib/fluxbit/config/form/check_box_component.rb +1 -1
- data/lib/fluxbit/config/form/dropzone_component.rb +1 -1
- data/lib/fluxbit/config/form/help_text_component.rb +1 -1
- data/lib/fluxbit/config/form/label_component.rb +3 -2
- data/lib/fluxbit/config/form/password_component.rb +19 -0
- data/lib/fluxbit/config/form/radio_group_button_component.rb +24 -0
- data/lib/fluxbit/config/form/text_field_component.rb +11 -11
- data/lib/fluxbit/config/form/toggle_component.rb +5 -5
- data/lib/fluxbit/config/link_component.rb +24 -0
- data/lib/fluxbit/config/modal_component.rb +1 -1
- data/lib/fluxbit/config/pagination_component.rb +31 -0
- data/lib/fluxbit/config/popover_component.rb +1 -1
- data/lib/fluxbit/config/progress_component.rb +63 -0
- data/lib/fluxbit/config/skeleton_component.rb +82 -0
- data/lib/fluxbit/config/speed_dial_component.rb +50 -0
- data/lib/fluxbit/config/spinner_component.rb +30 -0
- data/lib/fluxbit/config/spinner_percent_component.rb +61 -0
- data/lib/fluxbit/config/stepper_component.rb +299 -0
- data/lib/fluxbit/config/tab_component.rb +6 -0
- data/lib/fluxbit/config/table_component.rb +75 -0
- data/lib/fluxbit/config/theme_button_component.rb +19 -0
- data/lib/fluxbit/config/timeline_component.rb +77 -0
- data/lib/fluxbit/view_components/engine.rb +11 -3
- data/lib/fluxbit/view_components/version.rb +1 -1
- data/lib/fluxbit/view_components.rb +20 -0
- data/lib/generators/fluxbit/devise_views_generator.rb +116 -0
- data/lib/generators/fluxbit/pagy_generator.rb +39 -0
- data/lib/generators/fluxbit/scaffold_generator.rb +165 -0
- data/lib/generators/fluxbit/templates/_alert.html.erb.tt +1 -0
- data/lib/generators/fluxbit/templates/_flash.html.erb.tt +15 -0
- data/lib/generators/fluxbit/templates/_form.html.erb.tt +38 -0
- data/lib/generators/fluxbit/templates/_metadata.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/controller.rb.tt +406 -0
- data/lib/generators/fluxbit/templates/create.turbo_stream.erb.tt +7 -0
- data/lib/generators/fluxbit/templates/destroy.turbo_stream.erb.tt +3 -0
- data/lib/generators/fluxbit/templates/destroy_all.turbo_stream.erb.tt +9 -0
- data/lib/generators/fluxbit/templates/devise_views/confirmations/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/layouts/devise.html.erb +64 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/confirmation_instructions.html.erb +5 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/email_changed.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/password_changed.html.erb +3 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/reset_password_instructions.html.erb +8 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/unlock_instructions.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/edit.html.erb +29 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/edit.html.erb +43 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/new.html.erb +34 -0
- data/lib/generators/fluxbit/templates/devise_views/sessions/new.html.erb +15 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_error_messages.html.erb +14 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_links.html.erb +25 -0
- data/lib/generators/fluxbit/templates/devise_views/unlocks/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/edit.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/fluxbit_pagy.css +27 -0
- data/lib/generators/fluxbit/templates/i18n.en.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/i18n.pt-BR.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/index.html.erb.tt +254 -0
- data/lib/generators/fluxbit/templates/index.json.jbuilder.tt +33 -0
- data/lib/generators/fluxbit/templates/new.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/partial.html.erb.tt +61 -0
- data/lib/generators/fluxbit/templates/policy.rb.tt +36 -0
- data/lib/generators/fluxbit/templates/send_alert_via_drawer.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/show.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/show.json.jbuilder.tt +6 -0
- data/lib/generators/fluxbit/templates/update.turbo_stream.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/update_all.turbo_stream.erb.tt +20 -0
- data/lib/install/install.rb +58 -0
- metadata +107 -18
- data/app/helpers/fluxbit/classes_helper.rb +0 -9
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The `Fluxbit::AccordionComponent` renders an accordion component following Flowbite styles.
|
|
4
|
+
# It supports collapsible panels with headers and content, customizable icons, and various styling options.
|
|
5
|
+
class Fluxbit::AccordionComponent < Fluxbit::Component
|
|
6
|
+
include Fluxbit::Config::AccordionComponent
|
|
7
|
+
|
|
8
|
+
renders_many :panels, lambda { |**attrs, &block|
|
|
9
|
+
panel = Panel.new(accordion_id: fx_id, flush: @flush, color: @color, **attrs)
|
|
10
|
+
block.call(panel) if block_given?
|
|
11
|
+
panel
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Initializes the accordion component with the given properties.
|
|
16
|
+
#
|
|
17
|
+
# @param [Hash] **props The properties to customize the accordion.
|
|
18
|
+
# @option props [Boolean] :flush (false) When true, removes borders and rounded corners for seamless integration.
|
|
19
|
+
# @option props [Symbol, String] :color (:default) The color theme for accordion panels (default, light, primary, secondary, success, danger, warning, info, dark).
|
|
20
|
+
# @option props [Boolean] :collapse_all (false) When true, allows all panels to be collapsed simultaneously. When false, keeps at least one panel open.
|
|
21
|
+
# @option props [String] :remove_class ('') CSS classes to remove from the default class list.
|
|
22
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes for the accordion container.
|
|
23
|
+
#
|
|
24
|
+
# @return [Fluxbit::AccordionComponent]
|
|
25
|
+
def initialize(**props)
|
|
26
|
+
super
|
|
27
|
+
@props = props
|
|
28
|
+
@flush = options(@props.delete(:flush), default: @@flush)
|
|
29
|
+
@color = options(@props.delete(:color), collection: styles[:colors].keys, default: @@color).to_sym
|
|
30
|
+
@collapse_all = options(@props.delete(:collapse_all), default: @@collapse_all)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def before_render
|
|
34
|
+
add to: @props, first_element: true, class: [
|
|
35
|
+
styles[:base],
|
|
36
|
+
@flush ? "" : "border border-gray-200 dark:border-gray-700 rounded-xl"
|
|
37
|
+
]
|
|
38
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
|
39
|
+
@props[:id] ||= fx_id
|
|
40
|
+
@props["data-accordion"] = @collapse_all ? "collapse" : "open"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def call
|
|
44
|
+
tag.div(**@props) do
|
|
45
|
+
safe_join(panels)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class Panel < Fluxbit::Component
|
|
50
|
+
include Fluxbit::Config::AccordionComponent
|
|
51
|
+
renders_one :header
|
|
52
|
+
renders_one :body
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Initializes an accordion panel with the given properties.
|
|
56
|
+
#
|
|
57
|
+
# @param [String] accordion_id The parent accordion's ID for proper ARIA relationships.
|
|
58
|
+
# @param [Boolean] flush (false) Whether the panel should use flush styling.
|
|
59
|
+
# @param [Symbol, String] color (:default) The color theme for this panel.
|
|
60
|
+
# @param [Boolean] open (false) Whether the panel should start in an expanded state.
|
|
61
|
+
# @param [Integer] index (0) The panel's position index for proper styling (first, middle, last).
|
|
62
|
+
# @param [Hash] **props Additional HTML attributes for the panel container.
|
|
63
|
+
#
|
|
64
|
+
# @return [Fluxbit::AccordionComponent::Panel]
|
|
65
|
+
def initialize(accordion_id:, **props)
|
|
66
|
+
super
|
|
67
|
+
@props = props
|
|
68
|
+
@accordion_id = accordion_id
|
|
69
|
+
@flush = options(@props.delete(:flush), default: @@flush)
|
|
70
|
+
@color = options(@props.delete(:color), collection: styles[:colors].keys, default: @@color).to_sym
|
|
71
|
+
@open = options(@props.delete(:open), default: false)
|
|
72
|
+
@index = options(@props.delete(:index), default: 0)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def call
|
|
76
|
+
header_id = "#{@accordion_id}-header-#{@index}"
|
|
77
|
+
content_id = "#{@accordion_id}-content-#{@index}"
|
|
78
|
+
|
|
79
|
+
header_base = styles[:item][:header][:base]
|
|
80
|
+
content_base = styles[:item][:content][:base]
|
|
81
|
+
|
|
82
|
+
if @flush
|
|
83
|
+
header_base = header_base.gsub(/border[^-]\S*/, "").gsub(/rounded-\S+/, "")
|
|
84
|
+
content_base = content_base.gsub(/border[^-]\S*/, "").gsub(/rounded-\S+/, "")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
header_classes = [
|
|
88
|
+
header_base,
|
|
89
|
+
styles[:colors][@color][:header],
|
|
90
|
+
(@index == 0) ? styles[:item][:header][:first] : styles[:item][:header][:middle]
|
|
91
|
+
].compact.join(" ")
|
|
92
|
+
|
|
93
|
+
content_classes = [
|
|
94
|
+
content_base,
|
|
95
|
+
styles[:colors][@color][:content],
|
|
96
|
+
(@index == 0) ? styles[:item][:content][:first] : styles[:item][:content][:middle]
|
|
97
|
+
].compact.join(" ")
|
|
98
|
+
|
|
99
|
+
tag.div(class: styles[:item][:base]) do
|
|
100
|
+
concat(
|
|
101
|
+
tag.h2(id: header_id) do
|
|
102
|
+
tag.button(
|
|
103
|
+
type: "button",
|
|
104
|
+
class: header_classes,
|
|
105
|
+
"data-accordion-target" => "##{content_id}",
|
|
106
|
+
"aria-expanded" => @open.to_s,
|
|
107
|
+
"aria-controls" => content_id
|
|
108
|
+
) do
|
|
109
|
+
concat(tag.span(header || "Accordion Header"))
|
|
110
|
+
concat(chevron_down(class: styles[:item][:icon][:base]))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
)
|
|
114
|
+
concat(
|
|
115
|
+
tag.div(
|
|
116
|
+
body || "",
|
|
117
|
+
id: content_id,
|
|
118
|
+
class: [ @open ? "" : "hidden", content_classes ].join(" "),
|
|
119
|
+
"aria-labelledby" => header_id
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -73,9 +73,9 @@ class Fluxbit::AlertComponent < Fluxbit::Component
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def call
|
|
76
|
-
|
|
76
|
+
tag.div(**@props) do
|
|
77
77
|
concat @icon
|
|
78
|
-
concat
|
|
78
|
+
concat tag.div(content, class: "ml-3 text-sm font-medium")
|
|
79
79
|
concat close_button
|
|
80
80
|
end
|
|
81
81
|
end
|
|
@@ -103,24 +103,24 @@ class Fluxbit::AlertComponent < Fluxbit::Component
|
|
|
103
103
|
def define_icon(icon, class_icon = "")
|
|
104
104
|
return "" if icon == false
|
|
105
105
|
icon = icon || @@icon
|
|
106
|
-
return anyicon(icon
|
|
106
|
+
return anyicon(icon, class: class_icon) if icon != :default
|
|
107
107
|
|
|
108
|
-
anyicon(
|
|
108
|
+
anyicon("heroicons_solid:#{styles[:default_icons][@color]}", class: class_icon + " size-5")
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def close_button
|
|
112
112
|
return "" unless @can_close
|
|
113
113
|
|
|
114
114
|
b_props = {
|
|
115
|
-
"aria-label" => "
|
|
115
|
+
"aria-label" => t("fluxbit.alert.aria_close"),
|
|
116
116
|
"data-dismiss-target" => "##{@props["id"]}",
|
|
117
117
|
type: "button"
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
add to: b_props, class: [ styles[:close_button][:base], styles[:close_button][:colors][@color] ]
|
|
121
|
-
|
|
122
|
-
concat
|
|
123
|
-
concat anyicon(
|
|
121
|
+
tag.button(**b_props) do
|
|
122
|
+
concat tag.span(t("fluxbit.alert.dismiss"), class: "sr-only")
|
|
123
|
+
concat anyicon("heroicons_outline:x-mark", class: "size-5")
|
|
124
124
|
end
|
|
125
125
|
end
|
|
126
126
|
end
|
|
@@ -55,11 +55,11 @@ class Fluxbit::AvatarComponent < Fluxbit::Component
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def avatar_itself
|
|
58
|
-
return
|
|
58
|
+
return tag.img(**@props) unless @src.nil? || @placeholder_initials
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
tag.div(**@props) do
|
|
61
61
|
if @placeholder_initials
|
|
62
|
-
|
|
62
|
+
tag.span(@placeholder_initials, class: styles[:initials][:text])
|
|
63
63
|
else
|
|
64
64
|
placeholder_icon
|
|
65
65
|
end
|
|
@@ -80,8 +80,8 @@ class Fluxbit::AvatarComponent < Fluxbit::Component
|
|
|
80
80
|
"clip-rule": "evenodd"
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
tag.svg(**svg_attributes) do
|
|
84
|
+
tag.path(**path_attributes)
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
@@ -92,20 +92,19 @@ class Fluxbit::AvatarComponent < Fluxbit::Component
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
def dot_indicator
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
styles[:status][:options][@status],
|
|
100
|
-
styles[@rounded ? :rounded : :not_rounded][:status_position][@status_position[0]],
|
|
95
|
+
tag.span("", class: [
|
|
96
|
+
styles[:status][:base],
|
|
97
|
+
styles[:status][:options][@status],
|
|
98
|
+
styles[@rounded ? :rounded : :not_rounded][:status_position][@status_position[0]],
|
|
101
99
|
styles[@rounded ? :rounded : :not_rounded][:status_position][@status_position[1]][@size]
|
|
102
100
|
].join(" ")
|
|
101
|
+
)
|
|
103
102
|
end
|
|
104
103
|
|
|
105
104
|
def call
|
|
106
105
|
return avatar_itself unless @status
|
|
107
106
|
|
|
108
|
-
|
|
107
|
+
tag.div(class: "relative") do
|
|
109
108
|
concat avatar_itself
|
|
110
109
|
concat dot_indicator
|
|
111
110
|
end
|
|
@@ -11,7 +11,7 @@ class Fluxbit::AvatarGroupComponent < Fluxbit::Component
|
|
|
11
11
|
renders_many :gravatars, Fluxbit::GravatarComponent
|
|
12
12
|
|
|
13
13
|
def call
|
|
14
|
-
|
|
14
|
+
tag.div(class: styles[:group]) do
|
|
15
15
|
avatars.each do |avatar|
|
|
16
16
|
concat render(avatar)
|
|
17
17
|
end
|
|
@@ -36,12 +36,13 @@ class Fluxbit::BadgeComponent < Fluxbit::Component
|
|
|
36
36
|
def initialize(**props)
|
|
37
37
|
super
|
|
38
38
|
@props = props
|
|
39
|
-
@color = @props.delete(:color)
|
|
40
|
-
@pill = @props.delete(:pill)
|
|
41
|
-
@size = @props.delete(:size)
|
|
42
|
-
@perfect_rounded = @props.delete(:perfect_rounded)
|
|
43
|
-
@notification = @props.delete(:notification)
|
|
44
|
-
@as = @props.delete(:as)
|
|
39
|
+
@color = options @props.delete(:color), collection: styles[:colors].keys, default: @@color
|
|
40
|
+
@pill = options @props.delete(:pill), default: @@pill
|
|
41
|
+
@size = options @props.delete(:size), default: @@size
|
|
42
|
+
@perfect_rounded = options @props.delete(:perfect_rounded), default: @@perfect_rounded
|
|
43
|
+
@notification = options @props.delete(:notification), default: @@notification
|
|
44
|
+
@as = options @props.delete(:as), default: @@as
|
|
45
|
+
|
|
45
46
|
add(class: badge_classes, to: @props, first_element: true)
|
|
46
47
|
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
|
47
48
|
end
|
|
@@ -63,9 +64,9 @@ class Fluxbit::BadgeComponent < Fluxbit::Component
|
|
|
63
64
|
styles[:colors][@color.to_sym],
|
|
64
65
|
styles[:sizes][@size.to_i],
|
|
65
66
|
styles[:perfect_rounded][@perfect_rounded.to_i],
|
|
67
|
+
styles[:pill][@pill ? :on : :off],
|
|
66
68
|
notification_classes
|
|
67
69
|
]
|
|
68
|
-
base_classes << "rounded-full" if @pill
|
|
69
70
|
base_classes.join(" ")
|
|
70
71
|
end
|
|
71
72
|
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The `Fluxbit::BannerComponent` is a customizable banner component that extends `Fluxbit::Component`.
|
|
5
|
+
# It provides various options to display banner messages with different styles, positions, and behaviors
|
|
6
|
+
# such as close functionality and call-to-action elements.
|
|
7
|
+
#
|
|
8
|
+
# Example usage:
|
|
9
|
+
# = render Fluxbit::BannerComponent.new(position: :top, color: :info).with_content("Banner message")
|
|
10
|
+
#
|
|
11
|
+
class Fluxbit::BannerComponent < Fluxbit::Component
|
|
12
|
+
include Fluxbit::Config::BannerComponent
|
|
13
|
+
|
|
14
|
+
renders_one :cta_button, lambda { |**props|
|
|
15
|
+
Fluxbit::ButtonComponent.new(**props)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
renders_one :logo, lambda { |**props|
|
|
19
|
+
content_tag(:img, "", **props)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Initializes the banner component with the given properties.
|
|
24
|
+
#
|
|
25
|
+
# @param [Hash] props The properties to customize the banner.
|
|
26
|
+
# @option props [Symbol, String] :position (:top) The position of the banner (top, bottom, sticky_top, sticky_bottom).
|
|
27
|
+
# @option props [Symbol, String] :color (:info) The color style of the banner.
|
|
28
|
+
# @option props [Symbol, String, Boolean] :icon (:default) The icon to display in the banner or `false` to omit.
|
|
29
|
+
# @option props [Hash] :icon_html ({}) Additional HTML attributes for the icon.
|
|
30
|
+
# @option props [Boolean] :dismissible (true) Determines if the banner can be dismissed.
|
|
31
|
+
# @option props [Boolean] :full_width (true) Determines if the banner spans the full width.
|
|
32
|
+
# @option props [String] :remove_class ('') Classes to remove from the default class list.
|
|
33
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes.
|
|
34
|
+
#
|
|
35
|
+
# @return [Fluxbit::BannerComponent]
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
# = render Fluxbit::BannerComponent.new(position: :top, color: :info).with_content("Banner message")
|
|
39
|
+
#
|
|
40
|
+
def initialize(**props)
|
|
41
|
+
super
|
|
42
|
+
@props = props
|
|
43
|
+
@position = define_position(@props.delete(:position) || @@position)
|
|
44
|
+
@color = define_color(@props.delete(:color) || @@color)
|
|
45
|
+
icon_prop = @props.delete(:icon)
|
|
46
|
+
icon_html = @props.delete(:icon_html) || {}
|
|
47
|
+
@icon = define_icon(icon_prop.nil? ? :default : icon_prop, icon_html)
|
|
48
|
+
@dismissible = @props[:dismissible].nil? ? @@dismissible : @props.delete(:dismissible)
|
|
49
|
+
@full_width = @props[:full_width].nil? ? @@full_width : @props.delete(:full_width)
|
|
50
|
+
@props["id"] = fx_id if @props["id"].nil?
|
|
51
|
+
|
|
52
|
+
declare_classes
|
|
53
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def call
|
|
57
|
+
tag.div(**@props) do
|
|
58
|
+
concat banner_content
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def banner_content
|
|
65
|
+
content_wrapper_class = @full_width ? styles[:content_wrapper][:full_width] : styles[:content_wrapper][:constrained]
|
|
66
|
+
|
|
67
|
+
tag.div(class: content_wrapper_class) do
|
|
68
|
+
concat banner_left_content
|
|
69
|
+
concat banner_right_content if @dismissible || cta_button?
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def banner_left_content
|
|
74
|
+
tag.div(class: styles[:left_content]) do
|
|
75
|
+
concat logo if logo?
|
|
76
|
+
concat @icon unless @icon.blank?
|
|
77
|
+
text_class = icon_or_logo_present? ? styles[:text][:with_icon_or_logo] : styles[:text][:without_icon_or_logo]
|
|
78
|
+
concat tag.div(content, class: text_class)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def banner_right_content
|
|
83
|
+
tag.div(class: styles[:right_content]) do
|
|
84
|
+
concat cta_button if cta_button?
|
|
85
|
+
concat dismiss_button if @dismissible
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def icon_or_logo_present?
|
|
90
|
+
!@icon.blank? || logo?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def dismiss_button
|
|
94
|
+
button_props = {
|
|
95
|
+
"aria-label" => t("fluxbit.banner.aria_close"),
|
|
96
|
+
"data-dismiss-target" => "##{@props["id"]}",
|
|
97
|
+
type: "button",
|
|
98
|
+
class: styles[:dismiss_button][:base]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if cta_button?
|
|
102
|
+
add(to: button_props, class: styles[:dismiss_button][:with_cta])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
tag.button(**button_props) do
|
|
106
|
+
concat tag.span(t("fluxbit.banner.dismiss"), class: styles[:screen_reader])
|
|
107
|
+
concat close_icon(class: styles[:close_icon])
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def declare_classes
|
|
112
|
+
base_classes = [
|
|
113
|
+
styles[:base],
|
|
114
|
+
styles[:positions][@position],
|
|
115
|
+
styles[:colors][@color]
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
add(to: @props, first_element: true, class: base_classes)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def define_position(position)
|
|
122
|
+
position.to_sym.in?(styles[:positions].keys) ? position.to_sym : @@position
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def define_color(color)
|
|
126
|
+
color.to_sym.in?(styles[:colors].keys) ? color.to_sym : @@color
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def define_icon(icon, icon_html = {})
|
|
130
|
+
return "" if icon == false
|
|
131
|
+
icon = icon || @@icon
|
|
132
|
+
icon_props = { class: styles[:icon_default] }.merge(icon_html)
|
|
133
|
+
icon_props[:class] = remove_class(icon_props.delete(:remove_class) || "", icon_props[:class])
|
|
134
|
+
|
|
135
|
+
return anyicon(icon, **icon_props) if icon != :default
|
|
136
|
+
|
|
137
|
+
anyicon("heroicons_solid:#{styles[:default_icons][@color]}", **icon_props)
|
|
138
|
+
end
|
|
139
|
+
end
|