better_ui_tmp 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +211 -0
- data/Rakefile +8 -0
- data/app/assets/builds/application.js +1 -0
- data/app/assets/builds/better_ui.css +1 -0
- data/app/assets/stylesheets/better_ui.scss +3 -0
- data/app/components/better_ui/application/main/component.html.erb +5 -0
- data/app/components/better_ui/application/main/component.rb +99 -0
- data/app/components/better_ui/application/navbar/component.html.erb +219 -0
- data/app/components/better_ui/application/navbar/component.rb +148 -0
- data/app/components/better_ui/application/sidebar/component.html.erb +184 -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 +186 -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/card/component.html.erb +21 -0
- data/app/components/better_ui/general/card/component.rb +37 -0
- data/app/components/better_ui/general/container/component.html.erb +8 -0
- data/app/components/better_ui/general/container/component.rb +158 -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/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 +1 -0
- data/app/components/better_ui/general/icon/component.rb +222 -0
- data/app/components/better_ui/general/link/component.html.erb +18 -0
- data/app/components/better_ui/general/link/component.rb +255 -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/controllers/better_ui/application_controller.rb +5 -0
- data/app/helpers/better_ui/application/components/main/main_helper.rb +42 -0
- data/app/helpers/better_ui/application/components/main.rb +13 -0
- data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +51 -0
- data/app/helpers/better_ui/application/components/navbar.rb +13 -0
- data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +51 -0
- data/app/helpers/better_ui/application/components/sidebar.rb +13 -0
- data/app/helpers/better_ui/application_helper.rb +10 -0
- data/app/helpers/better_ui/form_helper.rb +5 -0
- data/app/helpers/better_ui/general/components/alert/alert_helper.rb +29 -0
- data/app/helpers/better_ui/general/components/alert.rb +13 -0
- data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +29 -0
- data/app/helpers/better_ui/general/components/avatar.rb +13 -0
- data/app/helpers/better_ui/general/components/badge/badge_helper.rb +53 -0
- data/app/helpers/better_ui/general/components/badge.rb +13 -0
- data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +37 -0
- data/app/helpers/better_ui/general/components/breadcrumb.rb +13 -0
- data/app/helpers/better_ui/general/components/button/button_helper.rb +65 -0
- data/app/helpers/better_ui/general/components/button.rb +13 -0
- data/app/helpers/better_ui/general/components/card/card_helper.rb +37 -0
- data/app/helpers/better_ui/general/components/card.rb +13 -0
- data/app/helpers/better_ui/general/components/container/container_helper.rb +60 -0
- data/app/helpers/better_ui/general/components/container.rb +13 -0
- data/app/helpers/better_ui/general/components/divider/divider_helper.rb +63 -0
- data/app/helpers/better_ui/general/components/divider.rb +13 -0
- data/app/helpers/better_ui/general/components/heading/heading_helper.rb +72 -0
- data/app/helpers/better_ui/general/components/heading.rb +13 -0
- data/app/helpers/better_ui/general/components/icon/icon_helper.rb +16 -0
- data/app/helpers/better_ui/general/components/icon.rb +13 -0
- data/app/helpers/better_ui/general/components/link/link_helper.rb +89 -0
- data/app/helpers/better_ui/general/components/link.rb +13 -0
- data/app/helpers/better_ui/general/components/panel/panel_helper.rb +83 -0
- data/app/helpers/better_ui/general/components/panel.rb +13 -0
- data/app/helpers/better_ui/general/components/progress/progress_helper.rb +53 -0
- data/app/helpers/better_ui/general/components/progress.rb +11 -0
- data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +17 -0
- data/app/helpers/better_ui/general/components/spinner.rb +10 -0
- data/app/helpers/better_ui/general/components/table/table_helper.rb +13 -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/table.rb +25 -0
- data/app/helpers/better_ui/general/components/tag/tag_helper.rb +26 -0
- data/app/helpers/better_ui/general/components/tag.rb +15 -0
- data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +60 -0
- data/app/helpers/better_ui/general/components/tooltip.rb +13 -0
- data/app/helpers/better_ui/general_helper.rb +24 -0
- data/app/helpers/better_ui_helper.rb +16 -0
- data/app/javascript/application.js +1 -0
- data/app/jobs/better_ui/application_job.rb +4 -0
- data/app/mailers/better_ui/application_mailer.rb +6 -0
- data/app/models/better_ui/application_record.rb +5 -0
- data/app/views/components/better_ui/general/table/_custom_body_row.html.erb +17 -0
- data/app/views/components/better_ui/general/table/_custom_footer_rows.html.erb +17 -0
- data/app/views/components/better_ui/general/table/_custom_header_rows.html.erb +12 -0
- data/app/views/layouts/component_preview.html.erb +32 -0
- data/config/initializers/lookbook.rb +23 -0
- data/config/routes.rb +3 -0
- data/lib/better_ui/engine.rb +109 -0
- data/lib/better_ui/version.rb +3 -0
- data/lib/better_ui.rb +37 -0
- data/lib/generators/better_ui/install_generator.rb +103 -0
- data/lib/generators/better_ui/stylesheet_generator.rb +159 -0
- data/lib/generators/better_ui/templates/components/_avatar.scss +200 -0
- data/lib/generators/better_ui/templates/components/_badge.scss +154 -0
- data/lib/generators/better_ui/templates/components/_breadcrumb.scss +106 -0
- data/lib/generators/better_ui/templates/components/_button.scss +109 -0
- data/lib/generators/better_ui/templates/components/_card.scss +60 -0
- data/lib/generators/better_ui/templates/components/_heading.scss +81 -0
- data/lib/generators/better_ui/templates/components/_icon.scss +134 -0
- data/lib/generators/better_ui/templates/components/_index.scss +17 -0
- data/lib/generators/better_ui/templates/components/_link.scss +100 -0
- data/lib/generators/better_ui/templates/components/_panel.scss +104 -0
- data/lib/generators/better_ui/templates/components/_spinner.scss +129 -0
- data/lib/generators/better_ui/templates/components/_table.scss +156 -0
- data/lib/generators/better_ui/templates/components/_variables.scss +0 -0
- data/lib/generators/better_ui/templates/components_stylesheet.scss +35 -0
- data/lib/generators/better_ui/templates/index.scss +18 -0
- data/lib/generators/better_ui/templates/initializer.rb +41 -0
- data/lib/tasks/better_ui_tasks.rake +4 -0
- metadata +260 -0
@@ -0,0 +1,255 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Link
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
attr_reader :label, :href, :theme, :orientation, :style, :size, :icon, :active, :disabled, :data, :method, :target
|
6
|
+
|
7
|
+
# Classi base sempre presenti
|
8
|
+
LINK_BASE_CLASSES = "transition-colors duration-200 no-underline"
|
9
|
+
|
10
|
+
# Temi con classi Tailwind dirette - LOGICA CORRETTA
|
11
|
+
LINK_THEME_CLASSES = {
|
12
|
+
default: "text-white hover:text-gray-300", # Bianco per sfondi scuri
|
13
|
+
white: "text-gray-900 hover:text-gray-700", # Nero per sfondi chiari
|
14
|
+
red: "text-red-500 hover:text-red-600",
|
15
|
+
rose: "text-rose-500 hover:text-rose-600",
|
16
|
+
orange: "text-orange-500 hover:text-orange-600",
|
17
|
+
green: "text-green-500 hover:text-green-600",
|
18
|
+
blue: "text-blue-500 hover:text-blue-600",
|
19
|
+
yellow: "text-yellow-600 hover:text-yellow-700",
|
20
|
+
violet: "text-violet-500 hover:text-violet-600"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Orientamenti con classi Tailwind dirette
|
24
|
+
LINK_ORIENTATION_CLASSES = {
|
25
|
+
horizontal: "inline-flex items-center",
|
26
|
+
vertical: "flex flex-col items-center"
|
27
|
+
}
|
28
|
+
|
29
|
+
# Stili con classi Tailwind dirette
|
30
|
+
LINK_STYLE_CLASSES = {
|
31
|
+
default: "",
|
32
|
+
underline: "underline",
|
33
|
+
bold: "font-bold",
|
34
|
+
text: "no-underline"
|
35
|
+
}
|
36
|
+
|
37
|
+
# Dimensioni con classi Tailwind dirette
|
38
|
+
LINK_SIZE_CLASSES = {
|
39
|
+
small: "text-sm",
|
40
|
+
medium: "text-base",
|
41
|
+
large: "text-lg"
|
42
|
+
}
|
43
|
+
|
44
|
+
# Stati con classi Tailwind dirette
|
45
|
+
LINK_STATE_CLASSES = {
|
46
|
+
normal: "",
|
47
|
+
active: "font-semibold",
|
48
|
+
disabled: "opacity-50 cursor-not-allowed pointer-events-none"
|
49
|
+
}
|
50
|
+
|
51
|
+
# @param label [String] testo del link
|
52
|
+
# @param href [String] URL di destinazione (nil per semplice testo)
|
53
|
+
# @param theme [Symbol] tema del colore (:default, :white, etc.)
|
54
|
+
# @param orientation [Symbol] orientamento (:horizontal, :vertical)
|
55
|
+
# @param style [Symbol] stile (:default, :underline, :bold, :text)
|
56
|
+
# @param size [Symbol] dimensione (:small, :medium, :large)
|
57
|
+
# @param icon [String] icona opzionale
|
58
|
+
# @param active [Boolean] stato attivo del link
|
59
|
+
# @param disabled [Boolean] stato disabilitato del link
|
60
|
+
# @param data [Hash] attributi data
|
61
|
+
# @param method [Symbol] metodo HTTP (per Turbo)
|
62
|
+
# @param target [String] target del link
|
63
|
+
# @param html_options [Hash] opzioni HTML aggiuntive
|
64
|
+
def initialize(
|
65
|
+
label:,
|
66
|
+
href: nil,
|
67
|
+
theme: :white,
|
68
|
+
orientation: :horizontal,
|
69
|
+
style: :default,
|
70
|
+
size: :medium,
|
71
|
+
icon: nil,
|
72
|
+
active: false,
|
73
|
+
disabled: false,
|
74
|
+
data: {},
|
75
|
+
method: nil,
|
76
|
+
target: nil,
|
77
|
+
**html_options
|
78
|
+
)
|
79
|
+
@label = label
|
80
|
+
@href = href
|
81
|
+
@theme = theme.to_sym
|
82
|
+
@orientation = orientation.to_sym
|
83
|
+
@style = style.to_sym
|
84
|
+
@size = size.to_sym
|
85
|
+
@icon = icon
|
86
|
+
@active = active
|
87
|
+
@disabled = disabled
|
88
|
+
@data = data || {}
|
89
|
+
@method = method
|
90
|
+
@target = target
|
91
|
+
@html_options = html_options
|
92
|
+
|
93
|
+
validate_params
|
94
|
+
end
|
95
|
+
|
96
|
+
# Determina se è un link attivo/corrente
|
97
|
+
def active?
|
98
|
+
@active
|
99
|
+
end
|
100
|
+
|
101
|
+
# Determina se è disabilitato
|
102
|
+
def disabled?
|
103
|
+
@disabled
|
104
|
+
end
|
105
|
+
|
106
|
+
# Determina se è un link o solo testo
|
107
|
+
def link?
|
108
|
+
@href.present? && !@disabled
|
109
|
+
end
|
110
|
+
|
111
|
+
# Combina tutte le classi CSS
|
112
|
+
def combined_classes
|
113
|
+
[
|
114
|
+
LINK_BASE_CLASSES,
|
115
|
+
get_theme_class,
|
116
|
+
get_orientation_class,
|
117
|
+
get_style_class,
|
118
|
+
get_size_class,
|
119
|
+
get_state_class,
|
120
|
+
@html_options[:class]
|
121
|
+
].compact.join(" ")
|
122
|
+
end
|
123
|
+
|
124
|
+
# Classi per l'icona con dimensionamento proporzionale
|
125
|
+
def icon_classes
|
126
|
+
return "" unless @icon.present?
|
127
|
+
|
128
|
+
# Definisce spacing e dimensioni icona basate su size
|
129
|
+
base_spacing = case @orientation
|
130
|
+
when :horizontal
|
131
|
+
"mr-2"
|
132
|
+
when :vertical
|
133
|
+
"mb-1"
|
134
|
+
else
|
135
|
+
"mr-2"
|
136
|
+
end
|
137
|
+
|
138
|
+
icon_size = case @size
|
139
|
+
when :small
|
140
|
+
"w-4 h-4"
|
141
|
+
when :medium
|
142
|
+
"w-5 h-5"
|
143
|
+
when :large
|
144
|
+
"w-6 h-6"
|
145
|
+
else
|
146
|
+
"w-5 h-5"
|
147
|
+
end
|
148
|
+
|
149
|
+
"#{base_spacing} #{icon_size} inline-block"
|
150
|
+
end
|
151
|
+
|
152
|
+
# Classi per il testo
|
153
|
+
def text_classes
|
154
|
+
"inline-block"
|
155
|
+
end
|
156
|
+
|
157
|
+
# Restituisce gli attributi per il link/span
|
158
|
+
def element_attributes
|
159
|
+
attrs = @html_options.except(:class)
|
160
|
+
attrs[:class] = combined_classes
|
161
|
+
|
162
|
+
if link?
|
163
|
+
# Attributi specifici per i link
|
164
|
+
if @method.present?
|
165
|
+
attrs[:data] = @data.merge(turbo_method: @method)
|
166
|
+
elsif @data.present?
|
167
|
+
attrs[:data] = @data
|
168
|
+
end
|
169
|
+
|
170
|
+
attrs[:target] = @target if @target.present?
|
171
|
+
attrs[:aria] ||= {}
|
172
|
+
attrs[:aria][:current] = 'page' if active?
|
173
|
+
else
|
174
|
+
# Attributi per span (testo semplice o disabilitato)
|
175
|
+
attrs[:aria] ||= {}
|
176
|
+
attrs[:aria][:disabled] = true if disabled?
|
177
|
+
end
|
178
|
+
|
179
|
+
attrs
|
180
|
+
end
|
181
|
+
|
182
|
+
# Determina se mostrare l'icona
|
183
|
+
def show_icon?
|
184
|
+
@icon.present?
|
185
|
+
end
|
186
|
+
|
187
|
+
# Renderizza l'icona
|
188
|
+
def render_icon
|
189
|
+
return nil unless show_icon?
|
190
|
+
|
191
|
+
if @icon.is_a?(String)
|
192
|
+
render BetterUi::General::IconComponent.new(name: @icon)
|
193
|
+
else
|
194
|
+
@icon # Assumiamo che sia già un componente renderizzato
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
def get_theme_class
|
201
|
+
LINK_THEME_CLASSES[@theme] || LINK_THEME_CLASSES[:white]
|
202
|
+
end
|
203
|
+
|
204
|
+
def get_orientation_class
|
205
|
+
LINK_ORIENTATION_CLASSES[@orientation] || LINK_ORIENTATION_CLASSES[:horizontal]
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_style_class
|
209
|
+
LINK_STYLE_CLASSES[@style] || LINK_STYLE_CLASSES[:default]
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_size_class
|
213
|
+
LINK_SIZE_CLASSES[@size] || LINK_SIZE_CLASSES[:medium]
|
214
|
+
end
|
215
|
+
|
216
|
+
def get_state_class
|
217
|
+
return LINK_STATE_CLASSES[:disabled] if disabled?
|
218
|
+
return LINK_STATE_CLASSES[:active] if active?
|
219
|
+
LINK_STATE_CLASSES[:normal]
|
220
|
+
end
|
221
|
+
|
222
|
+
def validate_params
|
223
|
+
validate_theme
|
224
|
+
validate_orientation
|
225
|
+
validate_style
|
226
|
+
validate_size
|
227
|
+
end
|
228
|
+
|
229
|
+
def validate_theme
|
230
|
+
unless LINK_THEME_CLASSES.keys.include?(@theme)
|
231
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{LINK_THEME_CLASSES.keys.join(', ')}"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def validate_orientation
|
236
|
+
unless LINK_ORIENTATION_CLASSES.keys.include?(@orientation)
|
237
|
+
raise ArgumentError, "L'orientamento deve essere uno tra: #{LINK_ORIENTATION_CLASSES.keys.join(', ')}"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def validate_style
|
242
|
+
unless LINK_STYLE_CLASSES.keys.include?(@style)
|
243
|
+
raise ArgumentError, "Lo stile deve essere uno tra: #{LINK_STYLE_CLASSES.keys.join(', ')}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def validate_size
|
248
|
+
unless LINK_SIZE_CLASSES.keys.include?(@size)
|
249
|
+
raise ArgumentError, "La dimensione deve essere una tra: #{LINK_SIZE_CLASSES.keys.join(', ')}"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<%# Template per il panel %>
|
2
|
+
<div <%= tag.attributes(panel_attributes) %>>
|
3
|
+
<% if show_header? %>
|
4
|
+
<div class="<%= header_classes %>">
|
5
|
+
<% if @header.present? %>
|
6
|
+
<%= raw @header %>
|
7
|
+
<% elsif @title.present? %>
|
8
|
+
<div class="<%= title_classes %>"><%= @title %></div>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<% if show_body? %>
|
14
|
+
<div class="<%= body_classes %>">
|
15
|
+
<% if @body.present? %>
|
16
|
+
<%= raw @body %>
|
17
|
+
<% elsif content.present? %>
|
18
|
+
<%= content %>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<% if show_footer? %>
|
24
|
+
<div class="<%= footer_classes %>">
|
25
|
+
<%= raw @footer %>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
@@ -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
|