better_ui 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +225 -119
- data/app/assets/stylesheets/better_ui/application.css +0 -356
- data/app/components/better_ui/application/card/component.html.erb +20 -0
- data/app/components/better_ui/application/card/component.rb +214 -0
- data/app/components/better_ui/application/main/component.html.erb +9 -0
- data/app/components/better_ui/application/main/component.rb +123 -0
- data/app/components/better_ui/application/navbar/component.html.erb +92 -0
- data/app/components/better_ui/application/navbar/component.rb +136 -0
- data/app/components/better_ui/application/sidebar/component.html.erb +190 -0
- data/app/components/better_ui/application/sidebar/component.rb +129 -0
- data/app/components/better_ui/general/alert/component.html.erb +32 -0
- data/app/components/better_ui/general/alert/component.rb +242 -0
- data/app/components/better_ui/general/avatar/component.html.erb +20 -0
- data/app/components/better_ui/general/avatar/component.rb +301 -0
- data/app/components/better_ui/general/badge/component.html.erb +23 -0
- data/app/components/better_ui/general/badge/component.rb +248 -0
- data/app/components/better_ui/general/breadcrumb/component.html.erb +15 -0
- data/app/components/better_ui/general/breadcrumb/component.rb +187 -0
- data/app/components/better_ui/general/button/component.html.erb +34 -0
- data/app/components/better_ui/general/button/component.rb +214 -0
- data/app/components/better_ui/general/divider/component.html.erb +10 -0
- data/app/components/better_ui/general/divider/component.rb +226 -0
- data/app/components/better_ui/general/field/component.html.erb +27 -0
- data/app/components/better_ui/general/field/component.rb +37 -0
- data/app/components/better_ui/general/heading/component.html.erb +22 -0
- data/app/components/better_ui/general/heading/component.rb +257 -0
- data/app/components/better_ui/general/icon/component.html.erb +7 -0
- data/app/components/better_ui/general/icon/component.rb +239 -0
- data/app/components/better_ui/general/input/checkbox/component.html.erb +5 -0
- data/app/components/better_ui/general/input/checkbox/component.rb +238 -0
- data/app/components/better_ui/general/input/datetime/component.html.erb +5 -0
- data/app/components/better_ui/general/input/datetime/component.rb +223 -0
- data/app/components/better_ui/general/input/radio/component.html.erb +5 -0
- data/app/components/better_ui/general/input/radio/component.rb +230 -0
- data/app/components/better_ui/general/input/select/component.html.erb +16 -0
- data/app/components/better_ui/general/input/select/component.rb +184 -0
- data/app/components/better_ui/general/input/select/select_component.html.erb +5 -0
- data/app/components/better_ui/general/input/select/select_component.rb +37 -0
- data/app/components/better_ui/general/input/text/component.html.erb +5 -0
- data/app/components/better_ui/general/input/text/component.rb +171 -0
- data/app/components/better_ui/general/input/textarea/component.html.erb +5 -0
- data/app/components/better_ui/general/input/textarea/component.rb +166 -0
- data/app/components/better_ui/general/link/component.html.erb +18 -0
- data/app/components/better_ui/general/link/component.rb +258 -0
- data/app/components/better_ui/general/panel/component.html.erb +28 -0
- data/app/components/better_ui/general/panel/component.rb +249 -0
- data/app/components/better_ui/general/progress/component.html.erb +11 -0
- data/app/components/better_ui/general/progress/component.rb +160 -0
- data/app/components/better_ui/general/spinner/component.html.erb +35 -0
- data/app/components/better_ui/general/spinner/component.rb +93 -0
- data/app/components/better_ui/general/table/component.html.erb +5 -0
- data/app/components/better_ui/general/table/component.rb +217 -0
- data/app/components/better_ui/general/table/tbody_component.html.erb +3 -0
- data/app/components/better_ui/general/table/tbody_component.rb +30 -0
- data/app/components/better_ui/general/table/td_component.html.erb +3 -0
- data/app/components/better_ui/general/table/td_component.rb +44 -0
- data/app/components/better_ui/general/table/tfoot_component.html.erb +3 -0
- data/app/components/better_ui/general/table/tfoot_component.rb +28 -0
- data/app/components/better_ui/general/table/th_component.html.erb +6 -0
- data/app/components/better_ui/general/table/th_component.rb +51 -0
- data/app/components/better_ui/general/table/thead_component.html.erb +3 -0
- data/app/components/better_ui/general/table/thead_component.rb +28 -0
- data/app/components/better_ui/general/table/tr_component.html.erb +3 -0
- data/app/components/better_ui/general/table/tr_component.rb +30 -0
- data/app/components/better_ui/general/tag/component.html.erb +3 -0
- data/app/components/better_ui/general/tag/component.rb +104 -0
- data/app/components/better_ui/general/tooltip/component.html.erb +7 -0
- data/app/components/better_ui/general/tooltip/component.rb +239 -0
- data/app/helpers/better_ui/application/components/card/card_helper.rb +96 -0
- data/app/helpers/better_ui/application/components/card.rb +11 -0
- data/app/helpers/better_ui/application/components/main/main_helper.rb +64 -0
- data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +77 -0
- data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +51 -0
- data/app/helpers/better_ui/application_helper.rb +42 -179
- data/app/helpers/better_ui/general/components/alert/alert_helper.rb +57 -0
- data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +29 -0
- data/app/helpers/better_ui/general/components/badge/badge_helper.rb +53 -0
- data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +37 -0
- data/app/helpers/better_ui/general/components/button/button_helper.rb +65 -0
- data/app/helpers/better_ui/general/components/container/container_helper.rb +60 -0
- data/app/helpers/better_ui/general/components/divider/divider_helper.rb +63 -0
- data/app/helpers/better_ui/general/components/field/field_helper.rb +26 -0
- data/app/helpers/better_ui/general/components/heading/heading_helper.rb +72 -0
- data/app/helpers/better_ui/general/components/icon/icon_helper.rb +16 -0
- data/app/helpers/better_ui/general/components/input/checkbox/checkbox_helper.rb +81 -0
- data/app/helpers/better_ui/general/components/input/datetime/datetime_helper.rb +91 -0
- data/app/helpers/better_ui/general/components/input/radio/radio_helper.rb +79 -0
- data/app/helpers/better_ui/general/components/input/radio_group/radio_group_helper.rb +124 -0
- data/app/helpers/better_ui/general/components/input/select/select_helper.rb +70 -0
- data/app/helpers/better_ui/general/components/input/text/text_helper.rb +138 -0
- data/app/helpers/better_ui/general/components/input/textarea/textarea_helper.rb +73 -0
- data/app/helpers/better_ui/general/components/link/link_helper.rb +89 -0
- data/app/helpers/better_ui/general/components/panel/panel_helper.rb +83 -0
- data/app/helpers/better_ui/general/components/progress/progress_helper.rb +53 -0
- data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +19 -0
- data/app/helpers/better_ui/general/components/table/table_helper.rb +53 -0
- data/app/helpers/better_ui/general/components/table/tbody_helper.rb +13 -0
- data/app/helpers/better_ui/general/components/table/td_helper.rb +19 -0
- data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +13 -0
- data/app/helpers/better_ui/general/components/table/th_helper.rb +19 -0
- data/app/helpers/better_ui/general/components/table/thead_helper.rb +13 -0
- data/app/helpers/better_ui/general/components/table/tr_helper.rb +13 -0
- data/app/helpers/better_ui/general/components/tag/tag_helper.rb +26 -0
- data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +60 -0
- data/app/views/layouts/better_ui/application.html.erb +6 -124
- data/config/initializers/lookbook.rb +23 -0
- data/config/routes.rb +0 -8
- data/lib/better_ui/engine.rb +5 -19
- data/lib/better_ui/railtie.rb +20 -0
- data/lib/better_ui/version.rb +1 -1
- data/lib/better_ui.rb +4 -20
- metadata +131 -28
- data/app/controllers/better_ui/docs_controller.rb +0 -41
- 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
@@ -0,0 +1,249 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Panel
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
attr_reader :header, :footer, :body, :title, :padding, :theme, :style, :radius
|
6
|
+
|
7
|
+
# Classi base sempre presenti
|
8
|
+
PANEL_BASE_CLASSES = "overflow-hidden"
|
9
|
+
|
10
|
+
# Temi con classi Tailwind dirette - LOGICA CORRETTA
|
11
|
+
PANEL_THEME_CLASSES = {
|
12
|
+
default: "bg-gray-800 border-gray-700", # Scuro per sfondi scuri
|
13
|
+
white: "bg-white border-gray-200", # Chiaro per sfondi chiari
|
14
|
+
red: "bg-red-50 border-red-200",
|
15
|
+
rose: "bg-rose-50 border-rose-200",
|
16
|
+
orange: "bg-orange-50 border-orange-200",
|
17
|
+
green: "bg-green-50 border-green-200",
|
18
|
+
blue: "bg-blue-50 border-blue-200",
|
19
|
+
yellow: "bg-yellow-50 border-yellow-200",
|
20
|
+
violet: "bg-violet-50 border-violet-200"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Temi per testo - LOGICA CORRETTA
|
24
|
+
PANEL_TEXT_THEME_CLASSES = {
|
25
|
+
default: "text-white", # Testo bianco per sfondi scuri
|
26
|
+
white: "text-gray-900", # Testo nero per sfondi chiari
|
27
|
+
red: "text-red-900",
|
28
|
+
rose: "text-rose-900",
|
29
|
+
orange: "text-orange-900",
|
30
|
+
green: "text-green-900",
|
31
|
+
blue: "text-blue-900",
|
32
|
+
yellow: "text-yellow-900",
|
33
|
+
violet: "text-violet-900"
|
34
|
+
}
|
35
|
+
|
36
|
+
# Stili con classi Tailwind dirette
|
37
|
+
PANEL_STYLE_CLASSES = {
|
38
|
+
default: "border shadow-sm",
|
39
|
+
flat: "border-0",
|
40
|
+
raised: "border shadow-lg",
|
41
|
+
bordered: "border-2"
|
42
|
+
}
|
43
|
+
|
44
|
+
# Padding con classi Tailwind dirette
|
45
|
+
PANEL_PADDING_CLASSES = {
|
46
|
+
none: "p-0",
|
47
|
+
small: "p-2",
|
48
|
+
medium: "p-4",
|
49
|
+
large: "p-6"
|
50
|
+
}
|
51
|
+
|
52
|
+
# Radius con classi Tailwind dirette
|
53
|
+
PANEL_RADIUS_CLASSES = {
|
54
|
+
none: "rounded-none",
|
55
|
+
small: "rounded",
|
56
|
+
medium: "rounded-md",
|
57
|
+
large: "rounded-lg",
|
58
|
+
full: "rounded-full"
|
59
|
+
}
|
60
|
+
|
61
|
+
# @param title [String] titolo del pannello (opzionale)
|
62
|
+
# @param body [String] contenuto HTML del pannello (opzionale)
|
63
|
+
# @param header [String] header personalizzato (opzionale)
|
64
|
+
# @param footer [String] footer del pannello (opzionale)
|
65
|
+
# @param theme [Symbol] tema del colore (:default, :white, etc.)
|
66
|
+
# @param style [Symbol] stile (:default, :flat, :raised, :bordered)
|
67
|
+
# @param padding [Symbol] padding interno (:none, :small, :medium, :large)
|
68
|
+
# @param radius [Symbol] raggio dei bordi (:none, :small, :medium, :large, :full)
|
69
|
+
# @param html_options [Hash] opzioni HTML aggiuntive
|
70
|
+
def initialize(
|
71
|
+
title: nil,
|
72
|
+
body: nil,
|
73
|
+
header: nil,
|
74
|
+
footer: nil,
|
75
|
+
theme: :white,
|
76
|
+
style: :default,
|
77
|
+
padding: :medium,
|
78
|
+
radius: :small,
|
79
|
+
**html_options
|
80
|
+
)
|
81
|
+
@title = title
|
82
|
+
@body = body
|
83
|
+
@header = header
|
84
|
+
@footer = footer
|
85
|
+
@theme = theme.to_sym
|
86
|
+
@style = style.to_sym
|
87
|
+
@padding = padding.to_sym
|
88
|
+
@radius = radius.to_sym
|
89
|
+
@html_options = html_options
|
90
|
+
|
91
|
+
validate_params
|
92
|
+
end
|
93
|
+
|
94
|
+
# Combina tutte le classi CSS per il panel
|
95
|
+
def combined_classes
|
96
|
+
[
|
97
|
+
PANEL_BASE_CLASSES,
|
98
|
+
get_theme_class,
|
99
|
+
get_style_class,
|
100
|
+
get_radius_class,
|
101
|
+
@html_options[:class]
|
102
|
+
].compact.join(" ")
|
103
|
+
end
|
104
|
+
|
105
|
+
# Restituisce gli attributi HTML per il panel
|
106
|
+
def panel_attributes
|
107
|
+
attrs = @html_options.except(:class)
|
108
|
+
attrs[:class] = combined_classes
|
109
|
+
attrs
|
110
|
+
end
|
111
|
+
|
112
|
+
# Classi per l'header
|
113
|
+
def header_classes
|
114
|
+
[
|
115
|
+
"border-b",
|
116
|
+
get_border_theme_class,
|
117
|
+
get_text_theme_class,
|
118
|
+
get_padding_class
|
119
|
+
].compact.join(" ")
|
120
|
+
end
|
121
|
+
|
122
|
+
# Classi per il body
|
123
|
+
def body_classes
|
124
|
+
[
|
125
|
+
get_text_theme_class,
|
126
|
+
get_padding_class
|
127
|
+
].compact.join(" ")
|
128
|
+
end
|
129
|
+
|
130
|
+
# Classi per il footer
|
131
|
+
def footer_classes
|
132
|
+
[
|
133
|
+
"border-t",
|
134
|
+
get_border_theme_class,
|
135
|
+
get_text_theme_class,
|
136
|
+
get_padding_class
|
137
|
+
].compact.join(" ")
|
138
|
+
end
|
139
|
+
|
140
|
+
# Classi per il title
|
141
|
+
def title_classes
|
142
|
+
[
|
143
|
+
"font-semibold text-lg leading-6",
|
144
|
+
get_text_theme_class
|
145
|
+
].compact.join(" ")
|
146
|
+
end
|
147
|
+
|
148
|
+
# Determina se il pannello deve essere renderizzato
|
149
|
+
def render?
|
150
|
+
@body.present? || @header.present? || @footer.present? || content.present?
|
151
|
+
end
|
152
|
+
|
153
|
+
# Determina se mostrare l'header
|
154
|
+
def show_header?
|
155
|
+
@header.present? || @title.present?
|
156
|
+
end
|
157
|
+
|
158
|
+
# Determina se mostrare il body
|
159
|
+
def show_body?
|
160
|
+
@body.present? || content.present?
|
161
|
+
end
|
162
|
+
|
163
|
+
# Determina se mostrare il footer
|
164
|
+
def show_footer?
|
165
|
+
@footer.present?
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def get_theme_class
|
171
|
+
PANEL_THEME_CLASSES[@theme] || PANEL_THEME_CLASSES[:white]
|
172
|
+
end
|
173
|
+
|
174
|
+
def get_text_theme_class
|
175
|
+
PANEL_TEXT_THEME_CLASSES[@theme] || PANEL_TEXT_THEME_CLASSES[:white]
|
176
|
+
end
|
177
|
+
|
178
|
+
def get_border_theme_class
|
179
|
+
# Usa lo stesso colore del bordo principale ma più leggero per i separatori interni
|
180
|
+
case @theme
|
181
|
+
when :default
|
182
|
+
"border-gray-600"
|
183
|
+
when :white
|
184
|
+
"border-gray-100"
|
185
|
+
when :red
|
186
|
+
"border-red-100"
|
187
|
+
when :rose
|
188
|
+
"border-rose-100"
|
189
|
+
when :orange
|
190
|
+
"border-orange-100"
|
191
|
+
when :green
|
192
|
+
"border-green-100"
|
193
|
+
when :blue
|
194
|
+
"border-blue-100"
|
195
|
+
when :yellow
|
196
|
+
"border-yellow-100"
|
197
|
+
when :violet
|
198
|
+
"border-violet-100"
|
199
|
+
else
|
200
|
+
"border-gray-100"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def get_style_class
|
205
|
+
PANEL_STYLE_CLASSES[@style] || PANEL_STYLE_CLASSES[:default]
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_radius_class
|
209
|
+
PANEL_RADIUS_CLASSES[@radius] || PANEL_RADIUS_CLASSES[:small]
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_padding_class
|
213
|
+
PANEL_PADDING_CLASSES[@padding] || PANEL_PADDING_CLASSES[:medium]
|
214
|
+
end
|
215
|
+
|
216
|
+
def validate_params
|
217
|
+
validate_theme
|
218
|
+
validate_style
|
219
|
+
validate_padding
|
220
|
+
validate_radius
|
221
|
+
end
|
222
|
+
|
223
|
+
def validate_theme
|
224
|
+
unless PANEL_THEME_CLASSES.keys.include?(@theme)
|
225
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{PANEL_THEME_CLASSES.keys.join(', ')}"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def validate_style
|
230
|
+
unless PANEL_STYLE_CLASSES.keys.include?(@style)
|
231
|
+
raise ArgumentError, "Lo stile deve essere uno tra: #{PANEL_STYLE_CLASSES.keys.join(', ')}"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def validate_padding
|
236
|
+
unless PANEL_PADDING_CLASSES.keys.include?(@padding)
|
237
|
+
raise ArgumentError, "Il padding deve essere uno tra: #{PANEL_PADDING_CLASSES.keys.join(', ')}"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def validate_radius
|
242
|
+
unless PANEL_RADIUS_CLASSES.keys.include?(@radius)
|
243
|
+
raise ArgumentError, "Il raggio deve essere uno tra: #{PANEL_RADIUS_CLASSES.keys.join(', ')}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div class="bui-progress-wrapper">
|
2
|
+
<div <%= progress_attributes.map { |k, v| "#{k}=\"#{v}\"" }.join(' ').html_safe %>>
|
3
|
+
<div <%= bar_attributes.map { |k, v| "#{k}=\"#{v}\"" }.join(' ').html_safe %>></div>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<% if show_label? %>
|
7
|
+
<div class="bui-progress-label mt-1 text-sm text-gray-600 text-center">
|
8
|
+
<%= value %>%
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Progress
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
# Classi base sempre presenti
|
6
|
+
PROGRESS_BASE_CLASSES = "relative w-full bg-gray-200 rounded-full overflow-hidden"
|
7
|
+
|
8
|
+
# Classi per la barra di progresso
|
9
|
+
PROGRESS_BAR_BASE_CLASSES = "h-full transition-all duration-300 ease-in-out"
|
10
|
+
|
11
|
+
# Dimensioni della progress bar con classi Tailwind dirette
|
12
|
+
PROGRESS_SIZES = {
|
13
|
+
small: "h-2",
|
14
|
+
medium: "h-4",
|
15
|
+
large: "h-6"
|
16
|
+
}
|
17
|
+
|
18
|
+
# Temi di progress bar con classi Tailwind dirette
|
19
|
+
PROGRESS_THEMES = {
|
20
|
+
default: "bg-gray-600",
|
21
|
+
white: "bg-white border border-gray-300",
|
22
|
+
red: "bg-red-600",
|
23
|
+
rose: "bg-rose-600",
|
24
|
+
orange: "bg-orange-600",
|
25
|
+
green: "bg-green-600",
|
26
|
+
blue: "bg-blue-600",
|
27
|
+
yellow: "bg-yellow-600",
|
28
|
+
violet: "bg-violet-600"
|
29
|
+
}
|
30
|
+
|
31
|
+
# Classi per il background container
|
32
|
+
PROGRESS_CONTAINER_THEMES = {
|
33
|
+
default: "bg-gray-200",
|
34
|
+
white: "bg-gray-100",
|
35
|
+
red: "bg-red-100",
|
36
|
+
rose: "bg-rose-100",
|
37
|
+
orange: "bg-orange-100",
|
38
|
+
green: "bg-green-100",
|
39
|
+
blue: "bg-blue-100",
|
40
|
+
yellow: "bg-yellow-100",
|
41
|
+
violet: "bg-violet-100"
|
42
|
+
}
|
43
|
+
|
44
|
+
# @param value [Integer] percentuale di completamento (0-100)
|
45
|
+
# @param theme [Symbol] :default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet
|
46
|
+
# @param size [Symbol] :small, :medium, :large
|
47
|
+
# @param label [Boolean] mostra etichetta con percentuale
|
48
|
+
# @param classes [String] classi CSS aggiuntive per il container
|
49
|
+
# @param html_options [Hash] opzioni HTML per il container
|
50
|
+
def initialize(
|
51
|
+
value: 0,
|
52
|
+
theme: :white,
|
53
|
+
size: :medium,
|
54
|
+
label: false,
|
55
|
+
classes: nil,
|
56
|
+
**html_options
|
57
|
+
)
|
58
|
+
@value = [ 0, [ value.to_i, 100 ].min ].max # Clamp tra 0 e 100
|
59
|
+
@theme = theme.to_sym
|
60
|
+
@size = size.to_sym
|
61
|
+
@label = label
|
62
|
+
@classes = classes
|
63
|
+
@html_options = html_options
|
64
|
+
|
65
|
+
validate_params
|
66
|
+
end
|
67
|
+
|
68
|
+
# Combina tutte le classi per il container
|
69
|
+
def combined_classes
|
70
|
+
[
|
71
|
+
PROGRESS_BASE_CLASSES,
|
72
|
+
get_size_class,
|
73
|
+
get_container_theme_class,
|
74
|
+
@classes,
|
75
|
+
@html_options[:class]
|
76
|
+
].compact.join(" ")
|
77
|
+
end
|
78
|
+
|
79
|
+
# Combina tutte le classi per la barra di progresso
|
80
|
+
def bar_classes
|
81
|
+
[
|
82
|
+
PROGRESS_BAR_BASE_CLASSES,
|
83
|
+
get_theme_class
|
84
|
+
].compact.join(" ")
|
85
|
+
end
|
86
|
+
|
87
|
+
# Restituisce gli attributi per il container della progress bar
|
88
|
+
def progress_attributes
|
89
|
+
attrs = {
|
90
|
+
class: combined_classes,
|
91
|
+
role: "progressbar",
|
92
|
+
"aria-valuenow": @value,
|
93
|
+
"aria-valuemin": 0,
|
94
|
+
"aria-valuemax": 100,
|
95
|
+
"aria-label": "Progresso: #{@value}%"
|
96
|
+
}
|
97
|
+
|
98
|
+
# Aggiungi altri attributi HTML se presenti
|
99
|
+
@html_options.except(:class).each do |key, value|
|
100
|
+
attrs[key] = value
|
101
|
+
end
|
102
|
+
|
103
|
+
attrs
|
104
|
+
end
|
105
|
+
|
106
|
+
# Restituisce gli attributi per la barra di progresso
|
107
|
+
def bar_attributes
|
108
|
+
{
|
109
|
+
class: bar_classes,
|
110
|
+
style: "width: #{@value}%"
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Restituisce il valore percentuale
|
115
|
+
attr_reader :value
|
116
|
+
|
117
|
+
# Verifica se mostrare l'etichetta
|
118
|
+
def show_label?
|
119
|
+
@label
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def validate_params
|
125
|
+
validate_theme
|
126
|
+
validate_size
|
127
|
+
end
|
128
|
+
|
129
|
+
def validate_theme
|
130
|
+
valid_themes = PROGRESS_THEMES.keys
|
131
|
+
unless valid_themes.include?(@theme)
|
132
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{valid_themes.join(', ')}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def validate_size
|
137
|
+
valid_sizes = PROGRESS_SIZES.keys
|
138
|
+
unless valid_sizes.include?(@size)
|
139
|
+
raise ArgumentError, "La dimensione deve essere una tra: #{valid_sizes.join(', ')}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Genera le classi per la dimensione
|
144
|
+
def get_size_class
|
145
|
+
PROGRESS_SIZES[@size] || PROGRESS_SIZES[:medium]
|
146
|
+
end
|
147
|
+
|
148
|
+
# Genera le classi per il tema della barra
|
149
|
+
def get_theme_class
|
150
|
+
PROGRESS_THEMES[@theme] || PROGRESS_THEMES[:white]
|
151
|
+
end
|
152
|
+
|
153
|
+
# Genera le classi per il tema del container
|
154
|
+
def get_container_theme_class
|
155
|
+
PROGRESS_CONTAINER_THEMES[@theme] || PROGRESS_CONTAINER_THEMES[:white]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<div <%= tag.attributes(container_attributes) %>>
|
2
|
+
<div class="flex-shrink-0">
|
3
|
+
<svg class="<%= svg_classes %> animate-spin" viewBox="0 0 24 24" fill="none">
|
4
|
+
<circle
|
5
|
+
cx="12"
|
6
|
+
cy="12"
|
7
|
+
r="10"
|
8
|
+
stroke="currentColor"
|
9
|
+
stroke-width="2"
|
10
|
+
stroke-linecap="round"
|
11
|
+
stroke-dasharray="32"
|
12
|
+
stroke-dashoffset="32">
|
13
|
+
<animate
|
14
|
+
attributeName="stroke-dasharray"
|
15
|
+
dur="2s"
|
16
|
+
values="0 32;16 16;0 32;0 32"
|
17
|
+
repeatCount="indefinite" />
|
18
|
+
<animate
|
19
|
+
attributeName="stroke-dashoffset"
|
20
|
+
dur="2s"
|
21
|
+
values="0;-16;-32;-32"
|
22
|
+
repeatCount="indefinite" />
|
23
|
+
<animateTransform
|
24
|
+
attributeName="transform"
|
25
|
+
type="rotate"
|
26
|
+
dur="2s"
|
27
|
+
values="0 12 12;360 12 12"
|
28
|
+
repeatCount="indefinite" />
|
29
|
+
</circle>
|
30
|
+
</svg>
|
31
|
+
</div>
|
32
|
+
<% if show_label? %>
|
33
|
+
<span class="text-sm font-medium"><%= label %></span>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Spinner
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
THEMES = %i[default white red rose orange green blue yellow violet].freeze
|
6
|
+
SIZES = %i[small medium large].freeze
|
7
|
+
STYLES = %i[default outline].freeze
|
8
|
+
|
9
|
+
# Classi base sempre presenti
|
10
|
+
SPINNER_BASE_CLASSES = "inline-flex items-center gap-2"
|
11
|
+
|
12
|
+
# Dimensioni SVG con classi Tailwind dirette
|
13
|
+
SPINNER_SIZES = {
|
14
|
+
small: "w-4 h-4", # 16px
|
15
|
+
medium: "w-6 h-6", # 24px
|
16
|
+
large: "w-8 h-8" # 32px
|
17
|
+
}
|
18
|
+
|
19
|
+
# Temi colore con classi Tailwind dirette
|
20
|
+
SPINNER_THEMES = {
|
21
|
+
default: "text-gray-900",
|
22
|
+
white: "text-white",
|
23
|
+
red: "text-red-500",
|
24
|
+
rose: "text-rose-500",
|
25
|
+
orange: "text-orange-500",
|
26
|
+
green: "text-green-500",
|
27
|
+
blue: "text-blue-500",
|
28
|
+
yellow: "text-yellow-500",
|
29
|
+
violet: "text-violet-500"
|
30
|
+
}
|
31
|
+
|
32
|
+
# Stili con classi Tailwind dirette
|
33
|
+
SPINNER_STYLES = {
|
34
|
+
default: "",
|
35
|
+
outline: "opacity-75"
|
36
|
+
}
|
37
|
+
|
38
|
+
def initialize(theme: :default, size: :medium, style: :default, label: nil, **html_options)
|
39
|
+
@theme = theme.to_sym
|
40
|
+
@size = size.to_sym
|
41
|
+
@style = style.to_sym
|
42
|
+
@label = label
|
43
|
+
@html_options = html_options
|
44
|
+
|
45
|
+
validate_options!
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
attr_reader :theme, :size, :style, :label, :html_options
|
51
|
+
|
52
|
+
def validate_options!
|
53
|
+
raise ArgumentError, "Theme deve essere uno di: #{THEMES.join(', ')}" unless THEMES.include?(theme)
|
54
|
+
raise ArgumentError, "Size deve essere uno di: #{SIZES.join(', ')}" unless SIZES.include?(size)
|
55
|
+
raise ArgumentError, "Style deve essere uno di: #{STYLES.join(', ')}" unless STYLES.include?(style)
|
56
|
+
end
|
57
|
+
|
58
|
+
def combined_classes
|
59
|
+
[
|
60
|
+
SPINNER_BASE_CLASSES,
|
61
|
+
get_spinner_theme_classes,
|
62
|
+
get_spinner_style_classes,
|
63
|
+
html_options[:class]
|
64
|
+
].compact.join(" ")
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_spinner_theme_classes
|
68
|
+
SPINNER_THEMES[theme] || SPINNER_THEMES[:default]
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_spinner_style_classes
|
72
|
+
SPINNER_STYLES[style] || SPINNER_STYLES[:default]
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_spinner_size_classes
|
76
|
+
SPINNER_SIZES[size] || SPINNER_SIZES[:medium]
|
77
|
+
end
|
78
|
+
|
79
|
+
def container_attributes
|
80
|
+
html_options.except(:class).merge(class: combined_classes)
|
81
|
+
end
|
82
|
+
|
83
|
+
def svg_classes
|
84
|
+
get_spinner_size_classes
|
85
|
+
end
|
86
|
+
|
87
|
+
def show_label?
|
88
|
+
label.present?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|