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,10 @@
|
|
1
|
+
<%# Template per il divider %>
|
2
|
+
<% if show_label? %>
|
3
|
+
<%= tag.div(**divider_attributes) do %>
|
4
|
+
<div class="<%= label_line_classes %>"></div>
|
5
|
+
<span class="<%= label_classes %>"><%= @label %></span>
|
6
|
+
<div class="<%= label_line_classes %>"></div>
|
7
|
+
<% end %>
|
8
|
+
<% else %>
|
9
|
+
<%= tag.div(**divider_attributes) %>
|
10
|
+
<% end %>
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Divider
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
attr_reader :theme, :orientation, :style, :size, :label, :height, :classes
|
6
|
+
|
7
|
+
# Classi base sempre presenti
|
8
|
+
DIVIDER_BASE_CLASSES = "my-4"
|
9
|
+
|
10
|
+
# Temi con classi Tailwind dirette - LOGICA CORRETTA
|
11
|
+
DIVIDER_THEME_CLASSES = {
|
12
|
+
default: "border-white", # Bordo bianco (per sfondi scuri)
|
13
|
+
white: "border-gray-300", # Bordo grigio (per sfondi chiari)
|
14
|
+
red: "border-red-500",
|
15
|
+
rose: "border-rose-500",
|
16
|
+
orange: "border-orange-500",
|
17
|
+
green: "border-green-500",
|
18
|
+
blue: "border-blue-500",
|
19
|
+
yellow: "border-yellow-500",
|
20
|
+
violet: "border-violet-500"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Orientamento con classi Tailwind dirette
|
24
|
+
DIVIDER_ORIENTATION_CLASSES = {
|
25
|
+
horizontal: "w-full border-t",
|
26
|
+
vertical: "h-full border-l"
|
27
|
+
}
|
28
|
+
|
29
|
+
# Stili di linea con classi Tailwind dirette
|
30
|
+
DIVIDER_STYLE_CLASSES = {
|
31
|
+
solid: "border-solid",
|
32
|
+
dashed: "border-dashed",
|
33
|
+
dotted: "border-dotted",
|
34
|
+
double: "border-double"
|
35
|
+
}
|
36
|
+
|
37
|
+
# Dimensioni con classi Tailwind dirette
|
38
|
+
DIVIDER_SIZE_CLASSES = {
|
39
|
+
thin: {
|
40
|
+
horizontal: "border-t",
|
41
|
+
vertical: "border-l"
|
42
|
+
},
|
43
|
+
medium: {
|
44
|
+
horizontal: "border-t-2",
|
45
|
+
vertical: "border-l-2"
|
46
|
+
},
|
47
|
+
thick: {
|
48
|
+
horizontal: "border-t-4",
|
49
|
+
vertical: "border-l-4"
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
# Classi per label con classi Tailwind dirette - LOGICA CORRETTA
|
54
|
+
DIVIDER_LABEL_THEME_CLASSES = {
|
55
|
+
default: "text-white bg-transparent px-3", # Testo bianco trasparente (per sfondi scuri)
|
56
|
+
white: "text-gray-900 bg-white px-3", # Testo nero su bianco (per sfondi chiari)
|
57
|
+
red: "text-red-500 bg-white px-3",
|
58
|
+
rose: "text-rose-500 bg-white px-3",
|
59
|
+
orange: "text-orange-500 bg-white px-3",
|
60
|
+
green: "text-green-500 bg-white px-3",
|
61
|
+
blue: "text-blue-500 bg-white px-3",
|
62
|
+
yellow: "text-yellow-600 bg-white px-3",
|
63
|
+
violet: "text-violet-500 bg-white px-3"
|
64
|
+
}
|
65
|
+
|
66
|
+
# @param theme [Symbol] tema del divider (:default, :white, etc.)
|
67
|
+
# @param orientation [Symbol] orientamento del divider (:horizontal, :vertical)
|
68
|
+
# @param style [Symbol] stile della linea (:solid, :dashed, :dotted, :double)
|
69
|
+
# @param size [Symbol] dimensione della linea (:thin, :medium, :thick)
|
70
|
+
# @param label [String] testo opzionale da mostrare al centro del divider
|
71
|
+
# @param height [String] altezza per divider verticale (es. "100px", "100%")
|
72
|
+
# @param classes [String] classi CSS aggiuntive
|
73
|
+
# @param html_options [Hash] opzioni HTML per il container
|
74
|
+
def initialize(
|
75
|
+
theme: :white,
|
76
|
+
orientation: :horizontal,
|
77
|
+
style: :solid,
|
78
|
+
size: :medium,
|
79
|
+
label: nil,
|
80
|
+
height: nil,
|
81
|
+
classes: nil,
|
82
|
+
**html_options
|
83
|
+
)
|
84
|
+
@theme = theme.to_sym
|
85
|
+
@orientation = orientation.to_sym
|
86
|
+
@style = style.to_sym
|
87
|
+
@size = size.to_sym
|
88
|
+
@label = label
|
89
|
+
@height = height
|
90
|
+
@classes = classes
|
91
|
+
@html_options = html_options
|
92
|
+
|
93
|
+
validate_params
|
94
|
+
end
|
95
|
+
|
96
|
+
# Combina tutte le classi per il container
|
97
|
+
def combined_classes
|
98
|
+
base_classes = []
|
99
|
+
|
100
|
+
if @label.present? && @orientation == :horizontal
|
101
|
+
# Per divider con label orizzontale: flex layout
|
102
|
+
base_classes = [
|
103
|
+
"flex items-center text-center",
|
104
|
+
get_theme_class,
|
105
|
+
get_style_class
|
106
|
+
]
|
107
|
+
else
|
108
|
+
# Per divider normale
|
109
|
+
base_classes = [
|
110
|
+
DIVIDER_BASE_CLASSES,
|
111
|
+
get_orientation_class,
|
112
|
+
get_theme_class,
|
113
|
+
get_style_class,
|
114
|
+
get_size_class
|
115
|
+
]
|
116
|
+
end
|
117
|
+
|
118
|
+
[ *base_classes, @classes, @html_options[:class] ].compact.join(" ")
|
119
|
+
end
|
120
|
+
|
121
|
+
# Classi per il label
|
122
|
+
def label_classes
|
123
|
+
return "" unless @label.present?
|
124
|
+
|
125
|
+
[
|
126
|
+
"relative z-10 text-sm font-medium",
|
127
|
+
get_label_theme_class
|
128
|
+
].compact.join(" ")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Classi per le linee before/after quando c'è un label
|
132
|
+
def label_line_classes
|
133
|
+
return "" unless @label.present? && @orientation == :horizontal
|
134
|
+
|
135
|
+
[
|
136
|
+
"flex-1 h-px",
|
137
|
+
get_theme_class,
|
138
|
+
get_style_class
|
139
|
+
].compact.join(" ")
|
140
|
+
end
|
141
|
+
|
142
|
+
# Genera gli attributi di stile inline necessari
|
143
|
+
def inline_styles
|
144
|
+
return nil unless @orientation == :vertical && @height.present?
|
145
|
+
"height: #{@height};"
|
146
|
+
end
|
147
|
+
|
148
|
+
# Restituisce gli attributi per il divider
|
149
|
+
def divider_attributes
|
150
|
+
attrs = {
|
151
|
+
class: combined_classes
|
152
|
+
}
|
153
|
+
|
154
|
+
# Aggiungi stile inline se presente
|
155
|
+
attrs[:style] = inline_styles if inline_styles.present?
|
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
|
+
# Determina se mostrare il label
|
166
|
+
def show_label?
|
167
|
+
@label.present? && @orientation == :horizontal
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def get_theme_class
|
173
|
+
DIVIDER_THEME_CLASSES[@theme] || DIVIDER_THEME_CLASSES[:white]
|
174
|
+
end
|
175
|
+
|
176
|
+
def get_orientation_class
|
177
|
+
DIVIDER_ORIENTATION_CLASSES[@orientation] || DIVIDER_ORIENTATION_CLASSES[:horizontal]
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_style_class
|
181
|
+
DIVIDER_STYLE_CLASSES[@style] || DIVIDER_STYLE_CLASSES[:solid]
|
182
|
+
end
|
183
|
+
|
184
|
+
def get_size_class
|
185
|
+
size_map = DIVIDER_SIZE_CLASSES[@size] || DIVIDER_SIZE_CLASSES[:medium]
|
186
|
+
size_map[@orientation] || size_map[:horizontal]
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_label_theme_class
|
190
|
+
DIVIDER_LABEL_THEME_CLASSES[@theme] || DIVIDER_LABEL_THEME_CLASSES[:white]
|
191
|
+
end
|
192
|
+
|
193
|
+
def validate_params
|
194
|
+
validate_theme
|
195
|
+
validate_orientation
|
196
|
+
validate_style
|
197
|
+
validate_size
|
198
|
+
end
|
199
|
+
|
200
|
+
def validate_theme
|
201
|
+
unless DIVIDER_THEME_CLASSES.keys.include?(@theme)
|
202
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{DIVIDER_THEME_CLASSES.keys.join(', ')}"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def validate_orientation
|
207
|
+
unless DIVIDER_ORIENTATION_CLASSES.keys.include?(@orientation)
|
208
|
+
raise ArgumentError, "L'orientamento deve essere uno tra: #{DIVIDER_ORIENTATION_CLASSES.keys.join(', ')}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def validate_style
|
213
|
+
unless DIVIDER_STYLE_CLASSES.keys.include?(@style)
|
214
|
+
raise ArgumentError, "Lo stile deve essere uno tra: #{DIVIDER_STYLE_CLASSES.keys.join(', ')}"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def validate_size
|
219
|
+
unless DIVIDER_SIZE_CLASSES.keys.include?(@size)
|
220
|
+
raise ArgumentError, "La dimensione deve essere una tra: #{DIVIDER_SIZE_CLASSES.keys.join(', ')}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<%# Form field component template %>
|
2
|
+
<div class="<%= BASE_CLASSES %>">
|
3
|
+
<% if label.present? %>
|
4
|
+
<label for="<%= id %>" class="<%= LABEL_CLASSES %>">
|
5
|
+
<%= label %>
|
6
|
+
<% if required %>
|
7
|
+
<span class="<%= REQUIRED_CLASSES %>">*</span>
|
8
|
+
<% end %>
|
9
|
+
</label>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<div class="mt-1">
|
13
|
+
<%= content %>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<% if error.present? %>
|
17
|
+
<div class="<%= ERROR_CLASSES %>">
|
18
|
+
<%= error %>
|
19
|
+
</div>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<% if help_text.present? %>
|
23
|
+
<div class="<%= HELP_TEXT_CLASSES %>">
|
24
|
+
<%= help_text %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BetterUi
|
4
|
+
module General
|
5
|
+
module Field
|
6
|
+
class Component < ViewComponent::Base
|
7
|
+
attr_reader :label, :name, :required, :error, :help_text, :id
|
8
|
+
|
9
|
+
renders_one :input
|
10
|
+
|
11
|
+
BASE_CLASSES = "flex flex-col space-y-2"
|
12
|
+
LABEL_CLASSES = "text-sm font-medium text-gray-700"
|
13
|
+
REQUIRED_CLASSES = "text-red-500 ml-1"
|
14
|
+
ERROR_CLASSES = "text-sm text-red-600 mt-1"
|
15
|
+
HELP_TEXT_CLASSES = "text-sm text-gray-500 mt-1"
|
16
|
+
|
17
|
+
def initialize(label:, name:, required: false, error: nil, help_text: nil, id: nil)
|
18
|
+
@label = label
|
19
|
+
@name = name
|
20
|
+
@required = required
|
21
|
+
@error = error
|
22
|
+
@help_text = help_text
|
23
|
+
@id = id
|
24
|
+
super()
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def field_classes
|
30
|
+
classes = [BASE_CLASSES]
|
31
|
+
classes << ERROR_CLASSES if @error.present?
|
32
|
+
classes.join(" ")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<%# Template per il heading %>
|
2
|
+
<div class="<%= container_classes %>">
|
3
|
+
<%= tag.public_send(heading_tag, **heading_attributes) do %>
|
4
|
+
<% if show_icon? %>
|
5
|
+
<span class="<%= icon_classes %>">
|
6
|
+
<%= render BetterUi::General::IconComponent.new(name: @icon) %>
|
7
|
+
</span>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<span><%= content %></span>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<% if show_subtitle? %>
|
14
|
+
<div class="<%= subtitle_classes %>">
|
15
|
+
<%= @subtitle %>
|
16
|
+
</div>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<% if show_divider? %>
|
20
|
+
<div class="<%= divider_classes %>"></div>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
@@ -0,0 +1,257 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Heading
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
attr_reader :level, :theme, :align, :size, :style, :icon, :subtitle, :with_divider
|
6
|
+
|
7
|
+
# Classi base sempre presenti
|
8
|
+
HEADING_BASE_CLASSES = "font-bold leading-tight"
|
9
|
+
|
10
|
+
# Temi con classi Tailwind dirette - LOGICA CORRETTA
|
11
|
+
HEADING_THEME_CLASSES = {
|
12
|
+
default: "text-white", # Testo bianco (per sfondi scuri)
|
13
|
+
white: "text-gray-900", # Testo nero (per sfondi chiari)
|
14
|
+
red: "text-red-500",
|
15
|
+
rose: "text-rose-500",
|
16
|
+
orange: "text-orange-500",
|
17
|
+
green: "text-green-500",
|
18
|
+
blue: "text-blue-500",
|
19
|
+
yellow: "text-yellow-600",
|
20
|
+
violet: "text-violet-500",
|
21
|
+
purple: "text-purple-500"
|
22
|
+
}
|
23
|
+
|
24
|
+
# Allineamenti con classi Tailwind dirette
|
25
|
+
HEADING_ALIGN_CLASSES = {
|
26
|
+
left: "text-left",
|
27
|
+
center: "text-center",
|
28
|
+
right: "text-right"
|
29
|
+
}
|
30
|
+
|
31
|
+
# Dimensioni base (verranno combinate con level)
|
32
|
+
HEADING_SIZE_CLASSES = {
|
33
|
+
small: {
|
34
|
+
1 => "text-2xl sm:text-3xl",
|
35
|
+
2 => "text-xl sm:text-2xl",
|
36
|
+
3 => "text-lg sm:text-xl",
|
37
|
+
4 => "text-base sm:text-lg",
|
38
|
+
5 => "text-sm sm:text-base",
|
39
|
+
6 => "text-xs sm:text-sm"
|
40
|
+
},
|
41
|
+
medium: {
|
42
|
+
1 => "text-3xl sm:text-4xl",
|
43
|
+
2 => "text-2xl sm:text-3xl",
|
44
|
+
3 => "text-xl sm:text-2xl",
|
45
|
+
4 => "text-lg sm:text-xl",
|
46
|
+
5 => "text-base sm:text-lg",
|
47
|
+
6 => "text-sm sm:text-base"
|
48
|
+
},
|
49
|
+
large: {
|
50
|
+
1 => "text-4xl sm:text-5xl",
|
51
|
+
2 => "text-3xl sm:text-4xl",
|
52
|
+
3 => "text-2xl sm:text-3xl",
|
53
|
+
4 => "text-xl sm:text-2xl",
|
54
|
+
5 => "text-lg sm:text-xl",
|
55
|
+
6 => "text-base sm:text-lg"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
# Stili con classi Tailwind dirette
|
60
|
+
HEADING_STYLE_CLASSES = {
|
61
|
+
normal: "",
|
62
|
+
bold: "font-extrabold",
|
63
|
+
italic: "italic",
|
64
|
+
underline: "underline"
|
65
|
+
}
|
66
|
+
|
67
|
+
# Temi per subtitle - LOGICA CORRETTA
|
68
|
+
HEADING_SUBTITLE_THEME_CLASSES = {
|
69
|
+
default: "text-gray-300", # Testo grigio chiaro (per sfondi scuri)
|
70
|
+
white: "text-gray-600", # Testo grigio scuro (per sfondi chiari)
|
71
|
+
red: "text-red-400",
|
72
|
+
rose: "text-rose-400",
|
73
|
+
orange: "text-orange-400",
|
74
|
+
green: "text-green-400",
|
75
|
+
blue: "text-blue-400",
|
76
|
+
yellow: "text-yellow-500",
|
77
|
+
violet: "text-violet-400"
|
78
|
+
}
|
79
|
+
|
80
|
+
# Temi per divider - LOGICA CORRETTA
|
81
|
+
HEADING_DIVIDER_THEME_CLASSES = {
|
82
|
+
default: "border-gray-700", # Bordo grigio scuro (per sfondi scuri)
|
83
|
+
white: "border-gray-200", # Bordo grigio chiaro (per sfondi chiari)
|
84
|
+
red: "border-red-200",
|
85
|
+
rose: "border-rose-200",
|
86
|
+
orange: "border-orange-200",
|
87
|
+
green: "border-green-200",
|
88
|
+
blue: "border-blue-200",
|
89
|
+
yellow: "border-yellow-200",
|
90
|
+
violet: "border-violet-200"
|
91
|
+
}
|
92
|
+
|
93
|
+
# @param level [Integer] livello del heading (1-6)
|
94
|
+
# @param theme [Symbol] tema del colore (:default, :white, etc.)
|
95
|
+
# @param align [Symbol] allineamento (:left, :center, :right)
|
96
|
+
# @param size [Symbol] dimensione (:small, :medium, :large)
|
97
|
+
# @param style [Symbol] stile (:normal, :bold, :italic, :underline)
|
98
|
+
# @param icon [String] icona opzionale
|
99
|
+
# @param subtitle [String] sottotitolo opzionale
|
100
|
+
# @param with_divider [Boolean] mostra linea divisoria
|
101
|
+
# @param html_options [Hash] opzioni HTML per il container
|
102
|
+
def initialize(
|
103
|
+
level: 2,
|
104
|
+
theme: :white,
|
105
|
+
align: :left,
|
106
|
+
size: :medium,
|
107
|
+
style: :normal,
|
108
|
+
icon: nil,
|
109
|
+
subtitle: nil,
|
110
|
+
with_divider: false,
|
111
|
+
**html_options
|
112
|
+
)
|
113
|
+
@level = level.to_i.clamp(1, 6)
|
114
|
+
@theme = theme.to_sym
|
115
|
+
@align = align.to_sym
|
116
|
+
@size = size.to_sym
|
117
|
+
@style = style.to_sym
|
118
|
+
@icon = icon
|
119
|
+
@subtitle = subtitle
|
120
|
+
@with_divider = with_divider
|
121
|
+
@html_options = html_options
|
122
|
+
|
123
|
+
validate_params
|
124
|
+
end
|
125
|
+
|
126
|
+
# Combina tutte le classi per il heading
|
127
|
+
def heading_classes
|
128
|
+
[
|
129
|
+
HEADING_BASE_CLASSES,
|
130
|
+
get_theme_class,
|
131
|
+
get_align_class,
|
132
|
+
get_size_class,
|
133
|
+
get_style_class,
|
134
|
+
@html_options[:class]
|
135
|
+
].compact.join(" ")
|
136
|
+
end
|
137
|
+
|
138
|
+
# Classi per il container principale
|
139
|
+
def container_classes
|
140
|
+
"mb-4"
|
141
|
+
end
|
142
|
+
|
143
|
+
# Classi per il subtitle
|
144
|
+
def subtitle_classes
|
145
|
+
return "" unless @subtitle.present?
|
146
|
+
|
147
|
+
[
|
148
|
+
"mt-1 text-sm",
|
149
|
+
get_subtitle_theme_class,
|
150
|
+
get_align_class
|
151
|
+
].compact.join(" ")
|
152
|
+
end
|
153
|
+
|
154
|
+
# Classi per il divider
|
155
|
+
def divider_classes
|
156
|
+
return "" unless @with_divider
|
157
|
+
|
158
|
+
[
|
159
|
+
"mt-2 border-t",
|
160
|
+
get_divider_theme_class
|
161
|
+
].compact.join(" ")
|
162
|
+
end
|
163
|
+
|
164
|
+
# Classi per l'icona
|
165
|
+
def icon_classes
|
166
|
+
return "" unless @icon.present?
|
167
|
+
"mr-2 inline-block"
|
168
|
+
end
|
169
|
+
|
170
|
+
# Restituisce gli attributi HTML per il heading
|
171
|
+
def heading_attributes
|
172
|
+
attrs = @html_options.except(:class)
|
173
|
+
attrs[:class] = heading_classes
|
174
|
+
attrs
|
175
|
+
end
|
176
|
+
|
177
|
+
# Tag del heading basato sul level
|
178
|
+
def heading_tag
|
179
|
+
"h#{@level}"
|
180
|
+
end
|
181
|
+
|
182
|
+
# Determina se mostrare l'icona
|
183
|
+
def show_icon?
|
184
|
+
@icon.present?
|
185
|
+
end
|
186
|
+
|
187
|
+
# Determina se mostrare il subtitle
|
188
|
+
def show_subtitle?
|
189
|
+
@subtitle.present?
|
190
|
+
end
|
191
|
+
|
192
|
+
# Determina se mostrare il divider
|
193
|
+
def show_divider?
|
194
|
+
@with_divider
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def get_theme_class
|
200
|
+
HEADING_THEME_CLASSES[@theme] || HEADING_THEME_CLASSES[:white]
|
201
|
+
end
|
202
|
+
|
203
|
+
def get_align_class
|
204
|
+
HEADING_ALIGN_CLASSES[@align] || HEADING_ALIGN_CLASSES[:left]
|
205
|
+
end
|
206
|
+
|
207
|
+
def get_size_class
|
208
|
+
size_map = HEADING_SIZE_CLASSES[@size] || HEADING_SIZE_CLASSES[:medium]
|
209
|
+
size_map[@level] || size_map[2]
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_style_class
|
213
|
+
HEADING_STYLE_CLASSES[@style] || HEADING_STYLE_CLASSES[:normal]
|
214
|
+
end
|
215
|
+
|
216
|
+
def get_subtitle_theme_class
|
217
|
+
HEADING_SUBTITLE_THEME_CLASSES[@theme] || HEADING_SUBTITLE_THEME_CLASSES[:white]
|
218
|
+
end
|
219
|
+
|
220
|
+
def get_divider_theme_class
|
221
|
+
HEADING_DIVIDER_THEME_CLASSES[@theme] || HEADING_DIVIDER_THEME_CLASSES[:white]
|
222
|
+
end
|
223
|
+
|
224
|
+
def validate_params
|
225
|
+
validate_theme
|
226
|
+
validate_align
|
227
|
+
validate_size
|
228
|
+
validate_style
|
229
|
+
end
|
230
|
+
|
231
|
+
def validate_theme
|
232
|
+
unless HEADING_THEME_CLASSES.keys.include?(@theme)
|
233
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{HEADING_THEME_CLASSES.keys.join(', ')}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def validate_align
|
238
|
+
unless HEADING_ALIGN_CLASSES.keys.include?(@align)
|
239
|
+
raise ArgumentError, "L'allineamento deve essere uno tra: #{HEADING_ALIGN_CLASSES.keys.join(', ')}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def validate_size
|
244
|
+
unless HEADING_SIZE_CLASSES.keys.include?(@size)
|
245
|
+
raise ArgumentError, "La dimensione deve essere una tra: #{HEADING_SIZE_CLASSES.keys.join(', ')}"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def validate_style
|
250
|
+
unless HEADING_STYLE_CLASSES.keys.include?(@style)
|
251
|
+
raise ArgumentError, "Lo stile deve essere uno tra: #{HEADING_STYLE_CLASSES.keys.join(', ')}"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|