better_ui 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +65 -1
- data/app/assets/javascripts/better_ui/controllers/navbar_controller.js +138 -0
- data/app/assets/javascripts/better_ui/controllers/sidebar_controller.js +211 -0
- data/app/assets/javascripts/better_ui/controllers/toast_controller.js +161 -0
- data/app/assets/javascripts/better_ui/index.js +159 -0
- data/app/assets/javascripts/better_ui/toast_manager.js +77 -0
- data/app/assets/stylesheets/better_ui/application.css +25 -351
- data/app/components/better_ui/application/alert_component.html.erb +27 -0
- data/app/components/better_ui/application/alert_component.rb +196 -0
- data/app/components/better_ui/application/header_component.html.erb +88 -0
- data/app/components/better_ui/application/header_component.rb +188 -0
- data/app/components/better_ui/application/navbar_component.html.erb +294 -0
- data/app/components/better_ui/application/navbar_component.rb +249 -0
- data/app/components/better_ui/application/sidebar_component.html.erb +207 -0
- data/app/components/better_ui/application/sidebar_component.rb +318 -0
- data/app/components/better_ui/application/toast_component.html.erb +35 -0
- data/app/components/better_ui/application/toast_component.rb +188 -0
- data/app/components/better_ui/general/breadcrumb_component.html.erb +39 -0
- data/app/components/better_ui/general/breadcrumb_component.rb +132 -0
- data/app/components/better_ui/general/button_component.html.erb +34 -0
- data/app/components/better_ui/general/button_component.rb +193 -0
- data/app/components/better_ui/general/heading_component.html.erb +25 -0
- data/app/components/better_ui/general/heading_component.rb +142 -0
- data/app/components/better_ui/general/icon_component.html.erb +2 -0
- data/app/components/better_ui/general/icon_component.rb +101 -0
- data/app/components/better_ui/general/panel_component.html.erb +27 -0
- data/app/components/better_ui/general/panel_component.rb +97 -0
- data/app/components/better_ui/general/table_component.html.erb +37 -0
- data/app/components/better_ui/general/table_component.rb +141 -0
- data/app/components/better_ui/theme_helper.rb +169 -0
- data/app/controllers/better_ui/application_controller.rb +1 -0
- data/app/controllers/better_ui/docs_controller.rb +18 -25
- data/app/helpers/better_ui_application_helper.rb +99 -0
- data/app/views/layouts/component_preview.html.erb +32 -0
- data/config/initializers/lookbook.rb +23 -0
- data/config/routes.rb +6 -1
- data/lib/better_ui/engine.rb +24 -1
- data/lib/better_ui/version.rb +1 -1
- metadata +103 -7
- data/app/helpers/better_ui/application_helper.rb +0 -183
- data/app/views/better_ui/docs/component.html.erb +0 -365
- data/app/views/better_ui/docs/index.html.erb +0 -100
- data/app/views/better_ui/docs/show.html.erb +0 -60
- data/app/views/layouts/better_ui/application.html.erb +0 -135
@@ -0,0 +1,142 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class HeadingComponent < ViewComponent::Base
|
4
|
+
attr_reader :text, :level, :variant, :size, :align, :classes, :icon, :subtitle, :with_divider
|
5
|
+
|
6
|
+
# Varianti di colore disponibili
|
7
|
+
VARIANTS = {
|
8
|
+
default: {
|
9
|
+
heading: "text-gray-900",
|
10
|
+
subtitle: "text-gray-600",
|
11
|
+
divider: "border-gray-200"
|
12
|
+
},
|
13
|
+
primary: {
|
14
|
+
heading: "text-orange-700",
|
15
|
+
subtitle: "text-orange-500",
|
16
|
+
divider: "border-orange-300"
|
17
|
+
},
|
18
|
+
success: {
|
19
|
+
heading: "text-green-700",
|
20
|
+
subtitle: "text-green-500",
|
21
|
+
divider: "border-green-300"
|
22
|
+
},
|
23
|
+
warning: {
|
24
|
+
heading: "text-yellow-700",
|
25
|
+
subtitle: "text-yellow-500",
|
26
|
+
divider: "border-yellow-300"
|
27
|
+
},
|
28
|
+
danger: {
|
29
|
+
heading: "text-red-700",
|
30
|
+
subtitle: "text-red-500",
|
31
|
+
divider: "border-red-300"
|
32
|
+
},
|
33
|
+
info: {
|
34
|
+
heading: "text-blue-700",
|
35
|
+
subtitle: "text-blue-500",
|
36
|
+
divider: "border-blue-300"
|
37
|
+
},
|
38
|
+
light: {
|
39
|
+
heading: "text-gray-100",
|
40
|
+
subtitle: "text-gray-300",
|
41
|
+
divider: "border-gray-700"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
# Dimensioni disponibili
|
46
|
+
SIZES = {
|
47
|
+
xs: {
|
48
|
+
heading: "text-lg",
|
49
|
+
subtitle: "text-sm"
|
50
|
+
},
|
51
|
+
sm: {
|
52
|
+
heading: "text-xl",
|
53
|
+
subtitle: "text-base"
|
54
|
+
},
|
55
|
+
md: {
|
56
|
+
heading: "text-2xl",
|
57
|
+
subtitle: "text-lg"
|
58
|
+
},
|
59
|
+
lg: {
|
60
|
+
heading: "text-3xl",
|
61
|
+
subtitle: "text-xl"
|
62
|
+
},
|
63
|
+
xl: {
|
64
|
+
heading: "text-4xl",
|
65
|
+
subtitle: "text-2xl"
|
66
|
+
},
|
67
|
+
xxl: {
|
68
|
+
heading: "text-5xl",
|
69
|
+
subtitle: "text-3xl"
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
# Allineamenti disponibili
|
74
|
+
ALIGNMENTS = {
|
75
|
+
left: "text-left",
|
76
|
+
center: "text-center",
|
77
|
+
right: "text-right"
|
78
|
+
}
|
79
|
+
|
80
|
+
# Inizializzazione del componente
|
81
|
+
def initialize(
|
82
|
+
text: nil,
|
83
|
+
level: 2,
|
84
|
+
variant: :default,
|
85
|
+
size: :md,
|
86
|
+
align: :left,
|
87
|
+
classes: nil,
|
88
|
+
icon: nil,
|
89
|
+
subtitle: nil,
|
90
|
+
with_divider: false
|
91
|
+
)
|
92
|
+
@text = text
|
93
|
+
@level = level.to_i.clamp(1, 6)
|
94
|
+
@variant = variant.to_sym
|
95
|
+
@size = size.to_sym
|
96
|
+
@align = align.to_sym
|
97
|
+
@classes = classes
|
98
|
+
@icon = icon
|
99
|
+
@subtitle = subtitle
|
100
|
+
@with_divider = with_divider
|
101
|
+
end
|
102
|
+
|
103
|
+
# Genera le classi per l'heading
|
104
|
+
def heading_classes
|
105
|
+
[
|
106
|
+
VARIANTS.fetch(@variant, VARIANTS[:default])[:heading],
|
107
|
+
SIZES.fetch(@size, SIZES[:md])[:heading],
|
108
|
+
ALIGNMENTS.fetch(@align, ALIGNMENTS[:left]),
|
109
|
+
"font-bold",
|
110
|
+
@classes
|
111
|
+
].compact.join(" ")
|
112
|
+
end
|
113
|
+
|
114
|
+
# Genera le classi per il sottotitolo
|
115
|
+
def subtitle_classes
|
116
|
+
[
|
117
|
+
VARIANTS.fetch(@variant, VARIANTS[:default])[:subtitle],
|
118
|
+
SIZES.fetch(@size, SIZES[:md])[:subtitle],
|
119
|
+
ALIGNMENTS.fetch(@align, ALIGNMENTS[:left]),
|
120
|
+
"mt-1"
|
121
|
+
].compact.join(" ")
|
122
|
+
end
|
123
|
+
|
124
|
+
# Genera le classi per il divisore
|
125
|
+
def divider_classes
|
126
|
+
[
|
127
|
+
"border-t",
|
128
|
+
"mt-2",
|
129
|
+
VARIANTS.fetch(@variant, VARIANTS[:default])[:divider]
|
130
|
+
].compact.join(" ")
|
131
|
+
end
|
132
|
+
|
133
|
+
# Genera le classi per il container
|
134
|
+
def container_classes
|
135
|
+
[
|
136
|
+
"mb-4",
|
137
|
+
@with_divider ? "pb-2" : ""
|
138
|
+
].compact.join(" ")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class IconComponent < ViewComponent::Base
|
4
|
+
# Dimensioni disponibili
|
5
|
+
SIZE_CLASSES = {
|
6
|
+
xs: "fa-xs",
|
7
|
+
sm: "fa-sm",
|
8
|
+
md: "", # Default di Font Awesome
|
9
|
+
lg: "fa-lg",
|
10
|
+
xl: "fa-xl",
|
11
|
+
"2xl": "fa-2xl"
|
12
|
+
}
|
13
|
+
|
14
|
+
# Stili disponibili
|
15
|
+
STYLE_CLASSES = {
|
16
|
+
solid: "fas",
|
17
|
+
regular: "far",
|
18
|
+
light: "fal",
|
19
|
+
brands: "fab",
|
20
|
+
duotone: "fad"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Inizializzazione del componente
|
24
|
+
def initialize(
|
25
|
+
name:,
|
26
|
+
size: :md,
|
27
|
+
style: :solid,
|
28
|
+
fixed_width: false,
|
29
|
+
spin: false,
|
30
|
+
pulse: false,
|
31
|
+
border: false,
|
32
|
+
flip: nil,
|
33
|
+
rotation: nil,
|
34
|
+
classes: nil
|
35
|
+
)
|
36
|
+
@name = name.to_s.gsub('_', '-') # Convertiamo da snake_case a kebab-case per Font Awesome
|
37
|
+
@size = size.to_sym
|
38
|
+
@style = style.to_sym
|
39
|
+
@fixed_width = fixed_width
|
40
|
+
@spin = spin
|
41
|
+
@pulse = pulse
|
42
|
+
@border = border
|
43
|
+
@flip = flip
|
44
|
+
@rotation = rotation
|
45
|
+
@classes = classes
|
46
|
+
end
|
47
|
+
|
48
|
+
# Classe CSS per lo stile dell'icona
|
49
|
+
def style_class
|
50
|
+
STYLE_CLASSES[@style] || STYLE_CLASSES[:solid]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Classe CSS per la dimensione
|
54
|
+
def size_class
|
55
|
+
SIZE_CLASSES[@size] || SIZE_CLASSES[:md]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Classe per rotazione
|
59
|
+
def rotation_class
|
60
|
+
return "" unless @rotation
|
61
|
+
"fa-rotate-#{@rotation}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Classe per rovesciamento
|
65
|
+
def flip_class
|
66
|
+
return "" unless @flip
|
67
|
+
"fa-flip-#{@flip}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# Classi per animazioni
|
71
|
+
def animation_classes
|
72
|
+
classes = []
|
73
|
+
classes << "fa-spin" if @spin
|
74
|
+
classes << "fa-pulse" if @pulse
|
75
|
+
classes.join(" ")
|
76
|
+
end
|
77
|
+
|
78
|
+
# Classi per caratteristiche aggiuntive
|
79
|
+
def feature_classes
|
80
|
+
classes = []
|
81
|
+
classes << "fa-fw" if @fixed_width
|
82
|
+
classes << "fa-border" if @border
|
83
|
+
classes.join(" ")
|
84
|
+
end
|
85
|
+
|
86
|
+
# Combinazione di tutte le classi
|
87
|
+
def combined_classes
|
88
|
+
[
|
89
|
+
style_class,
|
90
|
+
"fa-#{@name}",
|
91
|
+
size_class,
|
92
|
+
rotation_class,
|
93
|
+
flip_class,
|
94
|
+
animation_classes,
|
95
|
+
feature_classes,
|
96
|
+
@classes
|
97
|
+
].reject(&:blank?).join(" ")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="<%= panel_classes %>">
|
2
|
+
<% if @header.present? %>
|
3
|
+
<div class="<%= header_classes %>">
|
4
|
+
<%= raw @header %>
|
5
|
+
</div>
|
6
|
+
<% elsif @title.present? %>
|
7
|
+
<div class="<%= header_classes %>">
|
8
|
+
<div class="<%= title_classes %>"><%= @title %></div>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% if @body.present? %>
|
13
|
+
<div class="<%= body_classes %>">
|
14
|
+
<%= raw @body %>
|
15
|
+
</div>
|
16
|
+
<% elsif content.present? %>
|
17
|
+
<div class="<%= body_classes %>">
|
18
|
+
<%= content %>
|
19
|
+
</div>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<% if @footer.present? %>
|
23
|
+
<div class="<%= footer_classes %>">
|
24
|
+
<%= raw @footer %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class PanelComponent < ViewComponent::Base
|
4
|
+
attr_reader :header, :footer, :body, :title, :padding, :variant
|
5
|
+
|
6
|
+
PADDING_OPTIONS = {
|
7
|
+
none: '',
|
8
|
+
small: 'p-2',
|
9
|
+
medium: 'p-4',
|
10
|
+
large: 'p-6'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def initialize(title: nil, body: nil, header: nil, footer: nil, padding: :medium, variant: :default)
|
14
|
+
@title = title
|
15
|
+
@body = body
|
16
|
+
@header = header
|
17
|
+
@footer = footer
|
18
|
+
@padding = padding.to_sym
|
19
|
+
@variant = variant.to_sym
|
20
|
+
end
|
21
|
+
|
22
|
+
def panel_classes
|
23
|
+
ThemeHelper.generate_component_classes(:panel, @variant)
|
24
|
+
end
|
25
|
+
|
26
|
+
def header_classes
|
27
|
+
[
|
28
|
+
'panel-header',
|
29
|
+
ThemeHelper::LAYOUT_STYLES[:panel][:header],
|
30
|
+
header_color_classes,
|
31
|
+
PADDING_OPTIONS.fetch(@padding, PADDING_OPTIONS[:medium])
|
32
|
+
].compact.join(' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def body_classes
|
36
|
+
[
|
37
|
+
'panel-body',
|
38
|
+
ThemeHelper::LAYOUT_STYLES[:panel][:body],
|
39
|
+
'overflow-x-auto break-words',
|
40
|
+
PADDING_OPTIONS.fetch(@padding, PADDING_OPTIONS[:medium])
|
41
|
+
].compact.join(' ')
|
42
|
+
end
|
43
|
+
|
44
|
+
def footer_classes
|
45
|
+
[
|
46
|
+
'panel-footer',
|
47
|
+
ThemeHelper::LAYOUT_STYLES[:panel][:footer],
|
48
|
+
footer_color_classes,
|
49
|
+
'overflow-x-auto break-words',
|
50
|
+
PADDING_OPTIONS.fetch(@padding, PADDING_OPTIONS[:medium])
|
51
|
+
].compact.join(' ')
|
52
|
+
end
|
53
|
+
|
54
|
+
def title_classes
|
55
|
+
'text-lg font-medium'
|
56
|
+
end
|
57
|
+
|
58
|
+
def header_color_classes
|
59
|
+
case @variant
|
60
|
+
when :primary
|
61
|
+
'bg-orange-50 text-orange-700'
|
62
|
+
when :success
|
63
|
+
'bg-green-50 text-green-700'
|
64
|
+
when :warning
|
65
|
+
'bg-amber-50 text-amber-700'
|
66
|
+
when :danger
|
67
|
+
'bg-red-50 text-red-700'
|
68
|
+
when :info
|
69
|
+
'bg-blue-50 text-blue-700'
|
70
|
+
else
|
71
|
+
'bg-gray-50 text-gray-700'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def footer_color_classes
|
76
|
+
case @variant
|
77
|
+
when :primary
|
78
|
+
'bg-orange-50 text-orange-600'
|
79
|
+
when :success
|
80
|
+
'bg-green-50 text-green-600'
|
81
|
+
when :warning
|
82
|
+
'bg-amber-50 text-amber-600'
|
83
|
+
when :danger
|
84
|
+
'bg-red-50 text-red-600'
|
85
|
+
when :info
|
86
|
+
'bg-blue-50 text-blue-600'
|
87
|
+
else
|
88
|
+
'bg-gray-50 text-gray-600'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def render?
|
93
|
+
@body.present? || @header.present? || @footer.present? || content.present?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<div class="<%= table_container_classes %>">
|
2
|
+
<table class="<%= table_classes %>">
|
3
|
+
<% if caption.present? %>
|
4
|
+
<caption class="<%= caption_classes %>">
|
5
|
+
<%= caption %>
|
6
|
+
</caption>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<thead class="<%= thead_classes %>">
|
10
|
+
<tr>
|
11
|
+
<% headers_for_display.each do |header| %>
|
12
|
+
<th scope="col" class="<%= th_classes %>">
|
13
|
+
<%= header.to_s.humanize %>
|
14
|
+
</th>
|
15
|
+
<% end %>
|
16
|
+
</tr>
|
17
|
+
</thead>
|
18
|
+
|
19
|
+
<tbody class="<%= tbody_classes %>">
|
20
|
+
<% data.each_with_index do |row, index| %>
|
21
|
+
<tr class="<%= tr_classes(index) %>">
|
22
|
+
<% headers_for_display.each do |header| %>
|
23
|
+
<td class="<%= td_classes %>">
|
24
|
+
<% if row.is_a?(Hash) %>
|
25
|
+
<%= row[header.to_s] || row[header.to_sym] %>
|
26
|
+
<% elsif row.respond_to?(header.to_sym) %>
|
27
|
+
<%= row.send(header.to_sym) %>
|
28
|
+
<% else %>
|
29
|
+
—
|
30
|
+
<% end %>
|
31
|
+
</td>
|
32
|
+
<% end %>
|
33
|
+
</tr>
|
34
|
+
<% end %>
|
35
|
+
</tbody>
|
36
|
+
</table>
|
37
|
+
</div>
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class TableComponent < ViewComponent::Base
|
4
|
+
attr_reader :data, :headers, :caption, :striped, :hoverable, :bordered, :compact, :classes, :variant
|
5
|
+
|
6
|
+
def initialize(data:, headers: nil, caption: nil, striped: false, hoverable: false, bordered: true, compact: false, classes: nil, variant: :default)
|
7
|
+
@data = data || []
|
8
|
+
@headers = headers
|
9
|
+
@caption = caption
|
10
|
+
@striped = striped
|
11
|
+
@hoverable = hoverable
|
12
|
+
@bordered = bordered
|
13
|
+
@compact = compact
|
14
|
+
@classes = classes
|
15
|
+
@variant = variant.to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def table_classes
|
19
|
+
ThemeHelper.generate_component_classes(:table, @variant, { bordered: @bordered, classes: @classes })
|
20
|
+
end
|
21
|
+
|
22
|
+
def table_container_classes
|
23
|
+
[
|
24
|
+
ThemeHelper::LAYOUT_STYLES[:table][:container],
|
25
|
+
get_border_color
|
26
|
+
].compact.join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
def caption_classes
|
30
|
+
[
|
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(' ')
|
36
|
+
end
|
37
|
+
|
38
|
+
def thead_classes
|
39
|
+
ThemeHelper::LAYOUT_STYLES[:table][:header]
|
40
|
+
end
|
41
|
+
|
42
|
+
def tbody_classes
|
43
|
+
@striped ? ThemeHelper::LAYOUT_STYLES[:table][:row][:striped] : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def tr_classes(index)
|
47
|
+
[
|
48
|
+
@hoverable ? ThemeHelper::LAYOUT_STYLES[:table][:row][:hover] : nil,
|
49
|
+
@striped ? nil : (index.odd? ? 'bg-gray-50' : nil)
|
50
|
+
].compact.join(' ')
|
51
|
+
end
|
52
|
+
|
53
|
+
def th_classes
|
54
|
+
[
|
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(' ')
|
60
|
+
end
|
61
|
+
|
62
|
+
def td_classes
|
63
|
+
[
|
64
|
+
@compact ? 'px-2 py-1' : 'px-4 py-3',
|
65
|
+
@bordered ? "border #{get_border_color}" : nil,
|
66
|
+
'text-sm'
|
67
|
+
].compact.join(' ')
|
68
|
+
end
|
69
|
+
|
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
|
85
|
+
end
|
86
|
+
|
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
|
102
|
+
end
|
103
|
+
|
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
|
119
|
+
end
|
120
|
+
|
121
|
+
def headers_for_display
|
122
|
+
return @headers if @headers.present?
|
123
|
+
return [] if @data.empty?
|
124
|
+
|
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)
|
128
|
+
first_item.keys
|
129
|
+
elsif first_item.respond_to?(:attributes)
|
130
|
+
first_item.attributes.keys - ['id', 'created_at', 'updated_at']
|
131
|
+
else
|
132
|
+
[]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def render?
|
137
|
+
@data.present?
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|