better_ui 0.3.0 → 0.5.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +227 -209
  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 +202 -0
  12. data/app/components/better_ui/application/card_component.html.erb +24 -0
  13. data/app/components/better_ui/application/card_component.rb +53 -0
  14. data/app/components/better_ui/application/card_container_component.html.erb +8 -0
  15. data/app/components/better_ui/application/card_container_component.rb +14 -0
  16. data/app/components/better_ui/application/header_component.html.erb +88 -0
  17. data/app/components/better_ui/application/header_component.rb +188 -0
  18. data/app/components/better_ui/application/navbar_component.html.erb +294 -0
  19. data/app/components/better_ui/application/navbar_component.rb +249 -0
  20. data/app/components/better_ui/application/sidebar_component.html.erb +207 -0
  21. data/app/components/better_ui/application/sidebar_component.rb +318 -0
  22. data/app/components/better_ui/application/toast_component.html.erb +35 -0
  23. data/app/components/better_ui/application/toast_component.rb +223 -0
  24. data/app/components/better_ui/general/avatar_component.html.erb +19 -0
  25. data/app/components/better_ui/general/avatar_component.rb +171 -0
  26. data/app/components/better_ui/general/badge_component.html.erb +19 -0
  27. data/app/components/better_ui/general/badge_component.rb +123 -0
  28. data/app/components/better_ui/general/{breadcrumb/component.html.erb → breadcrumb_component.html.erb} +4 -4
  29. data/app/components/better_ui/general/breadcrumb_component.rb +130 -0
  30. data/app/components/better_ui/general/{button/component.html.erb → button_component.html.erb} +7 -7
  31. data/app/components/better_ui/general/button_component.rb +162 -0
  32. data/app/components/better_ui/general/heading_component.html.erb +25 -0
  33. data/app/components/better_ui/general/heading_component.rb +148 -0
  34. data/app/components/better_ui/general/icon_component.html.erb +2 -0
  35. data/app/components/better_ui/general/icon_component.rb +100 -0
  36. data/app/components/better_ui/general/link_component.html.erb +17 -0
  37. data/app/components/better_ui/general/link_component.rb +132 -0
  38. data/app/components/better_ui/general/panel_component.html.erb +27 -0
  39. data/app/components/better_ui/general/panel_component.rb +103 -0
  40. data/app/components/better_ui/general/spinner_component.html.erb +15 -0
  41. data/app/components/better_ui/general/spinner_component.rb +79 -0
  42. data/app/components/better_ui/general/table_component.html.erb +73 -0
  43. data/app/components/better_ui/general/table_component.rb +167 -0
  44. data/app/components/better_ui/theme_helper.rb +171 -0
  45. data/app/controllers/better_ui/application_controller.rb +1 -0
  46. data/app/controllers/better_ui/docs_controller.rb +34 -0
  47. data/app/views/components/better_ui/general/table/_custom_body_row.html.erb +17 -0
  48. data/app/views/components/better_ui/general/table/_custom_footer_rows.html.erb +17 -0
  49. data/app/views/components/better_ui/general/table/_custom_header_rows.html.erb +12 -0
  50. data/app/views/layouts/component_preview.html.erb +32 -0
  51. data/config/initializers/lookbook.rb +12 -12
  52. data/config/routes.rb +13 -0
  53. data/lib/better_ui/engine.rb +36 -5
  54. data/lib/better_ui/version.rb +1 -1
  55. data/lib/better_ui.rb +24 -4
  56. data/lib/generators/better_ui/stylesheet_generator.rb +96 -0
  57. data/lib/generators/better_ui/templates/README +56 -0
  58. data/lib/generators/better_ui/templates/components/_avatar.scss +151 -0
  59. data/lib/generators/better_ui/templates/components/_badge.scss +142 -0
  60. data/lib/generators/better_ui/templates/components/_breadcrumb.scss +107 -0
  61. data/lib/generators/better_ui/templates/components/_button.scss +106 -0
  62. data/lib/generators/better_ui/templates/components/_card.scss +69 -0
  63. data/lib/generators/better_ui/templates/components/_heading.scss +180 -0
  64. data/lib/generators/better_ui/templates/components/_icon.scss +90 -0
  65. data/lib/generators/better_ui/templates/components/_link.scss +130 -0
  66. data/lib/generators/better_ui/templates/components/_panel.scss +144 -0
  67. data/lib/generators/better_ui/templates/components/_spinner.scss +132 -0
  68. data/lib/generators/better_ui/templates/components/_table.scss +105 -0
  69. data/lib/generators/better_ui/templates/components/_variables.scss +33 -0
  70. data/lib/generators/better_ui/templates/components_stylesheet.scss +66 -0
  71. metadata +145 -156
  72. data/app/components/better_ui/application/card/component.html.erb +0 -20
  73. data/app/components/better_ui/application/card/component.rb +0 -214
  74. data/app/components/better_ui/application/main/component.html.erb +0 -9
  75. data/app/components/better_ui/application/main/component.rb +0 -123
  76. data/app/components/better_ui/application/navbar/component.html.erb +0 -92
  77. data/app/components/better_ui/application/navbar/component.rb +0 -136
  78. data/app/components/better_ui/application/sidebar/component.html.erb +0 -227
  79. data/app/components/better_ui/application/sidebar/component.rb +0 -130
  80. data/app/components/better_ui/general/accordion/component.html.erb +0 -5
  81. data/app/components/better_ui/general/accordion/component.rb +0 -92
  82. data/app/components/better_ui/general/accordion/item_component.html.erb +0 -12
  83. data/app/components/better_ui/general/accordion/item_component.rb +0 -176
  84. data/app/components/better_ui/general/alert/component.html.erb +0 -32
  85. data/app/components/better_ui/general/alert/component.rb +0 -242
  86. data/app/components/better_ui/general/avatar/component.html.erb +0 -20
  87. data/app/components/better_ui/general/avatar/component.rb +0 -301
  88. data/app/components/better_ui/general/badge/component.html.erb +0 -23
  89. data/app/components/better_ui/general/badge/component.rb +0 -248
  90. data/app/components/better_ui/general/breadcrumb/component.rb +0 -187
  91. data/app/components/better_ui/general/button/component.rb +0 -214
  92. data/app/components/better_ui/general/divider/component.html.erb +0 -10
  93. data/app/components/better_ui/general/divider/component.rb +0 -226
  94. data/app/components/better_ui/general/dropdown/component.html.erb +0 -25
  95. data/app/components/better_ui/general/dropdown/component.rb +0 -170
  96. data/app/components/better_ui/general/dropdown/divider_component.html.erb +0 -1
  97. data/app/components/better_ui/general/dropdown/divider_component.rb +0 -41
  98. data/app/components/better_ui/general/dropdown/item_component.html.erb +0 -6
  99. data/app/components/better_ui/general/dropdown/item_component.rb +0 -119
  100. data/app/components/better_ui/general/field/component.html.erb +0 -27
  101. data/app/components/better_ui/general/field/component.rb +0 -37
  102. data/app/components/better_ui/general/heading/component.html.erb +0 -22
  103. data/app/components/better_ui/general/heading/component.rb +0 -257
  104. data/app/components/better_ui/general/icon/component.html.erb +0 -7
  105. data/app/components/better_ui/general/icon/component.rb +0 -239
  106. data/app/components/better_ui/general/input/checkbox/component.html.erb +0 -5
  107. data/app/components/better_ui/general/input/checkbox/component.rb +0 -238
  108. data/app/components/better_ui/general/input/datetime/component.html.erb +0 -5
  109. data/app/components/better_ui/general/input/datetime/component.rb +0 -223
  110. data/app/components/better_ui/general/input/radio/component.html.erb +0 -5
  111. data/app/components/better_ui/general/input/radio/component.rb +0 -230
  112. data/app/components/better_ui/general/input/select/component.html.erb +0 -16
  113. data/app/components/better_ui/general/input/select/component.rb +0 -184
  114. data/app/components/better_ui/general/input/select/select_component.html.erb +0 -5
  115. data/app/components/better_ui/general/input/select/select_component.rb +0 -37
  116. data/app/components/better_ui/general/input/text/component.html.erb +0 -5
  117. data/app/components/better_ui/general/input/text/component.rb +0 -171
  118. data/app/components/better_ui/general/input/textarea/component.html.erb +0 -5
  119. data/app/components/better_ui/general/input/textarea/component.rb +0 -166
  120. data/app/components/better_ui/general/link/component.html.erb +0 -18
  121. data/app/components/better_ui/general/link/component.rb +0 -258
  122. data/app/components/better_ui/general/modal/component.html.erb +0 -5
  123. data/app/components/better_ui/general/modal/component.rb +0 -47
  124. data/app/components/better_ui/general/modal/modal_component.html.erb +0 -52
  125. data/app/components/better_ui/general/modal/modal_component.rb +0 -160
  126. data/app/components/better_ui/general/pagination/component.html.erb +0 -85
  127. data/app/components/better_ui/general/pagination/component.rb +0 -216
  128. data/app/components/better_ui/general/panel/component.html.erb +0 -28
  129. data/app/components/better_ui/general/panel/component.rb +0 -249
  130. data/app/components/better_ui/general/progress/component.html.erb +0 -11
  131. data/app/components/better_ui/general/progress/component.rb +0 -160
  132. data/app/components/better_ui/general/spinner/component.html.erb +0 -35
  133. data/app/components/better_ui/general/spinner/component.rb +0 -93
  134. data/app/components/better_ui/general/table/component.html.erb +0 -5
  135. data/app/components/better_ui/general/table/component.rb +0 -217
  136. data/app/components/better_ui/general/table/tbody_component.html.erb +0 -3
  137. data/app/components/better_ui/general/table/tbody_component.rb +0 -30
  138. data/app/components/better_ui/general/table/td_component.html.erb +0 -3
  139. data/app/components/better_ui/general/table/td_component.rb +0 -44
  140. data/app/components/better_ui/general/table/tfoot_component.html.erb +0 -3
  141. data/app/components/better_ui/general/table/tfoot_component.rb +0 -28
  142. data/app/components/better_ui/general/table/th_component.html.erb +0 -6
  143. data/app/components/better_ui/general/table/th_component.rb +0 -51
  144. data/app/components/better_ui/general/table/thead_component.html.erb +0 -3
  145. data/app/components/better_ui/general/table/thead_component.rb +0 -28
  146. data/app/components/better_ui/general/table/tr_component.html.erb +0 -3
  147. data/app/components/better_ui/general/table/tr_component.rb +0 -30
  148. data/app/components/better_ui/general/tabs/component.html.erb +0 -11
  149. data/app/components/better_ui/general/tabs/component.rb +0 -120
  150. data/app/components/better_ui/general/tabs/panel_component.html.erb +0 -3
  151. data/app/components/better_ui/general/tabs/panel_component.rb +0 -37
  152. data/app/components/better_ui/general/tabs/tab_component.html.erb +0 -13
  153. data/app/components/better_ui/general/tabs/tab_component.rb +0 -111
  154. data/app/components/better_ui/general/tag/component.html.erb +0 -3
  155. data/app/components/better_ui/general/tag/component.rb +0 -104
  156. data/app/components/better_ui/general/tooltip/component.html.erb +0 -7
  157. data/app/components/better_ui/general/tooltip/component.rb +0 -239
  158. data/app/helpers/better_ui/application/components/card/card_helper.rb +0 -96
  159. data/app/helpers/better_ui/application/components/card.rb +0 -11
  160. data/app/helpers/better_ui/application/components/main/main_helper.rb +0 -64
  161. data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +0 -77
  162. data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +0 -51
  163. data/app/helpers/better_ui/application_helper.rb +0 -55
  164. data/app/helpers/better_ui/general/components/accordion/accordion_helper.rb +0 -73
  165. data/app/helpers/better_ui/general/components/accordion.rb +0 -11
  166. data/app/helpers/better_ui/general/components/alert/alert_helper.rb +0 -57
  167. data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +0 -29
  168. data/app/helpers/better_ui/general/components/badge/badge_helper.rb +0 -53
  169. data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +0 -37
  170. data/app/helpers/better_ui/general/components/button/button_helper.rb +0 -65
  171. data/app/helpers/better_ui/general/components/container/container_helper.rb +0 -60
  172. data/app/helpers/better_ui/general/components/divider/divider_helper.rb +0 -63
  173. data/app/helpers/better_ui/general/components/dropdown/divider_helper.rb +0 -32
  174. data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +0 -79
  175. data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +0 -62
  176. data/app/helpers/better_ui/general/components/field/field_helper.rb +0 -26
  177. data/app/helpers/better_ui/general/components/heading/heading_helper.rb +0 -72
  178. data/app/helpers/better_ui/general/components/icon/icon_helper.rb +0 -16
  179. data/app/helpers/better_ui/general/components/input/checkbox/checkbox_helper.rb +0 -81
  180. data/app/helpers/better_ui/general/components/input/datetime/datetime_helper.rb +0 -91
  181. data/app/helpers/better_ui/general/components/input/radio/radio_helper.rb +0 -79
  182. data/app/helpers/better_ui/general/components/input/radio_group/radio_group_helper.rb +0 -124
  183. data/app/helpers/better_ui/general/components/input/select/select_helper.rb +0 -70
  184. data/app/helpers/better_ui/general/components/input/text/text_helper.rb +0 -138
  185. data/app/helpers/better_ui/general/components/input/textarea/textarea_helper.rb +0 -73
  186. data/app/helpers/better_ui/general/components/link/link_helper.rb +0 -89
  187. data/app/helpers/better_ui/general/components/modal/modal_helper.rb +0 -85
  188. data/app/helpers/better_ui/general/components/modal.rb +0 -11
  189. data/app/helpers/better_ui/general/components/pagination/pagination_helper.rb +0 -82
  190. data/app/helpers/better_ui/general/components/panel/panel_helper.rb +0 -83
  191. data/app/helpers/better_ui/general/components/progress/progress_helper.rb +0 -53
  192. data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +0 -19
  193. data/app/helpers/better_ui/general/components/table/table_helper.rb +0 -53
  194. data/app/helpers/better_ui/general/components/table/tbody_helper.rb +0 -13
  195. data/app/helpers/better_ui/general/components/table/td_helper.rb +0 -19
  196. data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +0 -13
  197. data/app/helpers/better_ui/general/components/table/th_helper.rb +0 -19
  198. data/app/helpers/better_ui/general/components/table/thead_helper.rb +0 -13
  199. data/app/helpers/better_ui/general/components/table/tr_helper.rb +0 -13
  200. data/app/helpers/better_ui/general/components/tabs/panel_helper.rb +0 -62
  201. data/app/helpers/better_ui/general/components/tabs/tab_helper.rb +0 -55
  202. data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +0 -95
  203. data/app/helpers/better_ui/general/components/tag/tag_helper.rb +0 -26
  204. data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +0 -60
  205. data/app/views/layouts/better_ui/application.html.erb +0 -17
  206. data/lib/better_ui/railtie.rb +0 -20
@@ -0,0 +1,188 @@
1
+ module BetterUi
2
+ module Application
3
+ class HeaderComponent < ViewComponent::Base
4
+ attr_reader :title, :subtitle, :breadcrumbs, :actions, :variant, :fixed, :container_class, :classes, :data, :show_breadcrumbs
5
+
6
+ # Varianti di colore disponibili
7
+ VARIANTS = {
8
+ light: {
9
+ bg: "bg-white border-gray-200",
10
+ text: "text-gray-700",
11
+ title: "text-gray-900",
12
+ subtitle: "text-gray-500",
13
+ border: "border-gray-200",
14
+ breadcrumb_text: "text-gray-500",
15
+ breadcrumb_hover: "hover:text-gray-700",
16
+ breadcrumb_active: "text-gray-900",
17
+ breadcrumb_divider: "text-gray-400"
18
+ },
19
+ dark: {
20
+ bg: "bg-gray-800 border-gray-700",
21
+ text: "text-gray-200",
22
+ title: "text-white",
23
+ subtitle: "text-gray-400",
24
+ border: "border-gray-700",
25
+ breadcrumb_text: "text-gray-400",
26
+ breadcrumb_hover: "hover:text-white",
27
+ breadcrumb_active: "text-white",
28
+ breadcrumb_divider: "text-gray-500"
29
+ },
30
+ primary: {
31
+ bg: "bg-orange-600",
32
+ text: "text-white",
33
+ title: "text-white",
34
+ subtitle: "text-orange-100",
35
+ border: "border-orange-500",
36
+ breadcrumb_text: "text-orange-200",
37
+ breadcrumb_hover: "hover:text-white",
38
+ breadcrumb_active: "text-white",
39
+ breadcrumb_divider: "text-orange-300"
40
+ },
41
+ transparent: {
42
+ bg: "bg-transparent",
43
+ text: "text-gray-700",
44
+ title: "text-gray-900",
45
+ subtitle: "text-gray-500",
46
+ border: "border-gray-200",
47
+ breadcrumb_text: "text-gray-500",
48
+ breadcrumb_hover: "hover:text-gray-700",
49
+ breadcrumb_active: "text-gray-900",
50
+ breadcrumb_divider: "text-gray-400"
51
+ },
52
+ modern: {
53
+ bg: "bg-white",
54
+ text: "text-gray-700",
55
+ title: "text-gray-900",
56
+ subtitle: "text-gray-500",
57
+ border: "border-gray-100",
58
+ breadcrumb_text: "text-gray-500",
59
+ breadcrumb_hover: "hover:text-gray-700",
60
+ breadcrumb_active: "text-gray-900",
61
+ breadcrumb_divider: "text-gray-400"
62
+ }
63
+ }
64
+
65
+ # Opzioni per la posizione fissa
66
+ FIXED_POSITIONS = {
67
+ top: "sticky top-0 z-40",
68
+ bottom: "sticky bottom-0 z-40"
69
+ }
70
+
71
+ # Inizializzazione del componente
72
+ def initialize(
73
+ title:,
74
+ subtitle: nil,
75
+ breadcrumbs: [],
76
+ actions: [],
77
+ variant: :modern,
78
+ fixed: nil,
79
+ container_class: "container mx-auto px-4",
80
+ classes: nil,
81
+ data: {},
82
+ show_breadcrumbs: true
83
+ )
84
+ @title = title
85
+ @subtitle = subtitle
86
+ @breadcrumbs = breadcrumbs || []
87
+ @actions = actions || []
88
+ @variant = variant.to_sym
89
+ @fixed = fixed.to_sym if fixed
90
+ @container_class = container_class
91
+ @classes = classes
92
+ @data = data || {}
93
+ @show_breadcrumbs = show_breadcrumbs
94
+ end
95
+
96
+ # Genera le classi per il container del header
97
+ def header_classes
98
+ styles = VARIANTS.fetch(@variant, VARIANTS[:modern])
99
+ position_class = @fixed.present? ? FIXED_POSITIONS[@fixed] : nil
100
+
101
+ cls = [
102
+ "w-full py-4",
103
+ styles[:bg],
104
+ position_class,
105
+ @classes
106
+ ]
107
+
108
+ # Aggiungi il bordo inferiore solo se non è trasparente
109
+ cls << "border-b" unless @variant == :transparent
110
+
111
+ cls.compact.join(" ")
112
+ end
113
+
114
+ # Genera classi per il titolo
115
+ def title_classes
116
+ styles = VARIANTS.fetch(@variant, VARIANTS[:modern])
117
+
118
+ [
119
+ "text-xl font-medium leading-6",
120
+ styles[:title]
121
+ ].join(" ")
122
+ end
123
+
124
+ # Genera classi per il sottotitolo
125
+ def subtitle_classes
126
+ styles = VARIANTS.fetch(@variant, VARIANTS[:modern])
127
+
128
+ [
129
+ "mt-1 text-sm",
130
+ styles[:subtitle]
131
+ ].join(" ")
132
+ end
133
+
134
+ # Genera classi per il breadcrumb
135
+ def breadcrumb_container_classes
136
+ "flex mb-3"
137
+ end
138
+
139
+ # Genera classi per i link del breadcrumb
140
+ def breadcrumb_link_classes(active = false)
141
+ styles = VARIANTS.fetch(@variant, VARIANTS[:modern])
142
+
143
+ if active
144
+ [
145
+ "text-sm font-medium",
146
+ styles[:breadcrumb_active]
147
+ ].join(" ")
148
+ else
149
+ [
150
+ "text-sm font-medium",
151
+ styles[:breadcrumb_text],
152
+ styles[:breadcrumb_hover]
153
+ ].join(" ")
154
+ end
155
+ end
156
+
157
+ # Genera classi per il divisore del breadcrumb
158
+ def breadcrumb_divider_classes
159
+ styles = VARIANTS.fetch(@variant, VARIANTS[:modern])
160
+
161
+ [
162
+ "mx-2 text-sm",
163
+ styles[:breadcrumb_divider]
164
+ ].join(" ")
165
+ end
166
+
167
+ # Genera classi per il contenitore delle azioni
168
+ def actions_container_classes
169
+ "mt-4 md:mt-0 flex flex-shrink-0 md:ml-4"
170
+ end
171
+
172
+ # Verifica se il componente deve essere reso
173
+ def render?
174
+ true
175
+ end
176
+
177
+ # Ritorna la lista delle azioni
178
+ def action_items
179
+ @actions
180
+ end
181
+
182
+ # Ritorna i breadcrumbs
183
+ def has_breadcrumbs?
184
+ @show_breadcrumbs && @breadcrumbs.present? && @breadcrumbs.any?
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,294 @@
1
+ <nav class="<%= navbar_classes %>" <%= @data&.map { |k, v| "data-#{k}=\"#{v}\"" }&.join(' ')&.html_safe %>>
2
+ <div class="<%= container_class %>">
3
+ <div class="flex items-center justify-between mx-auto py-3">
4
+ <% # Logo / Brand %>
5
+ <% if @brand.present? %>
6
+ <div class="flex items-center">
7
+ <% if @brand.is_a?(Hash) %>
8
+ <% if @brand[:logo].present? %>
9
+ <% if @brand[:url].present? %>
10
+ <a href="<%= @brand[:url] %>" class="flex items-center">
11
+ <%= @brand[:logo].html_safe %>
12
+ <% if @brand[:name].present? %>
13
+ <span class="text-base font-semibold whitespace-nowrap ml-3 text-gray-900"><%= @brand[:name] %></span>
14
+ <% end %>
15
+ </a>
16
+ <% else %>
17
+ <div class="flex items-center">
18
+ <%= @brand[:logo].html_safe %>
19
+ <% if @brand[:name].present? %>
20
+ <span class="text-base font-semibold whitespace-nowrap ml-3 text-gray-900"><%= @brand[:name] %></span>
21
+ <% end %>
22
+ </div>
23
+ <% end %>
24
+ <% elsif @brand[:name].present? %>
25
+ <% if @variant == :modern %>
26
+ <% if @brand[:url].present? %>
27
+ <a href="<%= @brand[:url] %>" class="flex items-center">
28
+ <div class="bg-gray-900 rounded-md p-2 mr-2">
29
+ <svg class="w-5 h-5 text-white" aria-hidden="true" fill="currentColor" viewBox="0 0 24 24">
30
+ <path fill-rule="evenodd" d="M4.5 9.75a6 6 0 0111.573-2.226 3.75 3.75 0 014.133 4.303A4.5 4.5 0 0118 20.25H6.75a5.25 5.25 0 01-2.23-10.004 6.072 6.072 0 01-.02-.496z" clip-rule="evenodd"></path>
31
+ </svg>
32
+ </div>
33
+ <div>
34
+ <span class="text-base font-semibold text-gray-900"><%= @brand[:name] %></span>
35
+ <% if @brand[:subtitle].present? %>
36
+ <p class="text-sm text-gray-500"><%= @brand[:subtitle] %></p>
37
+ <% end %>
38
+ </div>
39
+ </a>
40
+ <% else %>
41
+ <div class="flex items-center">
42
+ <div class="bg-gray-900 rounded-md p-2 mr-2">
43
+ <svg class="w-5 h-5 text-white" aria-hidden="true" fill="currentColor" viewBox="0 0 24 24">
44
+ <path fill-rule="evenodd" d="M4.5 9.75a6 6 0 0111.573-2.226 3.75 3.75 0 014.133 4.303A4.5 4.5 0 0118 20.25H6.75a5.25 5.25 0 01-2.23-10.004 6.072 6.072 0 01-.02-.496z" clip-rule="evenodd"></path>
45
+ </svg>
46
+ </div>
47
+ <div>
48
+ <span class="text-base font-semibold text-gray-900"><%= @brand[:name] %></span>
49
+ <% if @brand[:subtitle].present? %>
50
+ <p class="text-sm text-gray-500"><%= @brand[:subtitle] %></p>
51
+ <% end %>
52
+ </div>
53
+ </div>
54
+ <% end %>
55
+ <% else %>
56
+ <% if @brand[:url].present? %>
57
+ <a href="<%= @brand[:url] %>" class="text-xl font-semibold whitespace-nowrap">
58
+ <%= @brand[:name] %>
59
+ </a>
60
+ <% else %>
61
+ <span class="text-xl font-semibold whitespace-nowrap"><%= @brand[:name] %></span>
62
+ <% end %>
63
+ <% end %>
64
+ <% end %>
65
+ <% else %>
66
+ <% if @variant == :modern %>
67
+ <div class="flex items-center">
68
+ <div class="bg-gray-900 rounded-md p-2 mr-2">
69
+ <svg class="w-5 h-5 text-white" aria-hidden="true" fill="currentColor" viewBox="0 0 24 24">
70
+ <path fill-rule="evenodd" d="M4.5 9.75a6 6 0 0111.573-2.226 3.75 3.75 0 014.133 4.303A4.5 4.5 0 0118 20.25H6.75a5.25 5.25 0 01-2.23-10.004 6.072 6.072 0 01-.02-.496z" clip-rule="evenodd"></path>
71
+ </svg>
72
+ </div>
73
+ <span class="text-base font-semibold text-gray-900"><%= @brand %></span>
74
+ </div>
75
+ <% else %>
76
+ <span class="text-xl font-semibold whitespace-nowrap"><%= @brand %></span>
77
+ <% end %>
78
+ <% end %>
79
+ </div>
80
+ <% end %>
81
+
82
+ <div class="flex items-center">
83
+ <% # Menu principale della navbar visibile su desktop %>
84
+ <div class="hidden md:block">
85
+ <% if navigation_items.any? %>
86
+ <ul class="flex items-center space-x-1">
87
+ <% navigation_items.each do |item| %>
88
+ <li class="<%= has_dropdown?(item) ? 'group relative' : '' %>">
89
+ <% if item[:url].present? %>
90
+ <a
91
+ href="<%= item[:url] %>"
92
+ class="<%= nav_link_classes(active_item?(item)) %>"
93
+ <% if item[:target].present? %>target="<%= item[:target] %>"<% end %>
94
+ >
95
+ <% if item[:icon].present? %>
96
+ <span class="flex-shrink-0 mr-2 text-gray-500 w-5 h-5 inline-flex items-center justify-center">
97
+ <% if @variant == :modern %>
98
+ <% if item[:icon] == "home" %>
99
+ <svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
100
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
101
+ </svg>
102
+ <% elsif item[:icon] == "settings" || item[:icon] == "gear" %>
103
+ <svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
104
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
105
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
106
+ </svg>
107
+ <% elsif item[:icon] == "user" || item[:icon] == "profile" %>
108
+ <svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
109
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
110
+ </svg>
111
+ <% else %>
112
+ <%= render BetterUi::General::IconComponent.new(name: item[:icon]) %>
113
+ <% end %>
114
+ <% else %>
115
+ <%= render BetterUi::General::IconComponent.new(name: item[:icon]) %>
116
+ <% end %>
117
+ </span>
118
+ <% end %>
119
+ <span><%= item[:label] %></span>
120
+ <% if has_dropdown?(item) %>
121
+ <% if @variant == :modern %>
122
+ <svg class="w-4 h-4 ml-1 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
123
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
124
+ </svg>
125
+ <% else %>
126
+ <span class="ml-1">
127
+ <%= render BetterUi::General::IconComponent.new(name: "chevron-down") %>
128
+ </span>
129
+ <% end %>
130
+ <% end %>
131
+ </a>
132
+ <% else %>
133
+ <span class="<%= nav_link_classes(active_item?(item)) %>">
134
+ <% if item[:icon].present? %>
135
+ <span class="flex-shrink-0 mr-2 text-gray-500 w-5 h-5 inline-flex items-center justify-center">
136
+ <%= render BetterUi::General::IconComponent.new(name: item[:icon]) %>
137
+ </span>
138
+ <% end %>
139
+ <%= item[:label] %>
140
+ <% if has_dropdown?(item) %>
141
+ <% if @variant == :modern %>
142
+ <svg class="w-4 h-4 ml-1 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
143
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
144
+ </svg>
145
+ <% else %>
146
+ <span class="ml-1">
147
+ <%= render BetterUi::General::IconComponent.new(name: "chevron-down") %>
148
+ </span>
149
+ <% end %>
150
+ <% end %>
151
+ </span>
152
+ <% end %>
153
+
154
+ <% # Dropdown menu %>
155
+ <% if has_dropdown?(item) %>
156
+ <div class="<%= dropdown_classes %>">
157
+ <% item[:dropdown].each do |dropdown_item| %>
158
+ <a
159
+ href="<%= dropdown_item[:url] || '#' %>"
160
+ class="<%= dropdown_link_classes %>"
161
+ <% if dropdown_item[:target].present? %>target="<%= dropdown_item[:target] %>"<% end %>
162
+ >
163
+ <% if dropdown_item[:icon].present? %>
164
+ <span class="mr-2 inline-block text-gray-500">
165
+ <%= render BetterUi::General::IconComponent.new(name: dropdown_item[:icon]) %>
166
+ </span>
167
+ <% end %>
168
+ <%= dropdown_item[:label] %>
169
+ </a>
170
+ <% end %>
171
+ </div>
172
+ <% end %>
173
+ </li>
174
+ <% end %>
175
+ </ul>
176
+ <% end %>
177
+ </div>
178
+
179
+ <% # Azioni aggiuntive (pulsanti, ricerca, ecc.) %>
180
+ <% if action_items.any? %>
181
+ <div class="flex items-center ml-4">
182
+ <% action_items.each do |action| %>
183
+ <div class="ml-2">
184
+ <% if action.is_a?(Hash) && action[:content].present? %>
185
+ <%= action[:content].html_safe %>
186
+ <% elsif action.is_a?(String) %>
187
+ <%= action.html_safe %>
188
+ <% end %>
189
+ </div>
190
+ <% end %>
191
+ </div>
192
+ <% end %>
193
+
194
+ <% # Pulsante hamburger per menu mobile %>
195
+ <button
196
+ data-action="navbar#toggleMenu"
197
+ type="button"
198
+ class="<%= mobile_toggle_classes %>"
199
+ aria-controls="navbar-menu"
200
+ aria-expanded="false"
201
+ >
202
+ <span class="sr-only">Apri menu</span>
203
+ <svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
204
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
205
+ </svg>
206
+ </button>
207
+ </div>
208
+ </div>
209
+
210
+ <% # Menu mobile %>
211
+ <div class="hidden md:hidden mt-2 pb-2" id="navbar-menu" data-navbar-target="menu">
212
+ <% if navigation_items.any? %>
213
+ <ul class="flex flex-col border-t border-gray-100 pt-2">
214
+ <% navigation_items.each do |item| %>
215
+ <li class="py-1">
216
+ <% if item[:url].present? && !has_dropdown?(item) %>
217
+ <a
218
+ href="<%= item[:url] %>"
219
+ class="<%= nav_link_classes(active_item?(item)) %>"
220
+ <% if item[:target].present? %>target="<%= item[:target] %>"<% end %>
221
+ >
222
+ <% if item[:icon].present? %>
223
+ <span class="flex-shrink-0 mr-2 text-gray-500 w-5 h-5 inline-flex items-center justify-center">
224
+ <%= render BetterUi::General::IconComponent.new(name: item[:icon]) %>
225
+ </span>
226
+ <% end %>
227
+ <%= item[:label] %>
228
+ </a>
229
+ <% else %>
230
+ <div class="flex flex-col">
231
+ <% dropdown_id = "dropdown-#{SecureRandom.hex(4)}" %>
232
+ <button
233
+ type="button"
234
+ class="<%= nav_link_classes(active_item?(item)) %> w-full text-left flex items-center justify-between"
235
+ data-action="click->navbar#toggleDropdown"
236
+ data-navbar-target="dropdown"
237
+ aria-expanded="false"
238
+ aria-controls="<%= dropdown_id %>"
239
+ >
240
+ <div class="flex items-center">
241
+ <% if item[:icon].present? %>
242
+ <span class="flex-shrink-0 mr-2 text-gray-500 w-5 h-5 inline-flex items-center justify-center">
243
+ <%= render BetterUi::General::IconComponent.new(name: item[:icon]) %>
244
+ </span>
245
+ <% end %>
246
+ <%= item[:label] %>
247
+ </div>
248
+ <svg class="w-4 h-4 ml-1 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
249
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
250
+ </svg>
251
+ </button>
252
+
253
+ <% if has_dropdown?(item) %>
254
+ <div id="<%= dropdown_id %>" class="hidden pl-8 mt-1 space-y-1" data-navbar-target="submenu">
255
+ <% item[:dropdown].each do |dropdown_item| %>
256
+ <a
257
+ href="<%= dropdown_item[:url] || '#' %>"
258
+ class="block py-2 px-3 text-gray-700 hover:bg-gray-50 hover:text-gray-900 rounded-md"
259
+ <% if dropdown_item[:target].present? %>target="<%= dropdown_item[:target] %>"<% end %>
260
+ >
261
+ <% if dropdown_item[:icon].present? %>
262
+ <span class="mr-2 inline-block text-gray-500">
263
+ <%= render BetterUi::General::IconComponent.new(name: dropdown_item[:icon]) %>
264
+ </span>
265
+ <% end %>
266
+ <%= dropdown_item[:label] %>
267
+ </a>
268
+ <% end %>
269
+ </div>
270
+ <% end %>
271
+ </div>
272
+ <% end %>
273
+ </li>
274
+ <% end %>
275
+ </ul>
276
+ <% end %>
277
+
278
+ <% # Azioni aggiuntive nel menu mobile %>
279
+ <% if action_items.any? %>
280
+ <div class="mt-3 border-t border-gray-100 pt-3 px-3 space-y-2">
281
+ <% action_items.each do |action| %>
282
+ <div>
283
+ <% if action.is_a?(Hash) && action[:content].present? %>
284
+ <%= action[:content].html_safe %>
285
+ <% elsif action.is_a?(String) %>
286
+ <%= action.html_safe %>
287
+ <% end %>
288
+ </div>
289
+ <% end %>
290
+ </div>
291
+ <% end %>
292
+ </div>
293
+ </div>
294
+ </nav>