better_ui_tmp 0.5.1

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.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +211 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/builds/application.js +1 -0
  6. data/app/assets/builds/better_ui.css +1 -0
  7. data/app/assets/stylesheets/better_ui.scss +3 -0
  8. data/app/components/better_ui/application/main/component.html.erb +5 -0
  9. data/app/components/better_ui/application/main/component.rb +99 -0
  10. data/app/components/better_ui/application/navbar/component.html.erb +219 -0
  11. data/app/components/better_ui/application/navbar/component.rb +148 -0
  12. data/app/components/better_ui/application/sidebar/component.html.erb +184 -0
  13. data/app/components/better_ui/application/sidebar/component.rb +129 -0
  14. data/app/components/better_ui/general/alert/component.html.erb +32 -0
  15. data/app/components/better_ui/general/alert/component.rb +242 -0
  16. data/app/components/better_ui/general/avatar/component.html.erb +20 -0
  17. data/app/components/better_ui/general/avatar/component.rb +301 -0
  18. data/app/components/better_ui/general/badge/component.html.erb +23 -0
  19. data/app/components/better_ui/general/badge/component.rb +248 -0
  20. data/app/components/better_ui/general/breadcrumb/component.html.erb +15 -0
  21. data/app/components/better_ui/general/breadcrumb/component.rb +186 -0
  22. data/app/components/better_ui/general/button/component.html.erb +34 -0
  23. data/app/components/better_ui/general/button/component.rb +214 -0
  24. data/app/components/better_ui/general/card/component.html.erb +21 -0
  25. data/app/components/better_ui/general/card/component.rb +37 -0
  26. data/app/components/better_ui/general/container/component.html.erb +8 -0
  27. data/app/components/better_ui/general/container/component.rb +158 -0
  28. data/app/components/better_ui/general/divider/component.html.erb +10 -0
  29. data/app/components/better_ui/general/divider/component.rb +226 -0
  30. data/app/components/better_ui/general/heading/component.html.erb +22 -0
  31. data/app/components/better_ui/general/heading/component.rb +257 -0
  32. data/app/components/better_ui/general/icon/component.html.erb +1 -0
  33. data/app/components/better_ui/general/icon/component.rb +222 -0
  34. data/app/components/better_ui/general/link/component.html.erb +18 -0
  35. data/app/components/better_ui/general/link/component.rb +255 -0
  36. data/app/components/better_ui/general/panel/component.html.erb +28 -0
  37. data/app/components/better_ui/general/panel/component.rb +249 -0
  38. data/app/components/better_ui/general/progress/component.html.erb +11 -0
  39. data/app/components/better_ui/general/progress/component.rb +160 -0
  40. data/app/components/better_ui/general/spinner/component.html.erb +35 -0
  41. data/app/components/better_ui/general/spinner/component.rb +93 -0
  42. data/app/components/better_ui/general/table/component.html.erb +5 -0
  43. data/app/components/better_ui/general/table/component.rb +217 -0
  44. data/app/components/better_ui/general/table/tbody_component.html.erb +3 -0
  45. data/app/components/better_ui/general/table/tbody_component.rb +30 -0
  46. data/app/components/better_ui/general/table/td_component.html.erb +3 -0
  47. data/app/components/better_ui/general/table/td_component.rb +44 -0
  48. data/app/components/better_ui/general/table/tfoot_component.html.erb +3 -0
  49. data/app/components/better_ui/general/table/tfoot_component.rb +28 -0
  50. data/app/components/better_ui/general/table/th_component.html.erb +6 -0
  51. data/app/components/better_ui/general/table/th_component.rb +51 -0
  52. data/app/components/better_ui/general/table/thead_component.html.erb +3 -0
  53. data/app/components/better_ui/general/table/thead_component.rb +28 -0
  54. data/app/components/better_ui/general/table/tr_component.html.erb +3 -0
  55. data/app/components/better_ui/general/table/tr_component.rb +30 -0
  56. data/app/components/better_ui/general/tag/component.html.erb +3 -0
  57. data/app/components/better_ui/general/tag/component.rb +104 -0
  58. data/app/components/better_ui/general/tooltip/component.html.erb +7 -0
  59. data/app/components/better_ui/general/tooltip/component.rb +239 -0
  60. data/app/controllers/better_ui/application_controller.rb +5 -0
  61. data/app/helpers/better_ui/application/components/main/main_helper.rb +42 -0
  62. data/app/helpers/better_ui/application/components/main.rb +13 -0
  63. data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +51 -0
  64. data/app/helpers/better_ui/application/components/navbar.rb +13 -0
  65. data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +51 -0
  66. data/app/helpers/better_ui/application/components/sidebar.rb +13 -0
  67. data/app/helpers/better_ui/application_helper.rb +10 -0
  68. data/app/helpers/better_ui/form_helper.rb +5 -0
  69. data/app/helpers/better_ui/general/components/alert/alert_helper.rb +29 -0
  70. data/app/helpers/better_ui/general/components/alert.rb +13 -0
  71. data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +29 -0
  72. data/app/helpers/better_ui/general/components/avatar.rb +13 -0
  73. data/app/helpers/better_ui/general/components/badge/badge_helper.rb +53 -0
  74. data/app/helpers/better_ui/general/components/badge.rb +13 -0
  75. data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +37 -0
  76. data/app/helpers/better_ui/general/components/breadcrumb.rb +13 -0
  77. data/app/helpers/better_ui/general/components/button/button_helper.rb +65 -0
  78. data/app/helpers/better_ui/general/components/button.rb +13 -0
  79. data/app/helpers/better_ui/general/components/card/card_helper.rb +37 -0
  80. data/app/helpers/better_ui/general/components/card.rb +13 -0
  81. data/app/helpers/better_ui/general/components/container/container_helper.rb +60 -0
  82. data/app/helpers/better_ui/general/components/container.rb +13 -0
  83. data/app/helpers/better_ui/general/components/divider/divider_helper.rb +63 -0
  84. data/app/helpers/better_ui/general/components/divider.rb +13 -0
  85. data/app/helpers/better_ui/general/components/heading/heading_helper.rb +72 -0
  86. data/app/helpers/better_ui/general/components/heading.rb +13 -0
  87. data/app/helpers/better_ui/general/components/icon/icon_helper.rb +16 -0
  88. data/app/helpers/better_ui/general/components/icon.rb +13 -0
  89. data/app/helpers/better_ui/general/components/link/link_helper.rb +89 -0
  90. data/app/helpers/better_ui/general/components/link.rb +13 -0
  91. data/app/helpers/better_ui/general/components/panel/panel_helper.rb +83 -0
  92. data/app/helpers/better_ui/general/components/panel.rb +13 -0
  93. data/app/helpers/better_ui/general/components/progress/progress_helper.rb +53 -0
  94. data/app/helpers/better_ui/general/components/progress.rb +11 -0
  95. data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +17 -0
  96. data/app/helpers/better_ui/general/components/spinner.rb +10 -0
  97. data/app/helpers/better_ui/general/components/table/table_helper.rb +13 -0
  98. data/app/helpers/better_ui/general/components/table/tbody_helper.rb +13 -0
  99. data/app/helpers/better_ui/general/components/table/td_helper.rb +19 -0
  100. data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +13 -0
  101. data/app/helpers/better_ui/general/components/table/th_helper.rb +19 -0
  102. data/app/helpers/better_ui/general/components/table/thead_helper.rb +13 -0
  103. data/app/helpers/better_ui/general/components/table/tr_helper.rb +13 -0
  104. data/app/helpers/better_ui/general/components/table.rb +25 -0
  105. data/app/helpers/better_ui/general/components/tag/tag_helper.rb +26 -0
  106. data/app/helpers/better_ui/general/components/tag.rb +15 -0
  107. data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +60 -0
  108. data/app/helpers/better_ui/general/components/tooltip.rb +13 -0
  109. data/app/helpers/better_ui/general_helper.rb +24 -0
  110. data/app/helpers/better_ui_helper.rb +16 -0
  111. data/app/javascript/application.js +1 -0
  112. data/app/jobs/better_ui/application_job.rb +4 -0
  113. data/app/mailers/better_ui/application_mailer.rb +6 -0
  114. data/app/models/better_ui/application_record.rb +5 -0
  115. data/app/views/components/better_ui/general/table/_custom_body_row.html.erb +17 -0
  116. data/app/views/components/better_ui/general/table/_custom_footer_rows.html.erb +17 -0
  117. data/app/views/components/better_ui/general/table/_custom_header_rows.html.erb +12 -0
  118. data/app/views/layouts/component_preview.html.erb +32 -0
  119. data/config/initializers/lookbook.rb +23 -0
  120. data/config/routes.rb +3 -0
  121. data/lib/better_ui/engine.rb +109 -0
  122. data/lib/better_ui/version.rb +3 -0
  123. data/lib/better_ui.rb +37 -0
  124. data/lib/generators/better_ui/install_generator.rb +103 -0
  125. data/lib/generators/better_ui/stylesheet_generator.rb +159 -0
  126. data/lib/generators/better_ui/templates/components/_avatar.scss +200 -0
  127. data/lib/generators/better_ui/templates/components/_badge.scss +154 -0
  128. data/lib/generators/better_ui/templates/components/_breadcrumb.scss +106 -0
  129. data/lib/generators/better_ui/templates/components/_button.scss +109 -0
  130. data/lib/generators/better_ui/templates/components/_card.scss +60 -0
  131. data/lib/generators/better_ui/templates/components/_heading.scss +81 -0
  132. data/lib/generators/better_ui/templates/components/_icon.scss +134 -0
  133. data/lib/generators/better_ui/templates/components/_index.scss +17 -0
  134. data/lib/generators/better_ui/templates/components/_link.scss +100 -0
  135. data/lib/generators/better_ui/templates/components/_panel.scss +104 -0
  136. data/lib/generators/better_ui/templates/components/_spinner.scss +129 -0
  137. data/lib/generators/better_ui/templates/components/_table.scss +156 -0
  138. data/lib/generators/better_ui/templates/components/_variables.scss +0 -0
  139. data/lib/generators/better_ui/templates/components_stylesheet.scss +35 -0
  140. data/lib/generators/better_ui/templates/index.scss +18 -0
  141. data/lib/generators/better_ui/templates/initializer.rb +41 -0
  142. data/lib/tasks/better_ui_tasks.rake +4 -0
  143. metadata +260 -0
@@ -0,0 +1,255 @@
1
+ module BetterUi
2
+ module General
3
+ module Link
4
+ class Component < ViewComponent::Base
5
+ attr_reader :label, :href, :theme, :orientation, :style, :size, :icon, :active, :disabled, :data, :method, :target
6
+
7
+ # Classi base sempre presenti
8
+ LINK_BASE_CLASSES = "transition-colors duration-200 no-underline"
9
+
10
+ # Temi con classi Tailwind dirette - LOGICA CORRETTA
11
+ LINK_THEME_CLASSES = {
12
+ default: "text-white hover:text-gray-300", # Bianco per sfondi scuri
13
+ white: "text-gray-900 hover:text-gray-700", # Nero per sfondi chiari
14
+ red: "text-red-500 hover:text-red-600",
15
+ rose: "text-rose-500 hover:text-rose-600",
16
+ orange: "text-orange-500 hover:text-orange-600",
17
+ green: "text-green-500 hover:text-green-600",
18
+ blue: "text-blue-500 hover:text-blue-600",
19
+ yellow: "text-yellow-600 hover:text-yellow-700",
20
+ violet: "text-violet-500 hover:text-violet-600"
21
+ }
22
+
23
+ # Orientamenti con classi Tailwind dirette
24
+ LINK_ORIENTATION_CLASSES = {
25
+ horizontal: "inline-flex items-center",
26
+ vertical: "flex flex-col items-center"
27
+ }
28
+
29
+ # Stili con classi Tailwind dirette
30
+ LINK_STYLE_CLASSES = {
31
+ default: "",
32
+ underline: "underline",
33
+ bold: "font-bold",
34
+ text: "no-underline"
35
+ }
36
+
37
+ # Dimensioni con classi Tailwind dirette
38
+ LINK_SIZE_CLASSES = {
39
+ small: "text-sm",
40
+ medium: "text-base",
41
+ large: "text-lg"
42
+ }
43
+
44
+ # Stati con classi Tailwind dirette
45
+ LINK_STATE_CLASSES = {
46
+ normal: "",
47
+ active: "font-semibold",
48
+ disabled: "opacity-50 cursor-not-allowed pointer-events-none"
49
+ }
50
+
51
+ # @param label [String] testo del link
52
+ # @param href [String] URL di destinazione (nil per semplice testo)
53
+ # @param theme [Symbol] tema del colore (:default, :white, etc.)
54
+ # @param orientation [Symbol] orientamento (:horizontal, :vertical)
55
+ # @param style [Symbol] stile (:default, :underline, :bold, :text)
56
+ # @param size [Symbol] dimensione (:small, :medium, :large)
57
+ # @param icon [String] icona opzionale
58
+ # @param active [Boolean] stato attivo del link
59
+ # @param disabled [Boolean] stato disabilitato del link
60
+ # @param data [Hash] attributi data
61
+ # @param method [Symbol] metodo HTTP (per Turbo)
62
+ # @param target [String] target del link
63
+ # @param html_options [Hash] opzioni HTML aggiuntive
64
+ def initialize(
65
+ label:,
66
+ href: nil,
67
+ theme: :white,
68
+ orientation: :horizontal,
69
+ style: :default,
70
+ size: :medium,
71
+ icon: nil,
72
+ active: false,
73
+ disabled: false,
74
+ data: {},
75
+ method: nil,
76
+ target: nil,
77
+ **html_options
78
+ )
79
+ @label = label
80
+ @href = href
81
+ @theme = theme.to_sym
82
+ @orientation = orientation.to_sym
83
+ @style = style.to_sym
84
+ @size = size.to_sym
85
+ @icon = icon
86
+ @active = active
87
+ @disabled = disabled
88
+ @data = data || {}
89
+ @method = method
90
+ @target = target
91
+ @html_options = html_options
92
+
93
+ validate_params
94
+ end
95
+
96
+ # Determina se è un link attivo/corrente
97
+ def active?
98
+ @active
99
+ end
100
+
101
+ # Determina se è disabilitato
102
+ def disabled?
103
+ @disabled
104
+ end
105
+
106
+ # Determina se è un link o solo testo
107
+ def link?
108
+ @href.present? && !@disabled
109
+ end
110
+
111
+ # Combina tutte le classi CSS
112
+ def combined_classes
113
+ [
114
+ LINK_BASE_CLASSES,
115
+ get_theme_class,
116
+ get_orientation_class,
117
+ get_style_class,
118
+ get_size_class,
119
+ get_state_class,
120
+ @html_options[:class]
121
+ ].compact.join(" ")
122
+ end
123
+
124
+ # Classi per l'icona con dimensionamento proporzionale
125
+ def icon_classes
126
+ return "" unless @icon.present?
127
+
128
+ # Definisce spacing e dimensioni icona basate su size
129
+ base_spacing = case @orientation
130
+ when :horizontal
131
+ "mr-2"
132
+ when :vertical
133
+ "mb-1"
134
+ else
135
+ "mr-2"
136
+ end
137
+
138
+ icon_size = case @size
139
+ when :small
140
+ "w-4 h-4"
141
+ when :medium
142
+ "w-5 h-5"
143
+ when :large
144
+ "w-6 h-6"
145
+ else
146
+ "w-5 h-5"
147
+ end
148
+
149
+ "#{base_spacing} #{icon_size} inline-block"
150
+ end
151
+
152
+ # Classi per il testo
153
+ def text_classes
154
+ "inline-block"
155
+ end
156
+
157
+ # Restituisce gli attributi per il link/span
158
+ def element_attributes
159
+ attrs = @html_options.except(:class)
160
+ attrs[:class] = combined_classes
161
+
162
+ if link?
163
+ # Attributi specifici per i link
164
+ if @method.present?
165
+ attrs[:data] = @data.merge(turbo_method: @method)
166
+ elsif @data.present?
167
+ attrs[:data] = @data
168
+ end
169
+
170
+ attrs[:target] = @target if @target.present?
171
+ attrs[:aria] ||= {}
172
+ attrs[:aria][:current] = 'page' if active?
173
+ else
174
+ # Attributi per span (testo semplice o disabilitato)
175
+ attrs[:aria] ||= {}
176
+ attrs[:aria][:disabled] = true if disabled?
177
+ end
178
+
179
+ attrs
180
+ end
181
+
182
+ # Determina se mostrare l'icona
183
+ def show_icon?
184
+ @icon.present?
185
+ end
186
+
187
+ # Renderizza l'icona
188
+ def render_icon
189
+ return nil unless show_icon?
190
+
191
+ if @icon.is_a?(String)
192
+ render BetterUi::General::IconComponent.new(name: @icon)
193
+ else
194
+ @icon # Assumiamo che sia già un componente renderizzato
195
+ end
196
+ end
197
+
198
+ private
199
+
200
+ def get_theme_class
201
+ LINK_THEME_CLASSES[@theme] || LINK_THEME_CLASSES[:white]
202
+ end
203
+
204
+ def get_orientation_class
205
+ LINK_ORIENTATION_CLASSES[@orientation] || LINK_ORIENTATION_CLASSES[:horizontal]
206
+ end
207
+
208
+ def get_style_class
209
+ LINK_STYLE_CLASSES[@style] || LINK_STYLE_CLASSES[:default]
210
+ end
211
+
212
+ def get_size_class
213
+ LINK_SIZE_CLASSES[@size] || LINK_SIZE_CLASSES[:medium]
214
+ end
215
+
216
+ def get_state_class
217
+ return LINK_STATE_CLASSES[:disabled] if disabled?
218
+ return LINK_STATE_CLASSES[:active] if active?
219
+ LINK_STATE_CLASSES[:normal]
220
+ end
221
+
222
+ def validate_params
223
+ validate_theme
224
+ validate_orientation
225
+ validate_style
226
+ validate_size
227
+ end
228
+
229
+ def validate_theme
230
+ unless LINK_THEME_CLASSES.keys.include?(@theme)
231
+ raise ArgumentError, "Il tema deve essere uno tra: #{LINK_THEME_CLASSES.keys.join(', ')}"
232
+ end
233
+ end
234
+
235
+ def validate_orientation
236
+ unless LINK_ORIENTATION_CLASSES.keys.include?(@orientation)
237
+ raise ArgumentError, "L'orientamento deve essere uno tra: #{LINK_ORIENTATION_CLASSES.keys.join(', ')}"
238
+ end
239
+ end
240
+
241
+ def validate_style
242
+ unless LINK_STYLE_CLASSES.keys.include?(@style)
243
+ raise ArgumentError, "Lo stile deve essere uno tra: #{LINK_STYLE_CLASSES.keys.join(', ')}"
244
+ end
245
+ end
246
+
247
+ def validate_size
248
+ unless LINK_SIZE_CLASSES.keys.include?(@size)
249
+ raise ArgumentError, "La dimensione deve essere una tra: #{LINK_SIZE_CLASSES.keys.join(', ')}"
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,28 @@
1
+ <%# Template per il panel %>
2
+ <div <%= tag.attributes(panel_attributes) %>>
3
+ <% if show_header? %>
4
+ <div class="<%= header_classes %>">
5
+ <% if @header.present? %>
6
+ <%= raw @header %>
7
+ <% elsif @title.present? %>
8
+ <div class="<%= title_classes %>"><%= @title %></div>
9
+ <% end %>
10
+ </div>
11
+ <% end %>
12
+
13
+ <% if show_body? %>
14
+ <div class="<%= body_classes %>">
15
+ <% if @body.present? %>
16
+ <%= raw @body %>
17
+ <% elsif content.present? %>
18
+ <%= content %>
19
+ <% end %>
20
+ </div>
21
+ <% end %>
22
+
23
+ <% if show_footer? %>
24
+ <div class="<%= footer_classes %>">
25
+ <%= raw @footer %>
26
+ </div>
27
+ <% end %>
28
+ </div>
@@ -0,0 +1,249 @@
1
+ module BetterUi
2
+ module General
3
+ module Panel
4
+ class Component < ViewComponent::Base
5
+ attr_reader :header, :footer, :body, :title, :padding, :theme, :style, :radius
6
+
7
+ # Classi base sempre presenti
8
+ PANEL_BASE_CLASSES = "overflow-hidden"
9
+
10
+ # Temi con classi Tailwind dirette - LOGICA CORRETTA
11
+ PANEL_THEME_CLASSES = {
12
+ default: "bg-gray-800 border-gray-700", # Scuro per sfondi scuri
13
+ white: "bg-white border-gray-200", # Chiaro per sfondi chiari
14
+ red: "bg-red-50 border-red-200",
15
+ rose: "bg-rose-50 border-rose-200",
16
+ orange: "bg-orange-50 border-orange-200",
17
+ green: "bg-green-50 border-green-200",
18
+ blue: "bg-blue-50 border-blue-200",
19
+ yellow: "bg-yellow-50 border-yellow-200",
20
+ violet: "bg-violet-50 border-violet-200"
21
+ }
22
+
23
+ # Temi per testo - LOGICA CORRETTA
24
+ PANEL_TEXT_THEME_CLASSES = {
25
+ default: "text-white", # Testo bianco per sfondi scuri
26
+ white: "text-gray-900", # Testo nero per sfondi chiari
27
+ red: "text-red-900",
28
+ rose: "text-rose-900",
29
+ orange: "text-orange-900",
30
+ green: "text-green-900",
31
+ blue: "text-blue-900",
32
+ yellow: "text-yellow-900",
33
+ violet: "text-violet-900"
34
+ }
35
+
36
+ # Stili con classi Tailwind dirette
37
+ PANEL_STYLE_CLASSES = {
38
+ default: "border shadow-sm",
39
+ flat: "border-0",
40
+ raised: "border shadow-lg",
41
+ bordered: "border-2"
42
+ }
43
+
44
+ # Padding con classi Tailwind dirette
45
+ PANEL_PADDING_CLASSES = {
46
+ none: "p-0",
47
+ small: "p-2",
48
+ medium: "p-4",
49
+ large: "p-6"
50
+ }
51
+
52
+ # Radius con classi Tailwind dirette
53
+ PANEL_RADIUS_CLASSES = {
54
+ none: "rounded-none",
55
+ small: "rounded",
56
+ medium: "rounded-md",
57
+ large: "rounded-lg",
58
+ full: "rounded-full"
59
+ }
60
+
61
+ # @param title [String] titolo del pannello (opzionale)
62
+ # @param body [String] contenuto HTML del pannello (opzionale)
63
+ # @param header [String] header personalizzato (opzionale)
64
+ # @param footer [String] footer del pannello (opzionale)
65
+ # @param theme [Symbol] tema del colore (:default, :white, etc.)
66
+ # @param style [Symbol] stile (:default, :flat, :raised, :bordered)
67
+ # @param padding [Symbol] padding interno (:none, :small, :medium, :large)
68
+ # @param radius [Symbol] raggio dei bordi (:none, :small, :medium, :large, :full)
69
+ # @param html_options [Hash] opzioni HTML aggiuntive
70
+ def initialize(
71
+ title: nil,
72
+ body: nil,
73
+ header: nil,
74
+ footer: nil,
75
+ theme: :white,
76
+ style: :default,
77
+ padding: :medium,
78
+ radius: :small,
79
+ **html_options
80
+ )
81
+ @title = title
82
+ @body = body
83
+ @header = header
84
+ @footer = footer
85
+ @theme = theme.to_sym
86
+ @style = style.to_sym
87
+ @padding = padding.to_sym
88
+ @radius = radius.to_sym
89
+ @html_options = html_options
90
+
91
+ validate_params
92
+ end
93
+
94
+ # Combina tutte le classi CSS per il panel
95
+ def combined_classes
96
+ [
97
+ PANEL_BASE_CLASSES,
98
+ get_theme_class,
99
+ get_style_class,
100
+ get_radius_class,
101
+ @html_options[:class]
102
+ ].compact.join(" ")
103
+ end
104
+
105
+ # Restituisce gli attributi HTML per il panel
106
+ def panel_attributes
107
+ attrs = @html_options.except(:class)
108
+ attrs[:class] = combined_classes
109
+ attrs
110
+ end
111
+
112
+ # Classi per l'header
113
+ def header_classes
114
+ [
115
+ "border-b",
116
+ get_border_theme_class,
117
+ get_text_theme_class,
118
+ get_padding_class
119
+ ].compact.join(" ")
120
+ end
121
+
122
+ # Classi per il body
123
+ def body_classes
124
+ [
125
+ get_text_theme_class,
126
+ get_padding_class
127
+ ].compact.join(" ")
128
+ end
129
+
130
+ # Classi per il footer
131
+ def footer_classes
132
+ [
133
+ "border-t",
134
+ get_border_theme_class,
135
+ get_text_theme_class,
136
+ get_padding_class
137
+ ].compact.join(" ")
138
+ end
139
+
140
+ # Classi per il title
141
+ def title_classes
142
+ [
143
+ "font-semibold text-lg leading-6",
144
+ get_text_theme_class
145
+ ].compact.join(" ")
146
+ end
147
+
148
+ # Determina se il pannello deve essere renderizzato
149
+ def render?
150
+ @body.present? || @header.present? || @footer.present? || content.present?
151
+ end
152
+
153
+ # Determina se mostrare l'header
154
+ def show_header?
155
+ @header.present? || @title.present?
156
+ end
157
+
158
+ # Determina se mostrare il body
159
+ def show_body?
160
+ @body.present? || content.present?
161
+ end
162
+
163
+ # Determina se mostrare il footer
164
+ def show_footer?
165
+ @footer.present?
166
+ end
167
+
168
+ private
169
+
170
+ def get_theme_class
171
+ PANEL_THEME_CLASSES[@theme] || PANEL_THEME_CLASSES[:white]
172
+ end
173
+
174
+ def get_text_theme_class
175
+ PANEL_TEXT_THEME_CLASSES[@theme] || PANEL_TEXT_THEME_CLASSES[:white]
176
+ end
177
+
178
+ def get_border_theme_class
179
+ # Usa lo stesso colore del bordo principale ma più leggero per i separatori interni
180
+ case @theme
181
+ when :default
182
+ "border-gray-600"
183
+ when :white
184
+ "border-gray-100"
185
+ when :red
186
+ "border-red-100"
187
+ when :rose
188
+ "border-rose-100"
189
+ when :orange
190
+ "border-orange-100"
191
+ when :green
192
+ "border-green-100"
193
+ when :blue
194
+ "border-blue-100"
195
+ when :yellow
196
+ "border-yellow-100"
197
+ when :violet
198
+ "border-violet-100"
199
+ else
200
+ "border-gray-100"
201
+ end
202
+ end
203
+
204
+ def get_style_class
205
+ PANEL_STYLE_CLASSES[@style] || PANEL_STYLE_CLASSES[:default]
206
+ end
207
+
208
+ def get_radius_class
209
+ PANEL_RADIUS_CLASSES[@radius] || PANEL_RADIUS_CLASSES[:small]
210
+ end
211
+
212
+ def get_padding_class
213
+ PANEL_PADDING_CLASSES[@padding] || PANEL_PADDING_CLASSES[:medium]
214
+ end
215
+
216
+ def validate_params
217
+ validate_theme
218
+ validate_style
219
+ validate_padding
220
+ validate_radius
221
+ end
222
+
223
+ def validate_theme
224
+ unless PANEL_THEME_CLASSES.keys.include?(@theme)
225
+ raise ArgumentError, "Il tema deve essere uno tra: #{PANEL_THEME_CLASSES.keys.join(', ')}"
226
+ end
227
+ end
228
+
229
+ def validate_style
230
+ unless PANEL_STYLE_CLASSES.keys.include?(@style)
231
+ raise ArgumentError, "Lo stile deve essere uno tra: #{PANEL_STYLE_CLASSES.keys.join(', ')}"
232
+ end
233
+ end
234
+
235
+ def validate_padding
236
+ unless PANEL_PADDING_CLASSES.keys.include?(@padding)
237
+ raise ArgumentError, "Il padding deve essere uno tra: #{PANEL_PADDING_CLASSES.keys.join(', ')}"
238
+ end
239
+ end
240
+
241
+ def validate_radius
242
+ unless PANEL_RADIUS_CLASSES.keys.include?(@radius)
243
+ raise ArgumentError, "Il raggio deve essere uno tra: #{PANEL_RADIUS_CLASSES.keys.join(', ')}"
244
+ end
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,11 @@
1
+ <div class="bui-progress-wrapper">
2
+ <div <%= progress_attributes.map { |k, v| "#{k}=\"#{v}\"" }.join(' ').html_safe %>>
3
+ <div <%= bar_attributes.map { |k, v| "#{k}=\"#{v}\"" }.join(' ').html_safe %>></div>
4
+ </div>
5
+
6
+ <% if show_label? %>
7
+ <div class="bui-progress-label mt-1 text-sm text-gray-600 text-center">
8
+ <%= value %>%
9
+ </div>
10
+ <% end %>
11
+ </div>
@@ -0,0 +1,160 @@
1
+ module BetterUi
2
+ module General
3
+ module Progress
4
+ class Component < ViewComponent::Base
5
+ # Classi base sempre presenti
6
+ PROGRESS_BASE_CLASSES = "relative w-full bg-gray-200 rounded-full overflow-hidden"
7
+
8
+ # Classi per la barra di progresso
9
+ PROGRESS_BAR_BASE_CLASSES = "h-full transition-all duration-300 ease-in-out"
10
+
11
+ # Dimensioni della progress bar con classi Tailwind dirette
12
+ PROGRESS_SIZES = {
13
+ small: "h-2",
14
+ medium: "h-4",
15
+ large: "h-6"
16
+ }
17
+
18
+ # Temi di progress bar con classi Tailwind dirette
19
+ PROGRESS_THEMES = {
20
+ default: "bg-gray-600",
21
+ white: "bg-white border border-gray-300",
22
+ red: "bg-red-600",
23
+ rose: "bg-rose-600",
24
+ orange: "bg-orange-600",
25
+ green: "bg-green-600",
26
+ blue: "bg-blue-600",
27
+ yellow: "bg-yellow-600",
28
+ violet: "bg-violet-600"
29
+ }
30
+
31
+ # Classi per il background container
32
+ PROGRESS_CONTAINER_THEMES = {
33
+ default: "bg-gray-200",
34
+ white: "bg-gray-100",
35
+ red: "bg-red-100",
36
+ rose: "bg-rose-100",
37
+ orange: "bg-orange-100",
38
+ green: "bg-green-100",
39
+ blue: "bg-blue-100",
40
+ yellow: "bg-yellow-100",
41
+ violet: "bg-violet-100"
42
+ }
43
+
44
+ # @param value [Integer] percentuale di completamento (0-100)
45
+ # @param theme [Symbol] :default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet
46
+ # @param size [Symbol] :small, :medium, :large
47
+ # @param label [Boolean] mostra etichetta con percentuale
48
+ # @param classes [String] classi CSS aggiuntive per il container
49
+ # @param html_options [Hash] opzioni HTML per il container
50
+ def initialize(
51
+ value: 0,
52
+ theme: :white,
53
+ size: :medium,
54
+ label: false,
55
+ classes: nil,
56
+ **html_options
57
+ )
58
+ @value = [0, [value.to_i, 100].min].max # Clamp tra 0 e 100
59
+ @theme = theme.to_sym
60
+ @size = size.to_sym
61
+ @label = label
62
+ @classes = classes
63
+ @html_options = html_options
64
+
65
+ validate_params
66
+ end
67
+
68
+ # Combina tutte le classi per il container
69
+ def combined_classes
70
+ [
71
+ PROGRESS_BASE_CLASSES,
72
+ get_size_class,
73
+ get_container_theme_class,
74
+ @classes,
75
+ @html_options[:class]
76
+ ].compact.join(" ")
77
+ end
78
+
79
+ # Combina tutte le classi per la barra di progresso
80
+ def bar_classes
81
+ [
82
+ PROGRESS_BAR_BASE_CLASSES,
83
+ get_theme_class
84
+ ].compact.join(" ")
85
+ end
86
+
87
+ # Restituisce gli attributi per il container della progress bar
88
+ def progress_attributes
89
+ attrs = {
90
+ class: combined_classes,
91
+ role: "progressbar",
92
+ "aria-valuenow": @value,
93
+ "aria-valuemin": 0,
94
+ "aria-valuemax": 100,
95
+ "aria-label": "Progresso: #{@value}%"
96
+ }
97
+
98
+ # Aggiungi altri attributi HTML se presenti
99
+ @html_options.except(:class).each do |key, value|
100
+ attrs[key] = value
101
+ end
102
+
103
+ attrs
104
+ end
105
+
106
+ # Restituisce gli attributi per la barra di progresso
107
+ def bar_attributes
108
+ {
109
+ class: bar_classes,
110
+ style: "width: #{@value}%"
111
+ }
112
+ end
113
+
114
+ # Restituisce il valore percentuale
115
+ attr_reader :value
116
+
117
+ # Verifica se mostrare l'etichetta
118
+ def show_label?
119
+ @label
120
+ end
121
+
122
+ private
123
+
124
+ def validate_params
125
+ validate_theme
126
+ validate_size
127
+ end
128
+
129
+ def validate_theme
130
+ valid_themes = PROGRESS_THEMES.keys
131
+ unless valid_themes.include?(@theme)
132
+ raise ArgumentError, "Il tema deve essere uno tra: #{valid_themes.join(', ')}"
133
+ end
134
+ end
135
+
136
+ def validate_size
137
+ valid_sizes = PROGRESS_SIZES.keys
138
+ unless valid_sizes.include?(@size)
139
+ raise ArgumentError, "La dimensione deve essere una tra: #{valid_sizes.join(', ')}"
140
+ end
141
+ end
142
+
143
+ # Genera le classi per la dimensione
144
+ def get_size_class
145
+ PROGRESS_SIZES[@size] || PROGRESS_SIZES[:medium]
146
+ end
147
+
148
+ # Genera le classi per il tema della barra
149
+ def get_theme_class
150
+ PROGRESS_THEMES[@theme] || PROGRESS_THEMES[:white]
151
+ end
152
+
153
+ # Genera le classi per il tema del container
154
+ def get_container_theme_class
155
+ PROGRESS_CONTAINER_THEMES[@theme] || PROGRESS_CONTAINER_THEMES[:white]
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end