better_ui 0.4.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +165 -105
  3. data/app/components/better_ui/application/alert_component.html.erb +1 -1
  4. data/app/components/better_ui/application/alert_component.rb +95 -89
  5. data/app/components/better_ui/application/card_component.html.erb +24 -0
  6. data/app/components/better_ui/application/card_component.rb +53 -0
  7. data/app/components/better_ui/application/card_container_component.html.erb +8 -0
  8. data/app/components/better_ui/application/card_container_component.rb +14 -0
  9. data/app/components/better_ui/application/toast_component.rb +92 -57
  10. data/app/components/better_ui/general/avatar_component.html.erb +19 -0
  11. data/app/components/better_ui/general/avatar_component.rb +171 -0
  12. data/app/components/better_ui/general/badge_component.html.erb +19 -0
  13. data/app/components/better_ui/general/badge_component.rb +123 -0
  14. data/app/components/better_ui/general/breadcrumb_component.html.erb +7 -31
  15. data/app/components/better_ui/general/breadcrumb_component.rb +64 -66
  16. data/app/components/better_ui/general/button_component.html.erb +4 -4
  17. data/app/components/better_ui/general/button_component.rb +64 -95
  18. data/app/components/better_ui/general/heading_component.html.erb +3 -3
  19. data/app/components/better_ui/general/heading_component.rb +76 -70
  20. data/app/components/better_ui/general/icon_component.html.erb +1 -1
  21. data/app/components/better_ui/general/icon_component.rb +22 -23
  22. data/app/components/better_ui/general/link_component.html.erb +17 -0
  23. data/app/components/better_ui/general/link_component.rb +132 -0
  24. data/app/components/better_ui/general/panel_component.rb +62 -56
  25. data/app/components/better_ui/general/spinner_component.html.erb +15 -0
  26. data/app/components/better_ui/general/spinner_component.rb +79 -0
  27. data/app/components/better_ui/general/table_component.html.erb +56 -20
  28. data/app/components/better_ui/general/table_component.rb +106 -80
  29. data/app/components/better_ui/theme_helper.rb +77 -75
  30. data/app/views/components/better_ui/general/table/_custom_body_row.html.erb +17 -0
  31. data/app/views/components/better_ui/general/table/_custom_footer_rows.html.erb +17 -0
  32. data/app/views/components/better_ui/general/table/_custom_header_rows.html.erb +12 -0
  33. data/lib/better_ui/engine.rb +4 -10
  34. data/lib/better_ui/version.rb +1 -1
  35. data/lib/better_ui.rb +4 -0
  36. data/lib/generators/better_ui/stylesheet_generator.rb +96 -0
  37. data/lib/generators/better_ui/templates/README +56 -0
  38. data/lib/generators/better_ui/templates/components/_avatar.scss +151 -0
  39. data/lib/generators/better_ui/templates/components/_badge.scss +142 -0
  40. data/lib/generators/better_ui/templates/components/_breadcrumb.scss +107 -0
  41. data/lib/generators/better_ui/templates/components/_button.scss +106 -0
  42. data/lib/generators/better_ui/templates/components/_card.scss +69 -0
  43. data/lib/generators/better_ui/templates/components/_heading.scss +180 -0
  44. data/lib/generators/better_ui/templates/components/_icon.scss +90 -0
  45. data/lib/generators/better_ui/templates/components/_link.scss +130 -0
  46. data/lib/generators/better_ui/templates/components/_panel.scss +144 -0
  47. data/lib/generators/better_ui/templates/components/_spinner.scss +132 -0
  48. data/lib/generators/better_ui/templates/components/_table.scss +105 -0
  49. data/lib/generators/better_ui/templates/components/_variables.scss +33 -0
  50. data/lib/generators/better_ui/templates/components_stylesheet.scss +66 -0
  51. metadata +51 -22
  52. data/app/helpers/better_ui_application_helper.rb +0 -99
@@ -1,137 +1,163 @@
1
1
  module BetterUi
2
2
  module General
3
3
  class TableComponent < ViewComponent::Base
4
- attr_reader :data, :headers, :caption, :striped, :hoverable, :bordered, :compact, :classes, :variant
4
+ attr_reader :data, :headers, :caption, :striped, :hoverable, :bordered, :compact, :classes, :variant, :rounded, :footer,
5
+ :header_rows_partial, :body_row_partial, :footer_rows_partial
5
6
 
6
- def initialize(data:, headers: nil, caption: nil, striped: false, hoverable: false, bordered: true, compact: false, classes: nil, variant: :default)
7
+ # Costanti per configurazione stili
8
+ TABLE_THEMES = {
9
+ default: { base: "bui-table-default", border: "bui-table-border-default", bg: "bui-table-bg-default", text: "bui-table-text-default" },
10
+ white: { base: "bui-table-white", border: "bui-table-border-white", bg: "bui-table-bg-white", text: "bui-table-text-white" },
11
+ red: { base: "bui-table-red", border: "bui-table-border-red", bg: "bui-table-bg-red", text: "bui-table-text-red" },
12
+ rose: { base: "bui-table-rose", border: "bui-table-border-rose", bg: "bui-table-bg-rose", text: "bui-table-text-rose" },
13
+ orange: { base: "bui-table-orange", border: "bui-table-border-orange", bg: "bui-table-bg-orange", text: "bui-table-text-orange" },
14
+ green: { base: "bui-table-green", border: "bui-table-border-green", bg: "bui-table-bg-green", text: "bui-table-text-green" },
15
+ blue: { base: "bui-table-blue", border: "bui-table-border-blue", bg: "bui-table-bg-blue", text: "bui-table-text-blue" },
16
+ yellow: { base: "bui-table-yellow", border: "bui-table-border-yellow", bg: "bui-table-bg-yellow", text: "bui-table-text-yellow" },
17
+ violet: { base: "bui-table-violet", border: "bui-table-border-violet", bg: "bui-table-bg-violet", text: "bui-table-text-violet" }
18
+ }.freeze
19
+
20
+ # Opzioni di bordi arrotondati standardizzati
21
+ TABLE_RADIUS = {
22
+ none: "bui-table-radius-none",
23
+ small: "bui-table-radius-small",
24
+ medium: "bui-table-radius-medium",
25
+ large: "bui-table-radius-large",
26
+ full: "bui-table-radius-full"
27
+ }.freeze
28
+
29
+ def initialize(data:, headers: nil, caption: nil, striped: false, hoverable: false, bordered: true, compact: false, classes: nil, variant: :default, rounded: :small, footer: nil, header_rows_partial: nil, body_row_partial: nil, footer_rows_partial: nil)
7
30
  @data = data || []
8
31
  @headers = headers
9
32
  @caption = caption
10
- @striped = striped
11
- @hoverable = hoverable
12
- @bordered = bordered
13
- @compact = compact
33
+ @striped = !!striped
34
+ @hoverable = !!hoverable
35
+ @bordered = !!bordered
36
+ @compact = !!compact
14
37
  @classes = classes
15
- @variant = variant.to_sym
38
+ @variant = (TABLE_THEMES.key?(variant.to_sym) ? variant.to_sym : :default)
39
+ @rounded = (TABLE_RADIUS.key?(rounded.to_sym) ? rounded.to_sym : :small)
40
+ @footer = footer.is_a?(Array) ? footer : nil # Valida che sia un array
41
+ @header_rows_partial = header_rows_partial
42
+ @body_row_partial = body_row_partial
43
+ @footer_rows_partial = footer_rows_partial
16
44
  end
17
45
 
18
46
  def table_classes
19
- ThemeHelper.generate_component_classes(:table, @variant, { bordered: @bordered, classes: @classes })
47
+ [
48
+ "bui-table-base",
49
+ @bordered ? "bui-table-bordered" : nil,
50
+ @classes
51
+ ].compact.join(" ")
20
52
  end
21
53
 
22
54
  def table_container_classes
23
55
  [
24
- ThemeHelper::LAYOUT_STYLES[:table][:container],
25
- get_border_color
26
- ].compact.join(' ')
56
+ "bui-table-container",
57
+ get_border_radius_class
58
+ ].compact.join(" ")
59
+ end
60
+
61
+ def get_border_radius_class
62
+ TABLE_RADIUS[@rounded] || TABLE_RADIUS[:small]
27
63
  end
28
64
 
29
65
  def caption_classes
30
66
  [
31
- 'px-4 py-2',
32
- 'text-sm font-medium text-left',
33
- caption_color_classes,
34
- @bordered ? "border-b #{get_border_color}" : nil
35
- ].compact.join(' ')
67
+ "bui-table-caption",
68
+ get_theme_bg_color,
69
+ get_theme_text_class,
70
+ @bordered ? "bui-table-caption-bordered #{get_theme_border_color}" : nil
71
+ ].compact.join(" ")
36
72
  end
37
73
 
38
74
  def thead_classes
39
- ThemeHelper::LAYOUT_STYLES[:table][:header]
75
+ "bui-table-header"
40
76
  end
41
77
 
42
78
  def tbody_classes
43
- @striped ? ThemeHelper::LAYOUT_STYLES[:table][:row][:striped] : nil
79
+ @striped ? "bui-table-row-striped" : nil
80
+ end
81
+
82
+ def tfoot_classes
83
+ "bui-table-footer"
44
84
  end
45
85
 
46
86
  def tr_classes(index)
47
87
  [
48
- @hoverable ? ThemeHelper::LAYOUT_STYLES[:table][:row][:hover] : nil,
49
- @striped ? nil : (index.odd? ? 'bg-gray-50' : nil)
50
- ].compact.join(' ')
88
+ @hoverable ? "bui-table-row-hover" : nil,
89
+ @striped ? nil : (index.odd? ? "bui-table-row-alternate" : nil)
90
+ ].compact.join(" ")
51
91
  end
52
92
 
53
93
  def th_classes
54
94
  [
55
- @compact ? 'px-2 py-1' : 'px-4 py-3',
56
- 'text-left text-xs font-medium uppercase tracking-wider',
57
- th_color_classes,
58
- @bordered ? "border #{get_border_color}" : nil
59
- ].compact.join(' ')
95
+ @compact ? "bui-table-cell-compact" : "bui-table-cell",
96
+ get_theme_bg_color,
97
+ get_theme_text_class,
98
+ @bordered ? "bui-table-cell-bordered #{get_theme_border_color}" : nil
99
+ ].compact.join(" ")
60
100
  end
61
101
 
62
102
  def td_classes
63
103
  [
64
- @compact ? 'px-2 py-1' : 'px-4 py-3',
65
- @bordered ? "border #{get_border_color}" : nil,
66
- 'text-sm'
67
- ].compact.join(' ')
104
+ @compact ? "bui-table-cell-compact" : "bui-table-cell",
105
+ @bordered ? "bui-table-cell-bordered #{get_theme_border_color}" : nil
106
+ ].compact.join(" ")
68
107
  end
69
108
 
70
- def get_border_color
71
- case @variant
72
- when :primary
73
- 'border-orange-200'
74
- when :success
75
- 'border-green-200'
76
- when :warning
77
- 'border-amber-200'
78
- when :danger
79
- 'border-red-200'
80
- when :info
81
- 'border-blue-200'
82
- else
83
- 'border-gray-200'
84
- end
109
+ def tf_classes
110
+ [
111
+ @compact ? "bui-table-cell-compact" : "bui-table-cell",
112
+ "bui-table-footer-cell",
113
+ get_theme_bg_color,
114
+ get_theme_text_class,
115
+ @bordered ? "bui-table-cell-bordered #{get_theme_border_color}" : nil
116
+ ].compact.join(" ")
85
117
  end
86
118
 
87
- def caption_color_classes
88
- case @variant
89
- when :primary
90
- 'bg-orange-50 text-orange-700'
91
- when :success
92
- 'bg-green-50 text-green-700'
93
- when :warning
94
- 'bg-amber-50 text-amber-700'
95
- when :danger
96
- 'bg-red-50 text-red-700'
97
- when :info
98
- 'bg-blue-50 text-blue-700'
99
- else
100
- 'bg-gray-50 text-gray-700'
101
- end
119
+ def get_theme_base_class
120
+ TABLE_THEMES[@variant][:base] || TABLE_THEMES[:default][:base]
102
121
  end
103
122
 
104
- def th_color_classes
105
- case @variant
106
- when :primary
107
- 'text-orange-700'
108
- when :success
109
- 'text-green-700'
110
- when :warning
111
- 'text-amber-700'
112
- when :danger
113
- 'text-red-700'
114
- when :info
115
- 'text-blue-700'
116
- else
117
- 'text-gray-700'
118
- end
123
+ def get_theme_border_color
124
+ TABLE_THEMES[@variant][:border] || TABLE_THEMES[:default][:border]
125
+ end
126
+
127
+ def get_theme_bg_color
128
+ TABLE_THEMES[@variant][:bg] || TABLE_THEMES[:default][:bg]
129
+ end
130
+
131
+ def get_theme_text_class
132
+ TABLE_THEMES[@variant][:text] || TABLE_THEMES[:default][:text]
119
133
  end
120
134
 
121
135
  def headers_for_display
122
136
  return @headers if @headers.present?
123
137
  return [] if @data.empty?
124
138
 
125
- # Se non sono stati forniti headers, li derivo dalle chiavi del primo elemento
126
- first_item = @data.first
127
- if first_item.is_a?(Hash)
139
+ case first_item = @data.first
140
+ when Hash
128
141
  first_item.keys
129
- elsif first_item.respond_to?(:attributes)
130
- first_item.attributes.keys - ['id', 'created_at', 'updated_at']
142
+ when -> (item) { item.respond_to?(:attributes) }
143
+ first_item.attributes.keys - %w[id created_at updated_at]
131
144
  else
132
145
  []
133
146
  end
134
147
  end
148
+
149
+ # Ottiene il valore di una cella in modo consistente
150
+ def get_cell_value(row, header)
151
+ if row.is_a?(Hash)
152
+ row[header.to_s] || row[header.to_sym] || "—"
153
+ elsif row.respond_to?(header.to_sym)
154
+ row.send(header.to_sym)
155
+ elsif row.is_a?(Array) && headers_for_display.index(header)
156
+ row[headers_for_display.index(header)] || "—"
157
+ else
158
+ "—"
159
+ end
160
+ end
135
161
 
136
162
  def render?
137
163
  @data.present?
@@ -4,72 +4,80 @@ module BetterUi
4
4
  module ThemeHelper
5
5
  # Colori principali del tema
6
6
  THEME_COLORS = {
7
- # Neutrali
8
- white: 'bg-white',
9
- black: 'bg-black',
10
-
11
- # Colori del tema
12
- primary: {
13
- light: 'bg-orange-100',
14
- default: 'bg-orange-500',
15
- dark: 'bg-orange-600',
16
- text: 'text-white'
7
+ # Varianti cromatiche
8
+ default: {
9
+ bg: 'bg-black',
10
+ text: 'text-white',
11
+ hover: 'hover:bg-gray-900'
12
+ },
13
+ white: {
14
+ bg: 'bg-white',
15
+ text: 'text-black',
16
+ hover: 'hover:bg-gray-100'
17
+ },
18
+ red: {
19
+ bg: 'bg-red-500',
20
+ text: 'text-white',
21
+ hover: 'hover:bg-red-600'
17
22
  },
18
- secondary: {
19
- light: 'bg-gray-100',
20
- default: 'bg-gray-200',
21
- dark: 'bg-gray-300',
22
- text: 'text-gray-800'
23
+ rose: {
24
+ bg: 'bg-rose-500',
25
+ text: 'text-white',
26
+ hover: 'hover:bg-rose-600'
23
27
  },
24
- success: {
25
- light: 'bg-green-100',
26
- default: 'bg-green-500',
27
- dark: 'bg-green-600',
28
- text: 'text-white'
28
+ orange: {
29
+ bg: 'bg-orange-500',
30
+ text: 'text-white',
31
+ hover: 'hover:bg-orange-600'
29
32
  },
30
- warning: {
31
- light: 'bg-amber-100',
32
- default: 'bg-amber-500',
33
- dark: 'bg-amber-600',
34
- text: 'text-white'
33
+ green: {
34
+ bg: 'bg-green-500',
35
+ text: 'text-white',
36
+ hover: 'hover:bg-green-600'
35
37
  },
36
- danger: {
37
- light: 'bg-red-100',
38
- default: 'bg-red-500',
39
- dark: 'bg-red-600',
40
- text: 'text-white'
38
+ blue: {
39
+ bg: 'bg-blue-500',
40
+ text: 'text-white',
41
+ hover: 'hover:bg-blue-600'
41
42
  },
42
- info: {
43
- light: 'bg-blue-100',
44
- default: 'bg-blue-500',
45
- dark: 'bg-blue-600',
46
- text: 'text-white'
43
+ yellow: {
44
+ bg: 'bg-yellow-500',
45
+ text: 'text-black',
46
+ hover: 'hover:bg-yellow-600'
47
+ },
48
+ violet: {
49
+ bg: 'bg-violet-500',
50
+ text: 'text-white',
51
+ hover: 'hover:bg-violet-600'
47
52
  }
48
53
  }
49
54
 
50
55
  # Bordi del tema
51
56
  THEME_BORDERS = {
52
- primary: 'border-orange-200',
53
- secondary: 'border-gray-200',
54
- success: 'border-green-200',
55
- warning: 'border-amber-200',
56
- danger: 'border-red-200',
57
- info: 'border-blue-200'
57
+ default: 'border-gray-900',
58
+ white: 'border-gray-200',
59
+ red: 'border-red-600',
60
+ rose: 'border-rose-600',
61
+ orange: 'border-orange-600',
62
+ green: 'border-green-600',
63
+ blue: 'border-blue-600',
64
+ yellow: 'border-yellow-600',
65
+ violet: 'border-violet-600'
58
66
  }
59
67
 
68
+ # NOTA: I valori di border-radius sono ora definiti nelle costanti specifiche di ogni componente
69
+ # per garantire una nomenclatura standardizzata:
70
+ # - none: nessun arrotondamento (rounded-none)
71
+ # - small: arrotondamento piccolo (rounded-md)
72
+ # - medium: arrotondamento medio (rounded-lg)
73
+ # - large: arrotondamento grande (rounded-xl)
74
+ # - full: arrotondamento completo (rounded-full)
75
+
60
76
  # Effetti hover
61
- THEME_HOVER = {
62
- primary: 'hover:bg-orange-600',
63
- secondary: 'hover:bg-gray-300',
64
- success: 'hover:bg-green-600',
65
- warning: 'hover:bg-amber-600',
66
- danger: 'hover:bg-red-600',
67
- info: 'hover:bg-blue-600'
68
- }
77
+ THEME_HOVER = THEME_COLORS.transform_values { |v| v[:hover] }
69
78
 
70
79
  # Stili base comuni
71
80
  COMMON_STYLES = {
72
- rounded: 'rounded-md',
73
81
  shadow: 'shadow-sm',
74
82
  transitions: 'transition-all duration-200'
75
83
  }
@@ -77,13 +85,13 @@ module BetterUi
77
85
  # Stili per elementi di layout
78
86
  LAYOUT_STYLES = {
79
87
  panel: {
80
- base: 'rounded-lg border shadow-sm',
88
+ base: 'border shadow-sm',
81
89
  header: 'px-4 py-3 border-b',
82
90
  body: 'p-4',
83
91
  footer: 'px-4 py-3 border-t'
84
92
  },
85
93
  table: {
86
- container: 'overflow-hidden rounded-md border shadow-sm',
94
+ container: 'overflow-hidden border shadow-sm',
87
95
  header: 'bg-gray-50 text-left text-xs uppercase tracking-wider text-gray-500 font-medium',
88
96
  row: {
89
97
  base: '',
@@ -102,21 +110,14 @@ module BetterUi
102
110
  when :button
103
111
  base_classes << 'inline-flex items-center justify-center'
104
112
  base_classes << 'font-medium'
105
- base_classes << COMMON_STYLES[:rounded]
106
113
  base_classes << COMMON_STYLES[:transitions]
107
114
 
108
- if options[:outline]
109
- # Versione outline
110
- base_classes << 'border-2'
111
- base_classes << "border-#{variant}-500"
112
- base_classes << "text-#{variant}-500"
113
- base_classes << "hover:bg-#{variant}-50"
114
- else
115
- # Versione piena
116
- base_classes << THEME_COLORS.dig(variant.to_sym, :default)&.sub('bg-', '') || "bg-#{variant}-500"
117
- base_classes << THEME_COLORS.dig(variant.to_sym, :text) || 'text-white'
118
- base_classes << THEME_HOVER[variant.to_sym] || "hover:bg-#{variant}-600"
119
- end
115
+ variant_colors = THEME_COLORS[variant.to_sym] || THEME_COLORS[:default]
116
+
117
+ # Versione piena
118
+ base_classes << variant_colors[:bg]
119
+ base_classes << variant_colors[:text]
120
+ base_classes << THEME_HOVER[variant.to_sym] || THEME_HOVER[:default]
120
121
 
121
122
  # Dimensione
122
123
  case options[:size]
@@ -141,22 +142,23 @@ module BetterUi
141
142
  when :panel
142
143
  base_classes << LAYOUT_STYLES[:panel][:base]
143
144
 
144
- # Colore di sfondo in base alla variante
145
- if variant.to_sym == :default
146
- base_classes << 'bg-white'
147
- base_classes << 'border-gray-200'
148
- else
149
- base_classes << THEME_COLORS.dig(variant.to_sym, :light)&.sub('bg-', '') || "bg-#{variant}-50"
150
- base_classes << THEME_BORDERS[variant.to_sym] || "border-#{variant}-200"
151
- end
145
+ variant_colors = THEME_COLORS[variant.to_sym] || THEME_COLORS[:default]
146
+
147
+ base_classes << variant_colors[:bg]
148
+ base_classes << variant_colors[:text]
149
+ base_classes << THEME_BORDERS[variant.to_sym] || THEME_BORDERS[:default]
152
150
 
153
151
  when :table
154
- base_classes << 'min-w-full bg-white'
152
+ base_classes << 'min-w-full'
153
+
154
+ variant_colors = THEME_COLORS[variant.to_sym] || THEME_COLORS[:default]
155
+ base_classes << variant_colors[:bg]
156
+ base_classes << variant_colors[:text]
155
157
 
156
158
  # Bordi
157
159
  if options[:bordered]
158
160
  base_classes << 'border-collapse'
159
- base_classes << (THEME_BORDERS[variant.to_sym] || 'border-gray-200')
161
+ base_classes << (THEME_BORDERS[variant.to_sym] || THEME_BORDERS[:default])
160
162
  end
161
163
 
162
164
  # Classi personalizzate
@@ -0,0 +1,17 @@
1
+ <tr class="<%= component.tr_classes(index) %>">
2
+ <% headers.each_with_index do |header, cell_index| %>
3
+ <td class="<%= component.td_classes %>">
4
+ <% cell_value = component.get_cell_value(row, header) %>
5
+ <% if cell_index == 0 %>
6
+ <div class="flex items-center">
7
+ <div class="w-8 h-8 rounded-full bg-blue-100 mr-2 flex items-center justify-center text-blue-700">
8
+ <%= cell_value.to_s.first&.upcase || 'N/A' %>
9
+ </div>
10
+ <%= cell_value %>
11
+ </div>
12
+ <% else %>
13
+ <%= cell_value %>
14
+ <% end %>
15
+ </td>
16
+ <% end %>
17
+ </tr>
@@ -0,0 +1,17 @@
1
+ <tr>
2
+ <% footer.each_with_index do |value, index| %>
3
+ <td class="<%= component.tf_classes %>">
4
+ <% if index == 0 %>
5
+ <div class="flex items-center">
6
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
7
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2
8
+ 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
9
+ </svg>
10
+ <strong><%= value %></strong>
11
+ </div>
12
+ <% else %>
13
+ <%= value %>
14
+ <% end %>
15
+ </td>
16
+ <% end %>
17
+ </tr>
@@ -0,0 +1,12 @@
1
+ <tr>
2
+ <% headers.each do |header| %>
3
+ <th class="<%= component.th_classes %>">
4
+ <div class="flex items-center justify-between">
5
+ <%= header.to_s.humanize %>
6
+ <svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
7
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
8
+ </svg>
9
+ </div>
10
+ </th>
11
+ <% end %>
12
+ </tr>
@@ -3,6 +3,9 @@ require 'redcarpet'
3
3
  require 'tailwindcss-rails'
4
4
  require 'coderay'
5
5
  require 'font-awesome-sass'
6
+ require 'lookbook'
7
+ require 'listen'
8
+ require 'action_cable'
6
9
 
7
10
  module BetterUi
8
11
  class Engine < ::Rails::Engine
@@ -35,16 +38,7 @@ module BetterUi
35
38
 
36
39
  # Configurazione per Lookbook in sviluppo e test
37
40
  initializer 'better_ui.lookbook' do
38
- if defined?(Lookbook) && (Rails.env.development? || Rails.env.test?)
39
- # Carica esplicitamente le dipendenze per le funzionalità avanzate di Lookbook
40
- begin
41
- require 'listen'
42
- require 'action_cable'
43
- rescue LoadError => e
44
- # Log che le dipendenze opzionali non sono disponibili
45
- puts "NOTA: Alcune funzionalità avanzate di Lookbook potrebbero non essere disponibili: #{e.message}"
46
- end
47
-
41
+ if Rails.env.development? || Rails.env.test?
48
42
  config.lookbook = Lookbook
49
43
  end
50
44
  end
@@ -1,3 +1,3 @@
1
1
  module BetterUi
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/better_ui.rb CHANGED
@@ -23,3 +23,7 @@ module BetterUi
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ # Caricamento del generator
28
+ require 'rails/generators'
29
+ require 'generators/better_ui/stylesheet_generator' if defined?(Rails::Generators)
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterUi
4
+ module Generators
5
+ class StylesheetGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ desc "Genera un foglio di stile SCSS di base per personalizzare i componenti di BetterUi"
9
+
10
+ class_option :prefix, type: :string, default: "custom",
11
+ desc: "Prefisso da utilizzare per il foglio di stile (default: 'custom')"
12
+
13
+ def create_stylesheet
14
+ # Crea il file principale
15
+ template "components_stylesheet.scss",
16
+ File.join("app/assets/stylesheets", "#{options[:prefix]}_better_ui_components.scss")
17
+
18
+ # Crea la directory dei componenti se non esiste
19
+ directory = File.join("app/assets/stylesheets", "components")
20
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
21
+
22
+ # Lista dei file dei componenti
23
+ component_files = ['_variables.scss', '_button.scss', '_heading.scss', '_breadcrumb.scss',
24
+ '_link.scss', '_panel.scss', '_icon.scss', '_table.scss', '_badge.scss',
25
+ '_spinner.scss', '_avatar.scss']
26
+
27
+ # Copia i file originali
28
+ component_files.each do |filename|
29
+ copy_file "components/#{filename}", File.join(directory, filename)
30
+ end
31
+ end
32
+
33
+ def create_overrides
34
+ # Crea la directory dei componenti se non esiste
35
+ directory = File.join("app/assets/stylesheets", "components")
36
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
37
+
38
+ # Lista dei file dei componenti
39
+ component_files = ['_variables.scss', '_button.scss', '_heading.scss', '_breadcrumb.scss',
40
+ '_link.scss', '_panel.scss', '_icon.scss', '_table.scss', '_badge.scss',
41
+ '_spinner.scss', '_avatar.scss']
42
+
43
+ # Crea i file di override
44
+ component_files.each do |filename|
45
+ # Nome del file di override
46
+ override_filename = filename.sub('.scss', '_overrides.scss')
47
+ override_path = File.join(directory, override_filename)
48
+
49
+ # Crea il file di override solo se non esiste già
50
+ unless File.exist?(override_path)
51
+ # Leggi il contenuto del file originale dalla directory templates
52
+ template_path = File.join(self.class.source_root, "components", filename)
53
+
54
+ # Se il file template esiste, crea il file di override
55
+ if File.exist?(template_path)
56
+ original_content = File.read(template_path)
57
+ override_content = generate_empty_override(original_content, filename)
58
+ create_file override_path, override_content
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def show_readme
65
+ readme "README" if behavior == :invoke
66
+ end
67
+
68
+ private
69
+
70
+ # Genera un file di override vuoto con le stesse classi del file originale
71
+ def generate_empty_override(content, filename)
72
+ component_name = filename.sub('_', '').sub('.scss', '')
73
+ result = "/* ==============================\n"
74
+ result += " * #{component_name.capitalize} Component Overrides\n"
75
+ result += " * ==============================\n"
76
+ result += " * Questo file contiene le classi vuote per sovrascrivere gli stili di default.\n"
77
+ result += " * Aggiungi qui le tue personalizzazioni.\n"
78
+ result += " */\n\n"
79
+
80
+ # Estrae le classi tramite regex
81
+ class_matches = content.scan(/\.(bui-[a-zA-Z0-9_-]+)\s*\{/)
82
+ class_matches.flatten.uniq.each do |css_class|
83
+ result += ".#{css_class} {\n // Sovrascrivi qui gli stili per .#{css_class}\n}\n\n"
84
+ end
85
+
86
+ # Estrae anche classi annidate usando la sintassi SCSS
87
+ nested_matches = content.scan(/\.(bui-[a-zA-Z0-9_-]+)\s*{[^{]*\.([\w-]+)\s*{/)
88
+ nested_matches.each do |parent_class, child_class|
89
+ result += ".#{parent_class} {\n .#{child_class} {\n // Sovrascrivi qui gli stili annidati\n }\n}\n\n"
90
+ end
91
+
92
+ result
93
+ end
94
+ end
95
+ end
96
+ end