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,257 @@
1
+ module BetterUi
2
+ module General
3
+ module Heading
4
+ class Component < ViewComponent::Base
5
+ attr_reader :level, :theme, :align, :size, :style, :icon, :subtitle, :with_divider
6
+
7
+ # Classi base sempre presenti
8
+ HEADING_BASE_CLASSES = "font-bold leading-tight"
9
+
10
+ # Temi con classi Tailwind dirette - LOGICA CORRETTA
11
+ HEADING_THEME_CLASSES = {
12
+ default: "text-white", # Testo bianco (per sfondi scuri)
13
+ white: "text-gray-900", # Testo nero (per sfondi chiari)
14
+ red: "text-red-500",
15
+ rose: "text-rose-500",
16
+ orange: "text-orange-500",
17
+ green: "text-green-500",
18
+ blue: "text-blue-500",
19
+ yellow: "text-yellow-600",
20
+ violet: "text-violet-500",
21
+ purple: "text-purple-500"
22
+ }
23
+
24
+ # Allineamenti con classi Tailwind dirette
25
+ HEADING_ALIGN_CLASSES = {
26
+ left: "text-left",
27
+ center: "text-center",
28
+ right: "text-right"
29
+ }
30
+
31
+ # Dimensioni base (verranno combinate con level)
32
+ HEADING_SIZE_CLASSES = {
33
+ small: {
34
+ 1 => "text-2xl sm:text-3xl",
35
+ 2 => "text-xl sm:text-2xl",
36
+ 3 => "text-lg sm:text-xl",
37
+ 4 => "text-base sm:text-lg",
38
+ 5 => "text-sm sm:text-base",
39
+ 6 => "text-xs sm:text-sm"
40
+ },
41
+ medium: {
42
+ 1 => "text-3xl sm:text-4xl",
43
+ 2 => "text-2xl sm:text-3xl",
44
+ 3 => "text-xl sm:text-2xl",
45
+ 4 => "text-lg sm:text-xl",
46
+ 5 => "text-base sm:text-lg",
47
+ 6 => "text-sm sm:text-base"
48
+ },
49
+ large: {
50
+ 1 => "text-4xl sm:text-5xl",
51
+ 2 => "text-3xl sm:text-4xl",
52
+ 3 => "text-2xl sm:text-3xl",
53
+ 4 => "text-xl sm:text-2xl",
54
+ 5 => "text-lg sm:text-xl",
55
+ 6 => "text-base sm:text-lg"
56
+ }
57
+ }
58
+
59
+ # Stili con classi Tailwind dirette
60
+ HEADING_STYLE_CLASSES = {
61
+ normal: "",
62
+ bold: "font-extrabold",
63
+ italic: "italic",
64
+ underline: "underline"
65
+ }
66
+
67
+ # Temi per subtitle - LOGICA CORRETTA
68
+ HEADING_SUBTITLE_THEME_CLASSES = {
69
+ default: "text-gray-300", # Testo grigio chiaro (per sfondi scuri)
70
+ white: "text-gray-600", # Testo grigio scuro (per sfondi chiari)
71
+ red: "text-red-400",
72
+ rose: "text-rose-400",
73
+ orange: "text-orange-400",
74
+ green: "text-green-400",
75
+ blue: "text-blue-400",
76
+ yellow: "text-yellow-500",
77
+ violet: "text-violet-400"
78
+ }
79
+
80
+ # Temi per divider - LOGICA CORRETTA
81
+ HEADING_DIVIDER_THEME_CLASSES = {
82
+ default: "border-gray-700", # Bordo grigio scuro (per sfondi scuri)
83
+ white: "border-gray-200", # Bordo grigio chiaro (per sfondi chiari)
84
+ red: "border-red-200",
85
+ rose: "border-rose-200",
86
+ orange: "border-orange-200",
87
+ green: "border-green-200",
88
+ blue: "border-blue-200",
89
+ yellow: "border-yellow-200",
90
+ violet: "border-violet-200"
91
+ }
92
+
93
+ # @param level [Integer] livello del heading (1-6)
94
+ # @param theme [Symbol] tema del colore (:default, :white, etc.)
95
+ # @param align [Symbol] allineamento (:left, :center, :right)
96
+ # @param size [Symbol] dimensione (:small, :medium, :large)
97
+ # @param style [Symbol] stile (:normal, :bold, :italic, :underline)
98
+ # @param icon [String] icona opzionale
99
+ # @param subtitle [String] sottotitolo opzionale
100
+ # @param with_divider [Boolean] mostra linea divisoria
101
+ # @param html_options [Hash] opzioni HTML per il container
102
+ def initialize(
103
+ level: 2,
104
+ theme: :white,
105
+ align: :left,
106
+ size: :medium,
107
+ style: :normal,
108
+ icon: nil,
109
+ subtitle: nil,
110
+ with_divider: false,
111
+ **html_options
112
+ )
113
+ @level = level.to_i.clamp(1, 6)
114
+ @theme = theme.to_sym
115
+ @align = align.to_sym
116
+ @size = size.to_sym
117
+ @style = style.to_sym
118
+ @icon = icon
119
+ @subtitle = subtitle
120
+ @with_divider = with_divider
121
+ @html_options = html_options
122
+
123
+ validate_params
124
+ end
125
+
126
+ # Combina tutte le classi per il heading
127
+ def heading_classes
128
+ [
129
+ HEADING_BASE_CLASSES,
130
+ get_theme_class,
131
+ get_align_class,
132
+ get_size_class,
133
+ get_style_class,
134
+ @html_options[:class]
135
+ ].compact.join(" ")
136
+ end
137
+
138
+ # Classi per il container principale
139
+ def container_classes
140
+ "mb-4"
141
+ end
142
+
143
+ # Classi per il subtitle
144
+ def subtitle_classes
145
+ return "" unless @subtitle.present?
146
+
147
+ [
148
+ "mt-1 text-sm",
149
+ get_subtitle_theme_class,
150
+ get_align_class
151
+ ].compact.join(" ")
152
+ end
153
+
154
+ # Classi per il divider
155
+ def divider_classes
156
+ return "" unless @with_divider
157
+
158
+ [
159
+ "mt-2 border-t",
160
+ get_divider_theme_class
161
+ ].compact.join(" ")
162
+ end
163
+
164
+ # Classi per l'icona
165
+ def icon_classes
166
+ return "" unless @icon.present?
167
+ "mr-2 inline-block"
168
+ end
169
+
170
+ # Restituisce gli attributi HTML per il heading
171
+ def heading_attributes
172
+ attrs = @html_options.except(:class)
173
+ attrs[:class] = heading_classes
174
+ attrs
175
+ end
176
+
177
+ # Tag del heading basato sul level
178
+ def heading_tag
179
+ "h#{@level}"
180
+ end
181
+
182
+ # Determina se mostrare l'icona
183
+ def show_icon?
184
+ @icon.present?
185
+ end
186
+
187
+ # Determina se mostrare il subtitle
188
+ def show_subtitle?
189
+ @subtitle.present?
190
+ end
191
+
192
+ # Determina se mostrare il divider
193
+ def show_divider?
194
+ @with_divider
195
+ end
196
+
197
+ private
198
+
199
+ def get_theme_class
200
+ HEADING_THEME_CLASSES[@theme] || HEADING_THEME_CLASSES[:white]
201
+ end
202
+
203
+ def get_align_class
204
+ HEADING_ALIGN_CLASSES[@align] || HEADING_ALIGN_CLASSES[:left]
205
+ end
206
+
207
+ def get_size_class
208
+ size_map = HEADING_SIZE_CLASSES[@size] || HEADING_SIZE_CLASSES[:medium]
209
+ size_map[@level] || size_map[2]
210
+ end
211
+
212
+ def get_style_class
213
+ HEADING_STYLE_CLASSES[@style] || HEADING_STYLE_CLASSES[:normal]
214
+ end
215
+
216
+ def get_subtitle_theme_class
217
+ HEADING_SUBTITLE_THEME_CLASSES[@theme] || HEADING_SUBTITLE_THEME_CLASSES[:white]
218
+ end
219
+
220
+ def get_divider_theme_class
221
+ HEADING_DIVIDER_THEME_CLASSES[@theme] || HEADING_DIVIDER_THEME_CLASSES[:white]
222
+ end
223
+
224
+ def validate_params
225
+ validate_theme
226
+ validate_align
227
+ validate_size
228
+ validate_style
229
+ end
230
+
231
+ def validate_theme
232
+ unless HEADING_THEME_CLASSES.keys.include?(@theme)
233
+ raise ArgumentError, "Il tema deve essere uno tra: #{HEADING_THEME_CLASSES.keys.join(', ')}"
234
+ end
235
+ end
236
+
237
+ def validate_align
238
+ unless HEADING_ALIGN_CLASSES.keys.include?(@align)
239
+ raise ArgumentError, "L'allineamento deve essere uno tra: #{HEADING_ALIGN_CLASSES.keys.join(', ')}"
240
+ end
241
+ end
242
+
243
+ def validate_size
244
+ unless HEADING_SIZE_CLASSES.keys.include?(@size)
245
+ raise ArgumentError, "La dimensione deve essere una tra: #{HEADING_SIZE_CLASSES.keys.join(', ')}"
246
+ end
247
+ end
248
+
249
+ def validate_style
250
+ unless HEADING_STYLE_CLASSES.keys.include?(@style)
251
+ raise ArgumentError, "Lo stile deve essere uno tra: #{HEADING_STYLE_CLASSES.keys.join(', ')}"
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1 @@
1
+ <i class="<%= fa_class_name %> <%= icon_classes %>"></i>
@@ -0,0 +1,222 @@
1
+ module BetterUi
2
+ module General
3
+ module Icon
4
+ class Component < ViewComponent::Base
5
+ # Classi base per l'icona con nomenclatura BEM
6
+ ICON_BASE_CLASSES = "bui-icon inline-flex items-center justify-center"
7
+
8
+ # Dimensioni dell'icona (standardizzate: small, medium, large)
9
+ ICON_SIZE_CLASSES = {
10
+ small: "bui-icon--small w-4 h-4 text-sm",
11
+ medium: "bui-icon--medium w-5 h-5 text-base",
12
+ large: "bui-icon--large w-6 h-6 text-lg"
13
+ }.freeze
14
+
15
+ # Temi dell'icona con colori coerenti
16
+ ICON_THEME_CLASSES = {
17
+ default: "bui-icon--default text-gray-600",
18
+ white: "bui-icon--white text-white",
19
+ red: "bui-icon--red text-red-600",
20
+ rose: "bui-icon--rose text-rose-600",
21
+ orange: "bui-icon--orange text-orange-600",
22
+ green: "bui-icon--green text-green-600",
23
+ blue: "bui-icon--blue text-blue-600",
24
+ yellow: "bui-icon--yellow text-yellow-600",
25
+ violet: "bui-icon--violet text-violet-600",
26
+ purple: "bui-icon--purple text-purple-600"
27
+ }.freeze
28
+
29
+ # Animazioni disponibili
30
+ ICON_ANIMATION_CLASSES = {
31
+ spin: "bui-icon--spin animate-spin",
32
+ pulse: "bui-icon--pulse animate-pulse"
33
+ }.freeze
34
+
35
+ # Trasformazioni disponibili
36
+ ICON_ROTATION_CLASSES = {
37
+ 90 => "bui-icon--rotate-90 transform rotate-90",
38
+ 180 => "bui-icon--rotate-180 transform rotate-180",
39
+ 270 => "bui-icon--rotate-270 transform rotate-270"
40
+ }.freeze
41
+
42
+ ICON_FLIP_CLASSES = {
43
+ horizontal: "bui-icon--flip-h transform scale-x-[-1]",
44
+ vertical: "bui-icon--flip-v transform scale-y-[-1]",
45
+ both: "bui-icon--flip-both transform scale-[-1]"
46
+ }.freeze
47
+
48
+ # Bordo e larghezza fissa
49
+ ICON_BORDER_CLASSES = "bui-icon--border border border-current rounded-full p-1"
50
+ ICON_FIXED_WIDTH_CLASSES = "bui-icon--fixed-width w-5"
51
+
52
+ attr_reader :name, :style, :size, :theme, :spin, :pulse, :border, :fixed_width,
53
+ :rotation, :flip, :classes, :id, :html_options
54
+
55
+ # @param name [String] Nome dell'icona (richiesto)
56
+ # @param style [Symbol] Stile dell'icona (:solid, :regular, :brands)
57
+ # @param size [Symbol] Dimensione (:small, :medium, :large)
58
+ # @param theme [Symbol] Tema colore (:default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet)
59
+ # @param spin [Boolean] Rotazione continua
60
+ # @param pulse [Boolean] Animazione pulsazione
61
+ # @param border [Boolean] Mostra bordo attorno all'icona
62
+ # @param fixed_width [Boolean] Larghezza fissa per allineamento
63
+ # @param rotation [Integer] Rotazione in gradi (0, 90, 180, 270)
64
+ # @param flip [Symbol] Tipo di flip (:horizontal, :vertical, :both)
65
+ # @param classes [String] Classi CSS aggiuntive
66
+ # @param id [String] ID HTML
67
+ # @param html_options [Hash] Attributi HTML aggiuntivi
68
+ def initialize(
69
+ name:,
70
+ style: :solid,
71
+ size: :medium,
72
+ theme: :default,
73
+ spin: false,
74
+ pulse: false,
75
+ border: false,
76
+ fixed_width: false,
77
+ rotation: nil,
78
+ flip: nil,
79
+ classes: nil,
80
+ id: nil,
81
+ **html_options
82
+ )
83
+ @name = name
84
+ @style = style.to_sym
85
+ @size = size.to_sym
86
+ @theme = theme.to_sym
87
+ @spin = spin
88
+ @pulse = pulse
89
+ @border = border
90
+ @fixed_width = fixed_width
91
+ @rotation = rotation&.to_i
92
+ @flip = flip&.to_sym
93
+ @classes = classes
94
+ @id = id
95
+ @html_options = html_options
96
+
97
+ validate_params!
98
+ end
99
+
100
+ # Genera le classi CSS complete per l'icona
101
+ def icon_classes
102
+ classes = [
103
+ ICON_BASE_CLASSES,
104
+ size_classes,
105
+ theme_classes,
106
+ animation_classes,
107
+ transformation_classes,
108
+ border_classes,
109
+ fixed_width_classes,
110
+ @classes
111
+ ].compact.join(" ")
112
+ end
113
+
114
+ # Attributi HTML per l'elemento icona
115
+ def icon_attributes
116
+ {
117
+ class: icon_classes,
118
+ id: @id,
119
+ **@html_options
120
+ }.compact
121
+ end
122
+
123
+ # Nome completo della classe FontAwesome basato su stile
124
+ def fa_class_name
125
+ prefix = case @style
126
+ when :solid then "fas"
127
+ when :regular then "far"
128
+ when :brands then "fab"
129
+ else "fas"
130
+ end
131
+
132
+ "#{prefix} fa-#{@name}"
133
+ end
134
+
135
+ # Verifica se il componente deve essere renderizzato
136
+ def render?
137
+ @name.present?
138
+ end
139
+
140
+ private
141
+
142
+ def validate_params!
143
+ validate_name!
144
+ validate_style!
145
+ validate_size!
146
+ validate_theme!
147
+ validate_rotation!
148
+ validate_flip!
149
+ end
150
+
151
+ def validate_name!
152
+ raise ArgumentError, "Il nome dell'icona è richiesto" if @name.blank?
153
+ end
154
+
155
+ def validate_style!
156
+ valid_styles = [:solid, :regular, :brands]
157
+ unless valid_styles.include?(@style)
158
+ raise ArgumentError, "Lo stile deve essere uno tra: #{valid_styles.join(', ')}"
159
+ end
160
+ end
161
+
162
+ def validate_size!
163
+ unless ICON_SIZE_CLASSES.key?(@size)
164
+ valid_sizes = ICON_SIZE_CLASSES.keys
165
+ raise ArgumentError, "La dimensione deve essere una tra: #{valid_sizes.join(', ')}"
166
+ end
167
+ end
168
+
169
+ def validate_theme!
170
+ unless ICON_THEME_CLASSES.key?(@theme)
171
+ valid_themes = ICON_THEME_CLASSES.keys
172
+ raise ArgumentError, "Il tema deve essere uno tra: #{valid_themes.join(', ')}"
173
+ end
174
+ end
175
+
176
+ def validate_rotation!
177
+ if @rotation && !ICON_ROTATION_CLASSES.key?(@rotation)
178
+ valid_rotations = ICON_ROTATION_CLASSES.keys
179
+ raise ArgumentError, "La rotazione deve essere una tra: #{valid_rotations.join(', ')}"
180
+ end
181
+ end
182
+
183
+ def validate_flip!
184
+ if @flip && !ICON_FLIP_CLASSES.key?(@flip)
185
+ valid_flips = ICON_FLIP_CLASSES.keys
186
+ raise ArgumentError, "Il flip deve essere uno tra: #{valid_flips.join(', ')}"
187
+ end
188
+ end
189
+
190
+ def size_classes
191
+ ICON_SIZE_CLASSES[@size]
192
+ end
193
+
194
+ def theme_classes
195
+ ICON_THEME_CLASSES[@theme]
196
+ end
197
+
198
+ def animation_classes
199
+ animations = []
200
+ animations << ICON_ANIMATION_CLASSES[:spin] if @spin
201
+ animations << ICON_ANIMATION_CLASSES[:pulse] if @pulse
202
+ animations.join(" ")
203
+ end
204
+
205
+ def transformation_classes
206
+ transformations = []
207
+ transformations << ICON_ROTATION_CLASSES[@rotation] if @rotation
208
+ transformations << ICON_FLIP_CLASSES[@flip] if @flip
209
+ transformations.join(" ")
210
+ end
211
+
212
+ def border_classes
213
+ @border ? ICON_BORDER_CLASSES : nil
214
+ end
215
+
216
+ def fixed_width_classes
217
+ @fixed_width ? ICON_FIXED_WIDTH_CLASSES : nil
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,18 @@
1
+ <%# Template per il link %>
2
+ <% if link? %>
3
+ <%= link_to @href, **element_attributes do %>
4
+ <% if show_icon? %>
5
+ <span class="<%= icon_classes %>"><%= render_icon %></span>
6
+ <% end %>
7
+ <span class="<%= text_classes %>"><%= @label %></span>
8
+ <%= content %>
9
+ <% end %>
10
+ <% else %>
11
+ <%= tag.span(**element_attributes) do %>
12
+ <% if show_icon? %>
13
+ <span class="<%= icon_classes %>"><%= render_icon %></span>
14
+ <% end %>
15
+ <span class="<%= text_classes %>"><%= @label %></span>
16
+ <%= content %>
17
+ <% end %>
18
+ <% end %>