better_ui 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.

Potentially problematic release.


This version of better_ui might be problematic. Click here for more details.

Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +174 -216
  4. data/app/assets/javascripts/better_ui/controllers/navbar_controller.js +138 -0
  5. data/app/assets/javascripts/better_ui/controllers/sidebar_controller.js +211 -0
  6. data/app/assets/javascripts/better_ui/controllers/toast_controller.js +161 -0
  7. data/app/assets/javascripts/better_ui/index.js +159 -0
  8. data/app/assets/javascripts/better_ui/toast_manager.js +77 -0
  9. data/app/assets/stylesheets/better_ui/application.css +30 -0
  10. data/app/components/better_ui/application/alert_component.html.erb +27 -0
  11. data/app/components/better_ui/application/alert_component.rb +196 -0
  12. data/app/components/better_ui/application/header_component.html.erb +88 -0
  13. data/app/components/better_ui/application/header_component.rb +188 -0
  14. data/app/components/better_ui/application/navbar_component.html.erb +294 -0
  15. data/app/components/better_ui/application/navbar_component.rb +249 -0
  16. data/app/components/better_ui/application/sidebar_component.html.erb +207 -0
  17. data/app/components/better_ui/application/sidebar_component.rb +318 -0
  18. data/app/components/better_ui/application/toast_component.html.erb +35 -0
  19. data/app/components/better_ui/application/toast_component.rb +188 -0
  20. data/app/components/better_ui/general/breadcrumb_component.html.erb +39 -0
  21. data/app/components/better_ui/general/breadcrumb_component.rb +132 -0
  22. data/app/components/better_ui/general/{button/component.html.erb → button_component.html.erb} +7 -7
  23. data/app/components/better_ui/general/button_component.rb +193 -0
  24. data/app/components/better_ui/general/heading_component.html.erb +25 -0
  25. data/app/components/better_ui/general/heading_component.rb +142 -0
  26. data/app/components/better_ui/general/icon_component.html.erb +2 -0
  27. data/app/components/better_ui/general/icon_component.rb +101 -0
  28. data/app/components/better_ui/general/panel_component.html.erb +27 -0
  29. data/app/components/better_ui/general/panel_component.rb +97 -0
  30. data/app/components/better_ui/general/table_component.html.erb +37 -0
  31. data/app/components/better_ui/general/table_component.rb +141 -0
  32. data/app/components/better_ui/theme_helper.rb +169 -0
  33. data/app/controllers/better_ui/application_controller.rb +1 -0
  34. data/app/controllers/better_ui/docs_controller.rb +34 -0
  35. data/app/helpers/better_ui_application_helper.rb +99 -0
  36. data/app/views/layouts/component_preview.html.erb +32 -0
  37. data/config/initializers/lookbook.rb +12 -12
  38. data/config/routes.rb +13 -0
  39. data/lib/better_ui/engine.rb +42 -5
  40. data/lib/better_ui/version.rb +1 -1
  41. data/lib/better_ui.rb +20 -4
  42. metadata +117 -157
  43. data/app/components/better_ui/application/card/component.html.erb +0 -20
  44. data/app/components/better_ui/application/card/component.rb +0 -214
  45. data/app/components/better_ui/application/main/component.html.erb +0 -9
  46. data/app/components/better_ui/application/main/component.rb +0 -123
  47. data/app/components/better_ui/application/navbar/component.html.erb +0 -92
  48. data/app/components/better_ui/application/navbar/component.rb +0 -136
  49. data/app/components/better_ui/application/sidebar/component.html.erb +0 -227
  50. data/app/components/better_ui/application/sidebar/component.rb +0 -130
  51. data/app/components/better_ui/general/accordion/component.html.erb +0 -5
  52. data/app/components/better_ui/general/accordion/component.rb +0 -92
  53. data/app/components/better_ui/general/accordion/item_component.html.erb +0 -12
  54. data/app/components/better_ui/general/accordion/item_component.rb +0 -176
  55. data/app/components/better_ui/general/alert/component.html.erb +0 -32
  56. data/app/components/better_ui/general/alert/component.rb +0 -242
  57. data/app/components/better_ui/general/avatar/component.html.erb +0 -20
  58. data/app/components/better_ui/general/avatar/component.rb +0 -301
  59. data/app/components/better_ui/general/badge/component.html.erb +0 -23
  60. data/app/components/better_ui/general/badge/component.rb +0 -248
  61. data/app/components/better_ui/general/breadcrumb/component.html.erb +0 -15
  62. data/app/components/better_ui/general/breadcrumb/component.rb +0 -187
  63. data/app/components/better_ui/general/button/component.rb +0 -214
  64. data/app/components/better_ui/general/divider/component.html.erb +0 -10
  65. data/app/components/better_ui/general/divider/component.rb +0 -226
  66. data/app/components/better_ui/general/dropdown/component.html.erb +0 -25
  67. data/app/components/better_ui/general/dropdown/component.rb +0 -170
  68. data/app/components/better_ui/general/dropdown/divider_component.html.erb +0 -1
  69. data/app/components/better_ui/general/dropdown/divider_component.rb +0 -41
  70. data/app/components/better_ui/general/dropdown/item_component.html.erb +0 -6
  71. data/app/components/better_ui/general/dropdown/item_component.rb +0 -119
  72. data/app/components/better_ui/general/field/component.html.erb +0 -27
  73. data/app/components/better_ui/general/field/component.rb +0 -37
  74. data/app/components/better_ui/general/heading/component.html.erb +0 -22
  75. data/app/components/better_ui/general/heading/component.rb +0 -257
  76. data/app/components/better_ui/general/icon/component.html.erb +0 -7
  77. data/app/components/better_ui/general/icon/component.rb +0 -239
  78. data/app/components/better_ui/general/input/checkbox/component.html.erb +0 -5
  79. data/app/components/better_ui/general/input/checkbox/component.rb +0 -238
  80. data/app/components/better_ui/general/input/datetime/component.html.erb +0 -5
  81. data/app/components/better_ui/general/input/datetime/component.rb +0 -223
  82. data/app/components/better_ui/general/input/radio/component.html.erb +0 -5
  83. data/app/components/better_ui/general/input/radio/component.rb +0 -230
  84. data/app/components/better_ui/general/input/select/component.html.erb +0 -16
  85. data/app/components/better_ui/general/input/select/component.rb +0 -184
  86. data/app/components/better_ui/general/input/select/select_component.html.erb +0 -5
  87. data/app/components/better_ui/general/input/select/select_component.rb +0 -37
  88. data/app/components/better_ui/general/input/text/component.html.erb +0 -5
  89. data/app/components/better_ui/general/input/text/component.rb +0 -171
  90. data/app/components/better_ui/general/input/textarea/component.html.erb +0 -5
  91. data/app/components/better_ui/general/input/textarea/component.rb +0 -166
  92. data/app/components/better_ui/general/link/component.html.erb +0 -18
  93. data/app/components/better_ui/general/link/component.rb +0 -258
  94. data/app/components/better_ui/general/modal/component.html.erb +0 -5
  95. data/app/components/better_ui/general/modal/component.rb +0 -47
  96. data/app/components/better_ui/general/modal/modal_component.html.erb +0 -52
  97. data/app/components/better_ui/general/modal/modal_component.rb +0 -160
  98. data/app/components/better_ui/general/pagination/component.html.erb +0 -85
  99. data/app/components/better_ui/general/pagination/component.rb +0 -216
  100. data/app/components/better_ui/general/panel/component.html.erb +0 -28
  101. data/app/components/better_ui/general/panel/component.rb +0 -249
  102. data/app/components/better_ui/general/progress/component.html.erb +0 -11
  103. data/app/components/better_ui/general/progress/component.rb +0 -160
  104. data/app/components/better_ui/general/spinner/component.html.erb +0 -35
  105. data/app/components/better_ui/general/spinner/component.rb +0 -93
  106. data/app/components/better_ui/general/table/component.html.erb +0 -5
  107. data/app/components/better_ui/general/table/component.rb +0 -217
  108. data/app/components/better_ui/general/table/tbody_component.html.erb +0 -3
  109. data/app/components/better_ui/general/table/tbody_component.rb +0 -30
  110. data/app/components/better_ui/general/table/td_component.html.erb +0 -3
  111. data/app/components/better_ui/general/table/td_component.rb +0 -44
  112. data/app/components/better_ui/general/table/tfoot_component.html.erb +0 -3
  113. data/app/components/better_ui/general/table/tfoot_component.rb +0 -28
  114. data/app/components/better_ui/general/table/th_component.html.erb +0 -6
  115. data/app/components/better_ui/general/table/th_component.rb +0 -51
  116. data/app/components/better_ui/general/table/thead_component.html.erb +0 -3
  117. data/app/components/better_ui/general/table/thead_component.rb +0 -28
  118. data/app/components/better_ui/general/table/tr_component.html.erb +0 -3
  119. data/app/components/better_ui/general/table/tr_component.rb +0 -30
  120. data/app/components/better_ui/general/tabs/component.html.erb +0 -11
  121. data/app/components/better_ui/general/tabs/component.rb +0 -120
  122. data/app/components/better_ui/general/tabs/panel_component.html.erb +0 -3
  123. data/app/components/better_ui/general/tabs/panel_component.rb +0 -37
  124. data/app/components/better_ui/general/tabs/tab_component.html.erb +0 -13
  125. data/app/components/better_ui/general/tabs/tab_component.rb +0 -111
  126. data/app/components/better_ui/general/tag/component.html.erb +0 -3
  127. data/app/components/better_ui/general/tag/component.rb +0 -104
  128. data/app/components/better_ui/general/tooltip/component.html.erb +0 -7
  129. data/app/components/better_ui/general/tooltip/component.rb +0 -239
  130. data/app/helpers/better_ui/application/components/card/card_helper.rb +0 -96
  131. data/app/helpers/better_ui/application/components/card.rb +0 -11
  132. data/app/helpers/better_ui/application/components/main/main_helper.rb +0 -64
  133. data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +0 -77
  134. data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +0 -51
  135. data/app/helpers/better_ui/application_helper.rb +0 -55
  136. data/app/helpers/better_ui/general/components/accordion/accordion_helper.rb +0 -73
  137. data/app/helpers/better_ui/general/components/accordion.rb +0 -11
  138. data/app/helpers/better_ui/general/components/alert/alert_helper.rb +0 -57
  139. data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +0 -29
  140. data/app/helpers/better_ui/general/components/badge/badge_helper.rb +0 -53
  141. data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +0 -37
  142. data/app/helpers/better_ui/general/components/button/button_helper.rb +0 -65
  143. data/app/helpers/better_ui/general/components/container/container_helper.rb +0 -60
  144. data/app/helpers/better_ui/general/components/divider/divider_helper.rb +0 -63
  145. data/app/helpers/better_ui/general/components/dropdown/divider_helper.rb +0 -32
  146. data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +0 -79
  147. data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +0 -62
  148. data/app/helpers/better_ui/general/components/field/field_helper.rb +0 -26
  149. data/app/helpers/better_ui/general/components/heading/heading_helper.rb +0 -72
  150. data/app/helpers/better_ui/general/components/icon/icon_helper.rb +0 -16
  151. data/app/helpers/better_ui/general/components/input/checkbox/checkbox_helper.rb +0 -81
  152. data/app/helpers/better_ui/general/components/input/datetime/datetime_helper.rb +0 -91
  153. data/app/helpers/better_ui/general/components/input/radio/radio_helper.rb +0 -79
  154. data/app/helpers/better_ui/general/components/input/radio_group/radio_group_helper.rb +0 -124
  155. data/app/helpers/better_ui/general/components/input/select/select_helper.rb +0 -70
  156. data/app/helpers/better_ui/general/components/input/text/text_helper.rb +0 -138
  157. data/app/helpers/better_ui/general/components/input/textarea/textarea_helper.rb +0 -73
  158. data/app/helpers/better_ui/general/components/link/link_helper.rb +0 -89
  159. data/app/helpers/better_ui/general/components/modal/modal_helper.rb +0 -85
  160. data/app/helpers/better_ui/general/components/modal.rb +0 -11
  161. data/app/helpers/better_ui/general/components/pagination/pagination_helper.rb +0 -82
  162. data/app/helpers/better_ui/general/components/panel/panel_helper.rb +0 -83
  163. data/app/helpers/better_ui/general/components/progress/progress_helper.rb +0 -53
  164. data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +0 -19
  165. data/app/helpers/better_ui/general/components/table/table_helper.rb +0 -53
  166. data/app/helpers/better_ui/general/components/table/tbody_helper.rb +0 -13
  167. data/app/helpers/better_ui/general/components/table/td_helper.rb +0 -19
  168. data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +0 -13
  169. data/app/helpers/better_ui/general/components/table/th_helper.rb +0 -19
  170. data/app/helpers/better_ui/general/components/table/thead_helper.rb +0 -13
  171. data/app/helpers/better_ui/general/components/table/tr_helper.rb +0 -13
  172. data/app/helpers/better_ui/general/components/tabs/panel_helper.rb +0 -62
  173. data/app/helpers/better_ui/general/components/tabs/tab_helper.rb +0 -55
  174. data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +0 -95
  175. data/app/helpers/better_ui/general/components/tag/tag_helper.rb +0 -26
  176. data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +0 -60
  177. data/app/views/layouts/better_ui/application.html.erb +0 -17
  178. data/lib/better_ui/railtie.rb +0 -20
@@ -1,130 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BetterUi
4
- module Application
5
- module Sidebar
6
- class Component < ViewComponent::Base
7
- # Include degli helper per utilizzare bui_icon, bui_avatar e bui_button
8
- include BetterUi::General::Components::Icon::IconHelper
9
- include BetterUi::General::Components::Avatar::AvatarHelper
10
- include BetterUi::General::Components::Button::ButtonHelper
11
- attr_reader :width, :position, :theme, :shadow, :border, :header, :footer, :navigation_sections, :collapsible, :classes
12
-
13
- # Larghezze sidebar con classi Tailwind dirette
14
- SIDEBAR_WIDTHS = {
15
- sm: "w-48",
16
- md: "w-64",
17
- lg: "w-72",
18
- xl: "w-80"
19
- }
20
-
21
- # Temi sidebar con classi Tailwind dirette
22
- SIDEBAR_THEMES = {
23
- default: "bg-white text-gray-900",
24
- dark: "bg-gray-900 text-white",
25
- light: "bg-white text-gray-900"
26
- }
27
-
28
- # Ombre sidebar con classi Tailwind dirette
29
- SIDEBAR_SHADOWS = {
30
- none: "",
31
- sm: "shadow-sm",
32
- md: "shadow-md",
33
- lg: "shadow-lg",
34
- xl: "shadow-xl"
35
- }
36
-
37
- # Bordi sidebar con classi Tailwind dirette
38
- SIDEBAR_BORDERS = {
39
- left: "border-r border-gray-200",
40
- right: "border-l border-gray-200"
41
- }
42
-
43
- # @param width [Symbol] Larghezza della sidebar (:sm, :md, :lg, :xl), default :md (w-64)
44
- # @param position [Symbol] Posizione della sidebar (:left, :right), default :left
45
- # @param theme [Symbol] Tema colori (:default, :dark, :light), default :default
46
- # @param shadow [Symbol] Tipo di ombra (:none, :sm, :md, :lg), default :lg
47
- # @param border [Boolean] Se mostrare il bordo destro/sinistro, default true
48
- # @param header [Hash] Configurazione header (logo, title, subtitle)
49
- # @param footer [Hash] Configurazione footer (content, user_info)
50
- # @param navigation_sections [Array] Array di sezioni di navigazione
51
- # @param collapsible [Boolean] Se abilitare sezioni collassabili, default true
52
- # @param classes [String] Classi CSS aggiuntive
53
- def initialize(
54
- width: :md,
55
- position: :left,
56
- theme: :default,
57
- shadow: :lg,
58
- border: true,
59
- header: {},
60
- footer: {},
61
- navigation_sections: [],
62
- collapsible: true,
63
- classes: nil
64
- )
65
- @width = width.to_sym
66
- @position = position.to_sym
67
- @theme = theme.to_sym
68
- @shadow = shadow.to_sym
69
- @border = border
70
- @header = header || {}
71
- @footer = footer || {}
72
- @navigation_sections = navigation_sections || []
73
- @collapsible = collapsible
74
- @classes = classes
75
- end
76
-
77
- def container_classes
78
- base_classes = %w[fixed inset-y-0 h-screen z-50 flex flex-col]
79
-
80
- # Posizione
81
- base_classes << (position == :right ? "right-0" : "left-0")
82
-
83
- # Larghezza
84
- base_classes << width_class
85
-
86
- # Tema
87
- base_classes.concat(theme_classes)
88
-
89
- # Shadow
90
- base_classes << shadow_class if shadow != :none
91
-
92
- # Border
93
- base_classes << border_class if border
94
-
95
- # Classi aggiuntive
96
- base_classes << classes if classes.present?
97
-
98
- base_classes.compact.join(" ")
99
- end
100
-
101
-
102
- def has_header?
103
- header.present? && (header[:title].present? || header[:logo].present?)
104
- end
105
-
106
- def has_footer?
107
- footer.present? && (footer[:content].present? || footer[:user_info].present?)
108
- end
109
-
110
- private
111
-
112
- def width_class
113
- SIDEBAR_WIDTHS[@width] || SIDEBAR_WIDTHS[:md]
114
- end
115
-
116
- def theme_classes
117
- (SIDEBAR_THEMES[@theme] || SIDEBAR_THEMES[:default]).split
118
- end
119
-
120
- def shadow_class
121
- SIDEBAR_SHADOWS[@shadow] || SIDEBAR_SHADOWS[:none]
122
- end
123
-
124
- def border_class
125
- SIDEBAR_BORDERS[@position] || SIDEBAR_BORDERS[:left]
126
- end
127
- end
128
- end
129
- end
130
- end
@@ -1,5 +0,0 @@
1
- <div <%= tag.attributes(wrapper_attributes) %>>
2
- <% items.each do |item| %>
3
- <%= item %>
4
- <% end %>
5
- </div>
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BetterUi
4
- module General
5
- module Accordion
6
- class Component < ViewComponent::Base
7
- renders_many :items, "BetterUi::General::Accordion::ItemComponent"
8
-
9
- ACCORDION_THEME = {
10
- default: 'border-gray-200',
11
- white: 'border-gray-100 bg-white',
12
- blue: 'border-blue-200',
13
- red: 'border-red-200',
14
- green: 'border-green-200',
15
- yellow: 'border-yellow-200',
16
- violet: 'border-violet-200',
17
- orange: 'border-orange-200',
18
- rose: 'border-rose-200'
19
- }.freeze
20
-
21
- ACCORDION_VARIANT = {
22
- minimal: '',
23
- bordered: 'border rounded-lg',
24
- separated: 'space-y-2'
25
- }.freeze
26
-
27
- ACCORDION_SIZE = {
28
- small: 'text-sm',
29
- medium: 'text-base',
30
- large: 'text-lg'
31
- }.freeze
32
-
33
- def initialize(multiple: false, theme: :default, variant: :bordered, size: :medium,
34
- classes: '', **options)
35
- @multiple = multiple
36
- @theme = theme
37
- @variant = variant
38
- @size = size
39
- @classes = classes
40
- @options = options
41
-
42
- validate_params
43
- end
44
-
45
- private
46
-
47
- attr_reader :multiple, :theme, :variant, :size, :classes, :options
48
-
49
- def validate_params
50
- validate_theme
51
- validate_variant
52
- validate_size
53
- end
54
-
55
- def validate_theme
56
- return if ACCORDION_THEME.key?(theme)
57
-
58
- raise ArgumentError, "Invalid theme: #{theme}. Must be one of #{ACCORDION_THEME.keys}"
59
- end
60
-
61
- def validate_variant
62
- return if ACCORDION_VARIANT.key?(variant)
63
-
64
- raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{ACCORDION_VARIANT.keys}"
65
- end
66
-
67
- def validate_size
68
- return if ACCORDION_SIZE.key?(size)
69
-
70
- raise ArgumentError, "Invalid size: #{size}. Must be one of #{ACCORDION_SIZE.keys}"
71
- end
72
-
73
- # Attributi per il wrapper principale
74
- def wrapper_attributes
75
- base_classes = [
76
- 'bui-accordion',
77
- ACCORDION_SIZE[size],
78
- ACCORDION_VARIANT[variant],
79
- ACCORDION_THEME[theme],
80
- classes
81
- ].compact.join(' ')
82
-
83
- {
84
- class: base_classes,
85
- 'data-controller': 'bui-accordion',
86
- 'data-bui-accordion-multiple-value': multiple
87
- }.merge(options)
88
- end
89
- end
90
- end
91
- end
92
- end
@@ -1,12 +0,0 @@
1
- <div <%= tag.attributes(item_attributes) %>>
2
- <!-- Header -->
3
- <button <%= tag.attributes(header_attributes) %>>
4
- <span><%= title %></span>
5
- <i class="fas fa-<%= icon %> <%= icon_attributes[:class] %>" <%= tag.attributes(icon_attributes.except(:class)) %>></i>
6
- </button>
7
-
8
- <!-- Content -->
9
- <div <%= tag.attributes(content_attributes) %>>
10
- <%= content %>
11
- </div>
12
- </div>
@@ -1,176 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BetterUi
4
- module General
5
- module Accordion
6
- class ItemComponent < ViewComponent::Base
7
- ITEM_THEME = {
8
- default: 'border-gray-200 bg-white',
9
- white: 'border-gray-100 bg-white',
10
- blue: 'border-blue-200 bg-blue-50',
11
- red: 'border-red-200 bg-red-50',
12
- green: 'border-green-200 bg-green-50',
13
- yellow: 'border-yellow-200 bg-yellow-50',
14
- violet: 'border-violet-200 bg-violet-50',
15
- orange: 'border-orange-200 bg-orange-50',
16
- rose: 'border-rose-200 bg-rose-50'
17
- }.freeze
18
-
19
- ITEM_HEADER_THEME = {
20
- default: 'text-gray-900 hover:bg-gray-50',
21
- white: 'text-gray-900 hover:bg-gray-50',
22
- blue: 'text-blue-900 hover:bg-blue-100',
23
- red: 'text-red-900 hover:bg-red-100',
24
- green: 'text-green-900 hover:bg-green-100',
25
- yellow: 'text-yellow-900 hover:bg-yellow-100',
26
- violet: 'text-violet-900 hover:bg-violet-100',
27
- orange: 'text-orange-900 hover:bg-orange-100',
28
- rose: 'text-rose-900 hover:bg-rose-100'
29
- }.freeze
30
-
31
- ITEM_SIZE_HEADER = {
32
- small: 'text-sm px-4 py-3',
33
- medium: 'text-base px-5 py-4',
34
- large: 'text-lg px-6 py-5'
35
- }.freeze
36
-
37
- ITEM_SIZE_CONTENT = {
38
- small: 'px-4 py-3',
39
- medium: 'px-5 py-4',
40
- large: 'px-6 py-5'
41
- }.freeze
42
-
43
- ITEM_SIZE_ICON = {
44
- small: 'w-4 h-4',
45
- medium: 'w-5 h-5',
46
- large: 'w-6 h-6'
47
- }.freeze
48
-
49
- def initialize(title:, expanded: false, disabled: false, icon: 'chevron-down',
50
- theme: :default, size: :medium, classes: '', **options)
51
- @title = title
52
- @expanded = expanded
53
- @disabled = disabled
54
- @icon = icon
55
- @theme = theme
56
- @size = size
57
- @classes = classes
58
- @options = options
59
-
60
- validate_params
61
- end
62
-
63
- private
64
-
65
- attr_reader :title, :expanded, :disabled, :icon, :theme, :size, :classes, :options
66
-
67
- def validate_params
68
- validate_theme
69
- validate_size
70
-
71
- raise ArgumentError, 'title cannot be blank' if title.blank?
72
- end
73
-
74
- def validate_theme
75
- return if ITEM_THEME.key?(theme)
76
-
77
- raise ArgumentError, "Invalid theme: #{theme}. Must be one of #{ITEM_THEME.keys}"
78
- end
79
-
80
- def validate_size
81
- return if ITEM_SIZE_HEADER.key?(size)
82
-
83
- raise ArgumentError, "Invalid size: #{size}. Must be one of #{ITEM_SIZE_HEADER.keys}"
84
- end
85
-
86
- def unique_id
87
- @unique_id ||= "accordion-item-#{SecureRandom.hex(4)}"
88
- end
89
-
90
- def content_id
91
- "#{unique_id}-content"
92
- end
93
-
94
- def header_id
95
- "#{unique_id}-header"
96
- end
97
-
98
- # Attributi per il wrapper dell'item
99
- def item_attributes
100
- base_classes = [
101
- 'bui-accordion-item',
102
- ITEM_THEME[theme],
103
- classes
104
- ].compact.join(' ')
105
-
106
- {
107
- class: base_classes,
108
- 'data-bui-accordion-target': 'item'
109
- }.merge(options)
110
- end
111
-
112
- # Attributi per il button header
113
- def header_attributes
114
- base_classes = [
115
- 'bui-accordion-header',
116
- 'w-full flex items-center justify-between text-left font-medium transition-colors duration-200',
117
- ITEM_SIZE_HEADER[size],
118
- ITEM_HEADER_THEME[theme],
119
- disabled? ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
120
- ].compact.join(' ')
121
-
122
- {
123
- class: base_classes,
124
- type: 'button',
125
- id: header_id,
126
- 'aria-expanded': expanded,
127
- 'aria-controls': content_id,
128
- 'data-action': 'click->bui-accordion#toggle',
129
- 'data-bui-accordion-target': 'trigger',
130
- disabled: disabled
131
- }
132
- end
133
-
134
- # Attributi per il contenuto
135
- def content_attributes
136
- base_classes = [
137
- 'bui-accordion-content',
138
- 'transition-all duration-300 ease-in-out overflow-hidden',
139
- ITEM_SIZE_CONTENT[size],
140
- expanded? ? 'block' : 'hidden'
141
- ].compact.join(' ')
142
-
143
- {
144
- class: base_classes,
145
- id: content_id,
146
- 'aria-labelledby': header_id,
147
- 'data-bui-accordion-target': 'content'
148
- }
149
- end
150
-
151
- # Attributi per l'icona
152
- def icon_attributes
153
- base_classes = [
154
- 'bui-accordion-icon',
155
- 'transition-transform duration-200',
156
- ITEM_SIZE_ICON[size],
157
- expanded? ? 'rotate-180' : ''
158
- ].compact.join(' ')
159
-
160
- {
161
- class: base_classes,
162
- 'data-bui-accordion-target': 'icon'
163
- }
164
- end
165
-
166
- def disabled?
167
- disabled
168
- end
169
-
170
- def expanded?
171
- expanded
172
- end
173
- end
174
- end
175
- end
176
- end
@@ -1,32 +0,0 @@
1
- <div <%= tag.attributes(alert_attributes) %>>
2
- <% if (@icon.blank? ? default_icon : @icon) && @icon_position == :left %>
3
- <div class="<%= get_icon_classes %> <%= get_icon_theme_class %>">
4
- <%= render BetterUi::General::Icon::Component.new(name: @icon.blank? ? default_icon : @icon) %>
5
- </div>
6
- <% end %>
7
-
8
- <div class="<%= get_content_classes %>">
9
- <% if @title.present? %>
10
- <div class="<%= ALERT_TITLE_CLASSES %>"><%= @title %></div>
11
- <% end %>
12
- <div class="<%= ALERT_MESSAGE_CLASSES %>">
13
- <% if @html_content %>
14
- <%= raw @message %>
15
- <% else %>
16
- <%= @message %>
17
- <% end %>
18
- </div>
19
- </div>
20
-
21
- <% if (@icon.blank? ? default_icon : @icon) && @icon_position == :right %>
22
- <div class="<%= get_icon_classes %> <%= get_icon_theme_class %>">
23
- <%= render BetterUi::General::Icon::Component.new(name: @icon.blank? ? default_icon : @icon) %>
24
- </div>
25
- <% end %>
26
-
27
- <% if @dismissible %>
28
- <button type="button" class="<%= get_close_classes %>" aria-label="Chiudi">
29
- <%= render BetterUi::General::Icon::Component.new(name: "x", size: :sm) %>
30
- </button>
31
- <% end %>
32
- </div>
@@ -1,242 +0,0 @@
1
- module BetterUi
2
- module General
3
- module Alert
4
- class Component < ViewComponent::Base
5
- # Classi base sempre presenti
6
- ALERT_BASE_CLASSES = "flex p-4 mb-4 border"
7
-
8
- # Classi per elementi interni
9
- ALERT_ICON_CLASSES = "flex-shrink-0 mr-3 w-5 h-5"
10
- ALERT_ICON_RIGHT_CLASSES = "flex-shrink-0 ml-3 mr-0"
11
- ALERT_CONTENT_CLASSES = "flex-1"
12
- ALERT_TITLE_CLASSES = "font-medium mb-1"
13
- ALERT_MESSAGE_CLASSES = "text-sm"
14
- ALERT_CLOSE_CLASSES = "ml-auto -my-1.5 -mr-1.5 p-1.5 rounded-md focus:ring-2 focus:ring-offset-2 hover:bg-gray-100"
15
-
16
- # Temi di alert con classi Tailwind dirette
17
- ALERT_THEME_CLASSES = {
18
- default: "bg-black text-white border-gray-900",
19
- white: "bg-white text-black border-gray-200",
20
- red: "bg-red-500 text-white border-red-600",
21
- rose: "bg-rose-500 text-white border-rose-600",
22
- orange: "bg-orange-500 text-white border-orange-600",
23
- green: "bg-green-500 text-white border-green-600",
24
- blue: "bg-blue-500 text-white border-blue-600",
25
- yellow: "bg-yellow-500 text-black border-yellow-600",
26
- violet: "bg-violet-500 text-white border-violet-600"
27
- }
28
-
29
- # Colori icone per ogni tema
30
- ALERT_ICON_THEME_CLASSES = {
31
- default: "text-white",
32
- white: "text-black",
33
- red: "text-white",
34
- rose: "text-white",
35
- orange: "text-white",
36
- green: "text-white",
37
- blue: "text-white",
38
- yellow: "text-black",
39
- violet: "text-white"
40
- }
41
-
42
- # Colori close button per ogni tema
43
- ALERT_CLOSE_THEME_CLASSES = {
44
- default: "text-white focus:ring-gray-600",
45
- white: "text-black focus:ring-gray-400",
46
- red: "text-white focus:ring-red-400",
47
- rose: "text-white focus:ring-rose-400",
48
- orange: "text-white focus:ring-orange-400",
49
- green: "text-white focus:ring-green-400",
50
- blue: "text-white focus:ring-blue-400",
51
- yellow: "text-black focus:ring-yellow-400",
52
- violet: "text-white focus:ring-violet-400"
53
- }
54
-
55
- # Border radius con classi Tailwind dirette
56
- ALERT_RADIUS_CLASSES = {
57
- none: "rounded-none",
58
- small: "rounded-sm",
59
- medium: "rounded-md",
60
- large: "rounded-lg",
61
- full: "rounded-full"
62
- }
63
-
64
- # Classi per layout quando icon è a destra
65
- ALERT_ICON_RIGHT_LAYOUT_CLASSES = "flex-row-reverse"
66
- ALERT_CONTENT_RIGHT_CLASSES = "text-right"
67
-
68
- # Classi per alert dismissible
69
- ALERT_DISMISSIBLE_CLASSES = "pr-12 relative"
70
- ALERT_CLOSE_POSITION_CLASSES = "absolute right-4 top-4"
71
-
72
- # Livelli di importanza con attributi ARIA
73
- IMPORTANCE_LEVELS = {
74
- high: { role: "alert", "aria-live": "assertive" },
75
- medium: { role: "status", "aria-live": "polite" },
76
- low: { role: "status", "aria-live": "polite" }
77
- }
78
-
79
- # @param title [String] titolo dell'alert (opzionale)
80
- # @param message [String] contenuto dell'alert
81
- # @param theme [Symbol] :default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet
82
- # @param icon [String] nome dell'icona (opzionale)
83
- # @param icon_position [Symbol] :left, :right posizione dell'icona
84
- # @param dismissible [Boolean] se l'alert può essere chiuso
85
- # @param rounded [Symbol] :none, :small, :medium, :large, :full arrotondamento degli angoli
86
- # @param importance [Symbol] :high, :medium, :low livello di importanza per accessibilità
87
- # @param html_content [Boolean] se il messaggio contiene HTML
88
- # @param classes [String] classi CSS aggiuntive
89
- # @param html_options [Hash] opzioni HTML per il container
90
- def initialize(
91
- title: nil,
92
- message: nil,
93
- theme: :white,
94
- icon: nil,
95
- icon_position: :left,
96
- dismissible: false,
97
- rounded: :medium,
98
- importance: :medium,
99
- html_content: false,
100
- classes: nil,
101
- **html_options
102
- )
103
- @title = title
104
- @message = message
105
- @theme = theme.to_sym
106
- @icon = icon
107
- @icon_position = icon_position.to_sym
108
- @dismissible = dismissible
109
- @rounded = rounded.to_sym
110
- @importance = importance.to_sym
111
- @html_content = html_content
112
- @classes = classes
113
- @html_options = html_options
114
-
115
- validate_params
116
- end
117
-
118
- def default_icon
119
- case @theme
120
- when :default then "bell"
121
- when :white then "information-circle"
122
- when :red, :rose then "exclamation-circle"
123
- when :orange then "bell"
124
- when :green then "check-circle"
125
- when :blue then "information-circle"
126
- when :yellow then "exclamation-triangle"
127
- when :violet then "shield-exclamation"
128
- else "information-circle"
129
- end
130
- end
131
-
132
- # Combina tutte le classi
133
- def combined_classes
134
- [
135
- ALERT_BASE_CLASSES,
136
- get_theme_class,
137
- get_border_radius_class,
138
- get_icon_position_class,
139
- @dismissible ? ALERT_DISMISSIBLE_CLASSES : nil,
140
- @classes,
141
- @html_options[:class]
142
- ].compact.join(" ")
143
- end
144
-
145
- # Restituisce gli attributi per l'alert
146
- def alert_attributes
147
- attrs = {
148
- class: combined_classes
149
- }
150
-
151
- # Aggiungi attributi ARIA in base al livello di importanza
152
- importance_attrs = IMPORTANCE_LEVELS[@importance] || IMPORTANCE_LEVELS[:medium]
153
- importance_attrs.each do |key, value|
154
- attrs[key] = value
155
- end
156
-
157
- # Aggiungi altri attributi HTML se presenti
158
- @html_options.except(:class).each do |key, value|
159
- attrs[key] = value
160
- end
161
-
162
- attrs
163
- end
164
-
165
- # Genera le classi del tema
166
- def get_theme_class
167
- ALERT_THEME_CLASSES[@theme] || ALERT_THEME_CLASSES[:white]
168
- end
169
-
170
- # Genera le classi per il border radius
171
- def get_border_radius_class
172
- ALERT_RADIUS_CLASSES[@rounded] || ALERT_RADIUS_CLASSES[:medium]
173
- end
174
-
175
- # Genera la classe per la posizione dell'icona (layout)
176
- def get_icon_position_class
177
- @icon_position == :right ? ALERT_ICON_RIGHT_LAYOUT_CLASSES : nil
178
- end
179
-
180
- # Genera le classi per l'icona
181
- def get_icon_classes
182
- if @icon_position == :right
183
- ALERT_ICON_RIGHT_CLASSES
184
- else
185
- ALERT_ICON_CLASSES
186
- end
187
- end
188
-
189
- # Genera le classi per il contenuto
190
- def get_content_classes
191
- if @icon_position == :right
192
- [ ALERT_CONTENT_CLASSES, ALERT_CONTENT_RIGHT_CLASSES ].join(" ")
193
- else
194
- ALERT_CONTENT_CLASSES
195
- end
196
- end
197
-
198
- # Genera le classi per l'icona del tema
199
- def get_icon_theme_class
200
- ALERT_ICON_THEME_CLASSES[@theme] || ALERT_ICON_THEME_CLASSES[:white]
201
- end
202
-
203
- # Genera le classi per il close button
204
- def get_close_classes
205
- base_classes = ALERT_CLOSE_CLASSES
206
- theme_classes = ALERT_CLOSE_THEME_CLASSES[@theme] || ALERT_CLOSE_THEME_CLASSES[:white]
207
- position_classes = @dismissible ? ALERT_CLOSE_POSITION_CLASSES : nil
208
-
209
- [ base_classes, theme_classes, position_classes ].compact.join(" ")
210
- end
211
-
212
- private
213
-
214
- def validate_params
215
- # Validazione tema
216
- valid_themes = ALERT_THEME_CLASSES.keys
217
- unless valid_themes.include?(@theme)
218
- raise ArgumentError, "Il tema deve essere uno tra: #{valid_themes.join(', ')}"
219
- end
220
-
221
- # Validazione border radius
222
- valid_radius = ALERT_RADIUS_CLASSES.keys
223
- unless valid_radius.include?(@rounded)
224
- raise ArgumentError, "Il border radius deve essere uno tra: #{valid_radius.join(', ')}"
225
- end
226
-
227
- # Validazione posizione icona
228
- valid_positions = [ :left, :right ]
229
- unless valid_positions.include?(@icon_position)
230
- raise ArgumentError, "La posizione dell'icona deve essere una tra: #{valid_positions.join(', ')}"
231
- end
232
-
233
- # Validazione livello di importanza
234
- valid_importance = IMPORTANCE_LEVELS.keys
235
- unless valid_importance.include?(@importance)
236
- raise ArgumentError, "Il livello di importanza deve essere uno tra: #{valid_importance.join(', ')}"
237
- end
238
- end
239
- end
240
- end
241
- end
242
- end