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,242 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Alert
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
# Classi base sempre presenti
|
6
|
+
ALERT_BASE_CLASSES = "flex p-4 mb-4 border"
|
7
|
+
|
8
|
+
# Classi per elementi interni
|
9
|
+
ALERT_ICON_CLASSES = "flex-shrink-0 mr-3 w-5 h-5"
|
10
|
+
ALERT_ICON_RIGHT_CLASSES = "flex-shrink-0 ml-3 mr-0"
|
11
|
+
ALERT_CONTENT_CLASSES = "flex-1"
|
12
|
+
ALERT_TITLE_CLASSES = "font-medium mb-1"
|
13
|
+
ALERT_MESSAGE_CLASSES = "text-sm"
|
14
|
+
ALERT_CLOSE_CLASSES = "ml-auto -my-1.5 -mr-1.5 p-1.5 rounded-md focus:ring-2 focus:ring-offset-2 hover:bg-gray-100"
|
15
|
+
|
16
|
+
# Temi di alert con classi Tailwind dirette
|
17
|
+
ALERT_THEME_CLASSES = {
|
18
|
+
default: "bg-black text-white border-gray-900",
|
19
|
+
white: "bg-white text-black border-gray-200",
|
20
|
+
red: "bg-red-500 text-white border-red-600",
|
21
|
+
rose: "bg-rose-500 text-white border-rose-600",
|
22
|
+
orange: "bg-orange-500 text-white border-orange-600",
|
23
|
+
green: "bg-green-500 text-white border-green-600",
|
24
|
+
blue: "bg-blue-500 text-white border-blue-600",
|
25
|
+
yellow: "bg-yellow-500 text-black border-yellow-600",
|
26
|
+
violet: "bg-violet-500 text-white border-violet-600"
|
27
|
+
}
|
28
|
+
|
29
|
+
# Colori icone per ogni tema
|
30
|
+
ALERT_ICON_THEME_CLASSES = {
|
31
|
+
default: "text-white",
|
32
|
+
white: "text-black",
|
33
|
+
red: "text-white",
|
34
|
+
rose: "text-white",
|
35
|
+
orange: "text-white",
|
36
|
+
green: "text-white",
|
37
|
+
blue: "text-white",
|
38
|
+
yellow: "text-black",
|
39
|
+
violet: "text-white"
|
40
|
+
}
|
41
|
+
|
42
|
+
# Colori close button per ogni tema
|
43
|
+
ALERT_CLOSE_THEME_CLASSES = {
|
44
|
+
default: "text-white focus:ring-gray-600",
|
45
|
+
white: "text-black focus:ring-gray-400",
|
46
|
+
red: "text-white focus:ring-red-400",
|
47
|
+
rose: "text-white focus:ring-rose-400",
|
48
|
+
orange: "text-white focus:ring-orange-400",
|
49
|
+
green: "text-white focus:ring-green-400",
|
50
|
+
blue: "text-white focus:ring-blue-400",
|
51
|
+
yellow: "text-black focus:ring-yellow-400",
|
52
|
+
violet: "text-white focus:ring-violet-400"
|
53
|
+
}
|
54
|
+
|
55
|
+
# Border radius con classi Tailwind dirette
|
56
|
+
ALERT_RADIUS_CLASSES = {
|
57
|
+
none: "rounded-none",
|
58
|
+
small: "rounded-sm",
|
59
|
+
medium: "rounded-md",
|
60
|
+
large: "rounded-lg",
|
61
|
+
full: "rounded-full"
|
62
|
+
}
|
63
|
+
|
64
|
+
# Classi per layout quando icon è a destra
|
65
|
+
ALERT_ICON_RIGHT_LAYOUT_CLASSES = "flex-row-reverse"
|
66
|
+
ALERT_CONTENT_RIGHT_CLASSES = "text-right"
|
67
|
+
|
68
|
+
# Classi per alert dismissible
|
69
|
+
ALERT_DISMISSIBLE_CLASSES = "pr-12 relative"
|
70
|
+
ALERT_CLOSE_POSITION_CLASSES = "absolute right-4 top-4"
|
71
|
+
|
72
|
+
# Livelli di importanza con attributi ARIA
|
73
|
+
IMPORTANCE_LEVELS = {
|
74
|
+
high: { role: "alert", "aria-live": "assertive" },
|
75
|
+
medium: { role: "status", "aria-live": "polite" },
|
76
|
+
low: { role: "status", "aria-live": "polite" }
|
77
|
+
}
|
78
|
+
|
79
|
+
# @param title [String] titolo dell'alert (opzionale)
|
80
|
+
# @param message [String] contenuto dell'alert
|
81
|
+
# @param theme [Symbol] :default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet
|
82
|
+
# @param icon [String] nome dell'icona (opzionale)
|
83
|
+
# @param icon_position [Symbol] :left, :right posizione dell'icona
|
84
|
+
# @param dismissible [Boolean] se l'alert può essere chiuso
|
85
|
+
# @param rounded [Symbol] :none, :small, :medium, :large, :full arrotondamento degli angoli
|
86
|
+
# @param importance [Symbol] :high, :medium, :low livello di importanza per accessibilità
|
87
|
+
# @param html_content [Boolean] se il messaggio contiene HTML
|
88
|
+
# @param classes [String] classi CSS aggiuntive
|
89
|
+
# @param html_options [Hash] opzioni HTML per il container
|
90
|
+
def initialize(
|
91
|
+
title: nil,
|
92
|
+
message: nil,
|
93
|
+
theme: :white,
|
94
|
+
icon: nil,
|
95
|
+
icon_position: :left,
|
96
|
+
dismissible: false,
|
97
|
+
rounded: :medium,
|
98
|
+
importance: :medium,
|
99
|
+
html_content: false,
|
100
|
+
classes: nil,
|
101
|
+
**html_options
|
102
|
+
)
|
103
|
+
@title = title
|
104
|
+
@message = message
|
105
|
+
@theme = theme.to_sym
|
106
|
+
@icon = icon
|
107
|
+
@icon_position = icon_position.to_sym
|
108
|
+
@dismissible = dismissible
|
109
|
+
@rounded = rounded.to_sym
|
110
|
+
@importance = importance.to_sym
|
111
|
+
@html_content = html_content
|
112
|
+
@classes = classes
|
113
|
+
@html_options = html_options
|
114
|
+
|
115
|
+
validate_params
|
116
|
+
end
|
117
|
+
|
118
|
+
def default_icon
|
119
|
+
case @theme
|
120
|
+
when :default then "bell"
|
121
|
+
when :white then "information-circle"
|
122
|
+
when :red, :rose then "exclamation-circle"
|
123
|
+
when :orange then "bell"
|
124
|
+
when :green then "check-circle"
|
125
|
+
when :blue then "information-circle"
|
126
|
+
when :yellow then "exclamation-triangle"
|
127
|
+
when :violet then "shield-exclamation"
|
128
|
+
else "information-circle"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Combina tutte le classi
|
133
|
+
def combined_classes
|
134
|
+
[
|
135
|
+
ALERT_BASE_CLASSES,
|
136
|
+
get_theme_class,
|
137
|
+
get_border_radius_class,
|
138
|
+
get_icon_position_class,
|
139
|
+
@dismissible ? ALERT_DISMISSIBLE_CLASSES : nil,
|
140
|
+
@classes,
|
141
|
+
@html_options[:class]
|
142
|
+
].compact.join(" ")
|
143
|
+
end
|
144
|
+
|
145
|
+
# Restituisce gli attributi per l'alert
|
146
|
+
def alert_attributes
|
147
|
+
attrs = {
|
148
|
+
class: combined_classes
|
149
|
+
}
|
150
|
+
|
151
|
+
# Aggiungi attributi ARIA in base al livello di importanza
|
152
|
+
importance_attrs = IMPORTANCE_LEVELS[@importance] || IMPORTANCE_LEVELS[:medium]
|
153
|
+
importance_attrs.each do |key, value|
|
154
|
+
attrs[key] = value
|
155
|
+
end
|
156
|
+
|
157
|
+
# Aggiungi altri attributi HTML se presenti
|
158
|
+
@html_options.except(:class).each do |key, value|
|
159
|
+
attrs[key] = value
|
160
|
+
end
|
161
|
+
|
162
|
+
attrs
|
163
|
+
end
|
164
|
+
|
165
|
+
# Genera le classi del tema
|
166
|
+
def get_theme_class
|
167
|
+
ALERT_THEME_CLASSES[@theme] || ALERT_THEME_CLASSES[:white]
|
168
|
+
end
|
169
|
+
|
170
|
+
# Genera le classi per il border radius
|
171
|
+
def get_border_radius_class
|
172
|
+
ALERT_RADIUS_CLASSES[@rounded] || ALERT_RADIUS_CLASSES[:medium]
|
173
|
+
end
|
174
|
+
|
175
|
+
# Genera la classe per la posizione dell'icona (layout)
|
176
|
+
def get_icon_position_class
|
177
|
+
@icon_position == :right ? ALERT_ICON_RIGHT_LAYOUT_CLASSES : nil
|
178
|
+
end
|
179
|
+
|
180
|
+
# Genera le classi per l'icona
|
181
|
+
def get_icon_classes
|
182
|
+
if @icon_position == :right
|
183
|
+
ALERT_ICON_RIGHT_CLASSES
|
184
|
+
else
|
185
|
+
ALERT_ICON_CLASSES
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Genera le classi per il contenuto
|
190
|
+
def get_content_classes
|
191
|
+
if @icon_position == :right
|
192
|
+
[ALERT_CONTENT_CLASSES, ALERT_CONTENT_RIGHT_CLASSES].join(" ")
|
193
|
+
else
|
194
|
+
ALERT_CONTENT_CLASSES
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Genera le classi per l'icona del tema
|
199
|
+
def get_icon_theme_class
|
200
|
+
ALERT_ICON_THEME_CLASSES[@theme] || ALERT_ICON_THEME_CLASSES[:white]
|
201
|
+
end
|
202
|
+
|
203
|
+
# Genera le classi per il close button
|
204
|
+
def get_close_classes
|
205
|
+
base_classes = ALERT_CLOSE_CLASSES
|
206
|
+
theme_classes = ALERT_CLOSE_THEME_CLASSES[@theme] || ALERT_CLOSE_THEME_CLASSES[:white]
|
207
|
+
position_classes = @dismissible ? ALERT_CLOSE_POSITION_CLASSES : nil
|
208
|
+
|
209
|
+
[base_classes, theme_classes, position_classes].compact.join(" ")
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def validate_params
|
215
|
+
# Validazione tema
|
216
|
+
valid_themes = ALERT_THEME_CLASSES.keys
|
217
|
+
unless valid_themes.include?(@theme)
|
218
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{valid_themes.join(', ')}"
|
219
|
+
end
|
220
|
+
|
221
|
+
# Validazione border radius
|
222
|
+
valid_radius = ALERT_RADIUS_CLASSES.keys
|
223
|
+
unless valid_radius.include?(@rounded)
|
224
|
+
raise ArgumentError, "Il border radius deve essere uno tra: #{valid_radius.join(', ')}"
|
225
|
+
end
|
226
|
+
|
227
|
+
# Validazione posizione icona
|
228
|
+
valid_positions = [:left, :right]
|
229
|
+
unless valid_positions.include?(@icon_position)
|
230
|
+
raise ArgumentError, "La posizione dell'icona deve essere una tra: #{valid_positions.join(', ')}"
|
231
|
+
end
|
232
|
+
|
233
|
+
# Validazione livello di importanza
|
234
|
+
valid_importance = IMPORTANCE_LEVELS.keys
|
235
|
+
unless valid_importance.include?(@importance)
|
236
|
+
raise ArgumentError, "Il livello di importanza deve essere uno tra: #{valid_importance.join(', ')}"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%# Template per l'avatar %>
|
2
|
+
<%= tag.div(**avatar_attributes) do %>
|
3
|
+
<% if show_image? %>
|
4
|
+
<%= tag.img(
|
5
|
+
src: @src,
|
6
|
+
alt: @name || 'Avatar',
|
7
|
+
class: img_classes,
|
8
|
+
width: pixel_size,
|
9
|
+
height: pixel_size
|
10
|
+
) %>
|
11
|
+
<% else %>
|
12
|
+
<%= tag.div(class: placeholder_classes) do %>
|
13
|
+
<%= initials %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<% if show_status? %>
|
18
|
+
<%= tag.span(class: status_indicator_classes) %>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
@@ -0,0 +1,301 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Avatar
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
attr_reader :name, :src, :size, :shape, :status, :status_position, :theme, :style, :classes, :id
|
6
|
+
|
7
|
+
# Classi base sempre presenti
|
8
|
+
AVATAR_BASE_CLASSES = "relative inline-flex items-center justify-center flex-shrink-0 overflow-hidden"
|
9
|
+
|
10
|
+
# Classi per elementi interni
|
11
|
+
AVATAR_IMG_CLASSES = "h-full w-full object-cover"
|
12
|
+
AVATAR_PLACEHOLDER_BASE_CLASSES = "flex items-center justify-center h-full w-full font-medium"
|
13
|
+
AVATAR_STATUS_BASE_CLASSES = "absolute rounded-full border-2 border-white"
|
14
|
+
|
15
|
+
# Dimensioni container con classi Tailwind dirette
|
16
|
+
AVATAR_SIZE_CLASSES = {
|
17
|
+
xxsmall: "h-5 w-5",
|
18
|
+
xsmall: "h-6 w-6",
|
19
|
+
small: "h-8 w-8",
|
20
|
+
medium: "h-10 w-10",
|
21
|
+
large: "h-12 w-12",
|
22
|
+
xlarge: "h-16 w-16",
|
23
|
+
xxlarge: "h-24 w-24"
|
24
|
+
}
|
25
|
+
|
26
|
+
# Dimensioni testo placeholder
|
27
|
+
AVATAR_PLACEHOLDER_SIZE_CLASSES = {
|
28
|
+
xxsmall: "text-xs",
|
29
|
+
xsmall: "text-xs",
|
30
|
+
small: "text-sm",
|
31
|
+
medium: "text-base",
|
32
|
+
large: "text-lg",
|
33
|
+
xlarge: "text-xl",
|
34
|
+
xxlarge: "text-2xl"
|
35
|
+
}
|
36
|
+
|
37
|
+
# Forme con classi Tailwind dirette
|
38
|
+
AVATAR_SHAPE_CLASSES = {
|
39
|
+
circle: "rounded-full",
|
40
|
+
square: "rounded-none",
|
41
|
+
rounded: "rounded-lg"
|
42
|
+
}
|
43
|
+
|
44
|
+
# Temi placeholder con classi Tailwind dirette
|
45
|
+
AVATAR_PLACEHOLDER_THEME_CLASSES = {
|
46
|
+
default: "bg-black text-white",
|
47
|
+
white: "bg-white text-black border border-gray-300",
|
48
|
+
red: "bg-red-500 text-white",
|
49
|
+
rose: "bg-rose-500 text-white",
|
50
|
+
orange: "bg-orange-500 text-white",
|
51
|
+
green: "bg-green-500 text-white",
|
52
|
+
blue: "bg-blue-500 text-white",
|
53
|
+
yellow: "bg-yellow-500 text-black",
|
54
|
+
violet: "bg-violet-500 text-white"
|
55
|
+
}
|
56
|
+
|
57
|
+
# Stati online con classi Tailwind dirette
|
58
|
+
AVATAR_STATUS_THEME_CLASSES = {
|
59
|
+
online: "bg-green-400",
|
60
|
+
offline: "bg-gray-400",
|
61
|
+
busy: "bg-red-400",
|
62
|
+
away: "bg-yellow-400"
|
63
|
+
}
|
64
|
+
|
65
|
+
# Dimensioni indicatore stato
|
66
|
+
AVATAR_STATUS_SIZE_CLASSES = {
|
67
|
+
xxsmall: "h-1 w-1",
|
68
|
+
xsmall: "h-1.5 w-1.5",
|
69
|
+
small: "h-2 w-2",
|
70
|
+
medium: "h-2.5 w-2.5",
|
71
|
+
large: "h-3 w-3",
|
72
|
+
xlarge: "h-3.5 w-3.5",
|
73
|
+
xxlarge: "h-4 w-4"
|
74
|
+
}
|
75
|
+
|
76
|
+
# Posizioni dell'indicatore di stato
|
77
|
+
AVATAR_STATUS_POSITION_CLASSES = {
|
78
|
+
bottom_right: "bottom-0 right-0",
|
79
|
+
bottom_left: "bottom-0 left-0",
|
80
|
+
top_right: "top-0 right-0",
|
81
|
+
top_left: "top-0 left-0"
|
82
|
+
}
|
83
|
+
|
84
|
+
# Stili disponibili (mantenuto per compatibilità)
|
85
|
+
AVATAR_STYLE_CLASSES = {
|
86
|
+
filled: "",
|
87
|
+
outline: "border-2 border-gray-300",
|
88
|
+
light: "opacity-75"
|
89
|
+
}
|
90
|
+
|
91
|
+
def initialize(
|
92
|
+
name: nil,
|
93
|
+
src: nil,
|
94
|
+
size: :medium,
|
95
|
+
shape: :circle,
|
96
|
+
status: nil,
|
97
|
+
status_position: :bottom_right,
|
98
|
+
theme: :white,
|
99
|
+
style: :filled,
|
100
|
+
classes: nil,
|
101
|
+
id: nil,
|
102
|
+
**html_options
|
103
|
+
)
|
104
|
+
@name = name
|
105
|
+
@src = src
|
106
|
+
@size = size.to_sym
|
107
|
+
@shape = shape.to_sym
|
108
|
+
@status = status.present? ? status.to_sym : nil
|
109
|
+
@status_position = status_position.to_sym
|
110
|
+
@theme = theme.to_sym
|
111
|
+
@style = style.to_sym
|
112
|
+
@classes = classes
|
113
|
+
@id = id
|
114
|
+
@html_options = html_options
|
115
|
+
|
116
|
+
validate_params
|
117
|
+
end
|
118
|
+
|
119
|
+
# Combina tutte le classi per il container
|
120
|
+
def combined_classes
|
121
|
+
[
|
122
|
+
AVATAR_BASE_CLASSES,
|
123
|
+
get_size_class,
|
124
|
+
get_shape_class,
|
125
|
+
get_style_class,
|
126
|
+
@classes,
|
127
|
+
@html_options[:class]
|
128
|
+
].compact.join(" ")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Classi per il placeholder
|
132
|
+
def placeholder_classes
|
133
|
+
[
|
134
|
+
AVATAR_PLACEHOLDER_BASE_CLASSES,
|
135
|
+
get_placeholder_theme_class,
|
136
|
+
get_placeholder_size_class,
|
137
|
+
get_shape_class
|
138
|
+
].compact.join(" ")
|
139
|
+
end
|
140
|
+
|
141
|
+
# Classi per l'immagine
|
142
|
+
def img_classes
|
143
|
+
[
|
144
|
+
AVATAR_IMG_CLASSES,
|
145
|
+
get_shape_class
|
146
|
+
].compact.join(" ")
|
147
|
+
end
|
148
|
+
|
149
|
+
# Classi per l'indicatore di stato
|
150
|
+
def status_indicator_classes
|
151
|
+
[
|
152
|
+
AVATAR_STATUS_BASE_CLASSES,
|
153
|
+
get_status_theme_class,
|
154
|
+
get_status_size_class,
|
155
|
+
get_status_position_class
|
156
|
+
].compact.join(" ")
|
157
|
+
end
|
158
|
+
|
159
|
+
def get_size_class
|
160
|
+
AVATAR_SIZE_CLASSES[@size] || AVATAR_SIZE_CLASSES[:medium]
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_shape_class
|
164
|
+
AVATAR_SHAPE_CLASSES[@shape] || AVATAR_SHAPE_CLASSES[:circle]
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_style_class
|
168
|
+
AVATAR_STYLE_CLASSES[@style] || AVATAR_STYLE_CLASSES[:filled]
|
169
|
+
end
|
170
|
+
|
171
|
+
def get_placeholder_theme_class
|
172
|
+
AVATAR_PLACEHOLDER_THEME_CLASSES[@theme] || AVATAR_PLACEHOLDER_THEME_CLASSES[:white]
|
173
|
+
end
|
174
|
+
|
175
|
+
def get_placeholder_size_class
|
176
|
+
AVATAR_PLACEHOLDER_SIZE_CLASSES[@size] || AVATAR_PLACEHOLDER_SIZE_CLASSES[:medium]
|
177
|
+
end
|
178
|
+
|
179
|
+
def get_status_theme_class
|
180
|
+
AVATAR_STATUS_THEME_CLASSES[@status] || ""
|
181
|
+
end
|
182
|
+
|
183
|
+
def get_status_size_class
|
184
|
+
AVATAR_STATUS_SIZE_CLASSES[@size] || AVATAR_STATUS_SIZE_CLASSES[:medium]
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_status_position_class
|
188
|
+
AVATAR_STATUS_POSITION_CLASSES[@status_position] || AVATAR_STATUS_POSITION_CLASSES[:bottom_right]
|
189
|
+
end
|
190
|
+
|
191
|
+
# Restituisce gli attributi per l'avatar
|
192
|
+
def avatar_attributes
|
193
|
+
attrs = {
|
194
|
+
class: combined_classes,
|
195
|
+
id: @id
|
196
|
+
}
|
197
|
+
|
198
|
+
# Aggiungi altri attributi HTML se presenti
|
199
|
+
@html_options.except(:class).each do |key, value|
|
200
|
+
attrs[key] = value
|
201
|
+
end
|
202
|
+
|
203
|
+
attrs
|
204
|
+
end
|
205
|
+
|
206
|
+
# Determina se mostrare l'indicatore di stato
|
207
|
+
def show_status?
|
208
|
+
@status.present? && AVATAR_STATUS_THEME_CLASSES.key?(@status)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Ottiene le iniziali dal nome
|
212
|
+
def initials
|
213
|
+
return "" unless @name.present?
|
214
|
+
|
215
|
+
words = @name.strip.split(/\s+/)
|
216
|
+
if words.size >= 2
|
217
|
+
"#{words[0][0]}#{words[1][0]}".upcase
|
218
|
+
else
|
219
|
+
@name[0..1].upcase
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Determina se mostrare l'immagine
|
224
|
+
def show_image?
|
225
|
+
@src.present?
|
226
|
+
end
|
227
|
+
|
228
|
+
# Ottiene le dimensioni dell'avatar in pixel (per attributi width/height img)
|
229
|
+
def pixel_size
|
230
|
+
case @size
|
231
|
+
when :xxsmall
|
232
|
+
20
|
233
|
+
when :xsmall
|
234
|
+
24
|
235
|
+
when :small
|
236
|
+
32
|
237
|
+
when :medium
|
238
|
+
40
|
239
|
+
when :large
|
240
|
+
48
|
241
|
+
when :xlarge
|
242
|
+
64
|
243
|
+
when :xxlarge
|
244
|
+
96
|
245
|
+
else
|
246
|
+
40
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
private
|
251
|
+
|
252
|
+
def validate_params
|
253
|
+
validate_size
|
254
|
+
validate_shape
|
255
|
+
validate_theme
|
256
|
+
validate_style
|
257
|
+
validate_status
|
258
|
+
validate_status_position
|
259
|
+
end
|
260
|
+
|
261
|
+
def validate_size
|
262
|
+
unless AVATAR_SIZE_CLASSES.keys.include?(@size)
|
263
|
+
raise ArgumentError, "La dimensione deve essere una tra: #{AVATAR_SIZE_CLASSES.keys.join(', ')}"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def validate_shape
|
268
|
+
unless AVATAR_SHAPE_CLASSES.keys.include?(@shape)
|
269
|
+
raise ArgumentError, "La forma deve essere una tra: #{AVATAR_SHAPE_CLASSES.keys.join(', ')}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def validate_theme
|
274
|
+
unless AVATAR_PLACEHOLDER_THEME_CLASSES.keys.include?(@theme)
|
275
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{AVATAR_PLACEHOLDER_THEME_CLASSES.keys.join(', ')}"
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def validate_style
|
280
|
+
unless AVATAR_STYLE_CLASSES.keys.include?(@style)
|
281
|
+
raise ArgumentError, "Lo stile deve essere uno tra: #{AVATAR_STYLE_CLASSES.keys.join(', ')}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def validate_status
|
286
|
+
return if @status.nil?
|
287
|
+
|
288
|
+
unless AVATAR_STATUS_THEME_CLASSES.keys.include?(@status)
|
289
|
+
raise ArgumentError, "Lo stato deve essere uno tra: #{AVATAR_STATUS_THEME_CLASSES.keys.join(', ')}"
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def validate_status_position
|
294
|
+
unless AVATAR_STATUS_POSITION_CLASSES.keys.include?(@status_position)
|
295
|
+
raise ArgumentError, "La posizione dello stato deve essere una tra: #{AVATAR_STATUS_POSITION_CLASSES.keys.join(', ')}"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<span <%= tag.attributes(badge_attributes) %>>
|
2
|
+
<% if @variant == :dot %>
|
3
|
+
<span class="<%= dot_classes %>"></span>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<% if @icon && @icon_position == :left %>
|
7
|
+
<span class="<%= icon_classes %>">
|
8
|
+
<%= render_icon(@icon) %>
|
9
|
+
</span>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% if @label.present? %>
|
13
|
+
<span class="<%= text_classes %>"><%= @label %></span>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<% if @icon && @icon_position == :right %>
|
17
|
+
<span class="<%= icon_classes %>">
|
18
|
+
<%= render_icon(@icon) %>
|
19
|
+
</span>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<%= content %>
|
23
|
+
</span>
|