better_ui 0.1.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +199 -75
- data/app/assets/javascripts/better_ui/controllers/navbar_controller.js +138 -0
- data/app/assets/javascripts/better_ui/controllers/sidebar_controller.js +211 -0
- data/app/assets/javascripts/better_ui/controllers/toast_controller.js +161 -0
- data/app/assets/javascripts/better_ui/index.js +159 -0
- data/app/assets/javascripts/better_ui/toast_manager.js +77 -0
- data/app/assets/stylesheets/better_ui/application.css +25 -351
- data/app/components/better_ui/application/alert_component.html.erb +27 -0
- data/app/components/better_ui/application/alert_component.rb +202 -0
- data/app/components/better_ui/application/card_component.html.erb +24 -0
- data/app/components/better_ui/application/card_component.rb +53 -0
- data/app/components/better_ui/application/card_container_component.html.erb +8 -0
- data/app/components/better_ui/application/card_container_component.rb +14 -0
- data/app/components/better_ui/application/header_component.html.erb +88 -0
- data/app/components/better_ui/application/header_component.rb +188 -0
- data/app/components/better_ui/application/navbar_component.html.erb +294 -0
- data/app/components/better_ui/application/navbar_component.rb +249 -0
- data/app/components/better_ui/application/sidebar_component.html.erb +207 -0
- data/app/components/better_ui/application/sidebar_component.rb +318 -0
- data/app/components/better_ui/application/toast_component.html.erb +35 -0
- data/app/components/better_ui/application/toast_component.rb +223 -0
- data/app/components/better_ui/general/avatar_component.html.erb +19 -0
- data/app/components/better_ui/general/avatar_component.rb +171 -0
- data/app/components/better_ui/general/badge_component.html.erb +19 -0
- data/app/components/better_ui/general/badge_component.rb +123 -0
- data/app/components/better_ui/general/breadcrumb_component.html.erb +15 -0
- data/app/components/better_ui/general/breadcrumb_component.rb +130 -0
- data/app/components/better_ui/general/button_component.html.erb +34 -0
- data/app/components/better_ui/general/button_component.rb +162 -0
- data/app/components/better_ui/general/heading_component.html.erb +25 -0
- data/app/components/better_ui/general/heading_component.rb +148 -0
- data/app/components/better_ui/general/icon_component.html.erb +2 -0
- data/app/components/better_ui/general/icon_component.rb +100 -0
- data/app/components/better_ui/general/link_component.html.erb +17 -0
- data/app/components/better_ui/general/link_component.rb +132 -0
- data/app/components/better_ui/general/panel_component.html.erb +27 -0
- data/app/components/better_ui/general/panel_component.rb +103 -0
- data/app/components/better_ui/general/spinner_component.html.erb +15 -0
- data/app/components/better_ui/general/spinner_component.rb +79 -0
- data/app/components/better_ui/general/table_component.html.erb +73 -0
- data/app/components/better_ui/general/table_component.rb +167 -0
- data/app/components/better_ui/theme_helper.rb +171 -0
- data/app/controllers/better_ui/application_controller.rb +1 -0
- data/app/controllers/better_ui/docs_controller.rb +18 -25
- 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 +6 -1
- data/lib/better_ui/engine.rb +18 -1
- data/lib/better_ui/version.rb +1 -1
- data/lib/better_ui.rb +4 -0
- data/lib/generators/better_ui/stylesheet_generator.rb +96 -0
- data/lib/generators/better_ui/templates/README +56 -0
- data/lib/generators/better_ui/templates/components/_avatar.scss +151 -0
- data/lib/generators/better_ui/templates/components/_badge.scss +142 -0
- data/lib/generators/better_ui/templates/components/_breadcrumb.scss +107 -0
- data/lib/generators/better_ui/templates/components/_button.scss +106 -0
- data/lib/generators/better_ui/templates/components/_card.scss +69 -0
- data/lib/generators/better_ui/templates/components/_heading.scss +180 -0
- data/lib/generators/better_ui/templates/components/_icon.scss +90 -0
- data/lib/generators/better_ui/templates/components/_link.scss +130 -0
- data/lib/generators/better_ui/templates/components/_panel.scss +144 -0
- data/lib/generators/better_ui/templates/components/_spinner.scss +132 -0
- data/lib/generators/better_ui/templates/components/_table.scss +105 -0
- data/lib/generators/better_ui/templates/components/_variables.scss +33 -0
- data/lib/generators/better_ui/templates/components_stylesheet.scss +66 -0
- metadata +135 -10
- data/app/helpers/better_ui/application_helper.rb +0 -183
- data/app/views/better_ui/docs/component.html.erb +0 -365
- data/app/views/better_ui/docs/index.html.erb +0 -100
- data/app/views/better_ui/docs/show.html.erb +0 -60
- data/app/views/layouts/better_ui/application.html.erb +0 -135
@@ -0,0 +1,148 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class HeadingComponent < ViewComponent::Base
|
4
|
+
attr_reader :text, :level, :variant, :size, :align, :classes, :icon, :subtitle, :with_divider
|
5
|
+
|
6
|
+
# Varianti di colore disponibili
|
7
|
+
HEADER_THEME = {
|
8
|
+
default: {
|
9
|
+
heading: "bui-header-default-heading",
|
10
|
+
subtitle: "bui-header-default-subtitle",
|
11
|
+
divider: "bui-header-default-divider"
|
12
|
+
},
|
13
|
+
white: {
|
14
|
+
heading: "bui-header-white-heading",
|
15
|
+
subtitle: "bui-header-white-subtitle",
|
16
|
+
divider: "bui-header-white-divider"
|
17
|
+
},
|
18
|
+
red: {
|
19
|
+
heading: "bui-header-red-heading",
|
20
|
+
subtitle: "bui-header-red-subtitle",
|
21
|
+
divider: "bui-header-red-divider"
|
22
|
+
},
|
23
|
+
rose: {
|
24
|
+
heading: "bui-header-rose-heading",
|
25
|
+
subtitle: "bui-header-rose-subtitle",
|
26
|
+
divider: "bui-header-rose-divider"
|
27
|
+
},
|
28
|
+
orange: {
|
29
|
+
heading: "bui-header-orange-heading",
|
30
|
+
subtitle: "bui-header-orange-subtitle",
|
31
|
+
divider: "bui-header-orange-divider"
|
32
|
+
},
|
33
|
+
green: {
|
34
|
+
heading: "bui-header-green-heading",
|
35
|
+
subtitle: "bui-header-green-subtitle",
|
36
|
+
divider: "bui-header-green-divider"
|
37
|
+
},
|
38
|
+
blue: {
|
39
|
+
heading: "bui-header-blue-heading",
|
40
|
+
subtitle: "bui-header-blue-subtitle",
|
41
|
+
divider: "bui-header-blue-divider"
|
42
|
+
},
|
43
|
+
yellow: {
|
44
|
+
heading: "bui-header-yellow-heading",
|
45
|
+
subtitle: "bui-header-yellow-subtitle",
|
46
|
+
divider: "bui-header-yellow-divider"
|
47
|
+
},
|
48
|
+
violet: {
|
49
|
+
heading: "bui-header-violet-heading",
|
50
|
+
subtitle: "bui-header-violet-subtitle",
|
51
|
+
divider: "bui-header-violet-divider"
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
# Dimensioni disponibili
|
56
|
+
HEADER_SIZES = {
|
57
|
+
small: {
|
58
|
+
heading: "bui-header-small-heading",
|
59
|
+
subtitle: "bui-header-small-subtitle"
|
60
|
+
},
|
61
|
+
medium: {
|
62
|
+
heading: "bui-header-medium-heading",
|
63
|
+
subtitle: "bui-header-medium-subtitle"
|
64
|
+
},
|
65
|
+
large: {
|
66
|
+
heading: "bui-header-large-heading",
|
67
|
+
subtitle: "bui-header-large-subtitle"
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
# Allineamenti disponibili
|
72
|
+
HEADER_ALIGNMENTS = {
|
73
|
+
left: "bui-header-left",
|
74
|
+
center: "bui-header-center",
|
75
|
+
right: "bui-header-right"
|
76
|
+
}
|
77
|
+
|
78
|
+
# Inizializzazione del componente
|
79
|
+
def initialize(
|
80
|
+
text: nil,
|
81
|
+
level: 2,
|
82
|
+
variant: :default,
|
83
|
+
size: :medium,
|
84
|
+
align: :left,
|
85
|
+
classes: nil,
|
86
|
+
icon: nil,
|
87
|
+
subtitle: nil,
|
88
|
+
with_divider: false
|
89
|
+
)
|
90
|
+
@text = text
|
91
|
+
@level = level.to_i.clamp(1, 6)
|
92
|
+
@variant = variant.to_sym
|
93
|
+
@size = size.to_sym
|
94
|
+
@align = align.to_sym
|
95
|
+
@classes = classes
|
96
|
+
@icon = icon
|
97
|
+
@subtitle = subtitle
|
98
|
+
@with_divider = with_divider
|
99
|
+
end
|
100
|
+
|
101
|
+
# Genera le classi per l'heading
|
102
|
+
def heading_classes
|
103
|
+
[
|
104
|
+
HEADER_THEME.fetch(@variant, HEADER_THEME[:default])[:heading],
|
105
|
+
HEADER_SIZES.fetch(@size, HEADER_SIZES[:medium])[:heading],
|
106
|
+
HEADER_ALIGNMENTS.fetch(@align, HEADER_ALIGNMENTS[:left]),
|
107
|
+
"bui-header-heading-base",
|
108
|
+
@classes
|
109
|
+
].compact.join(" ")
|
110
|
+
end
|
111
|
+
|
112
|
+
# Genera le classi per il sottotitolo
|
113
|
+
def subtitle_classes
|
114
|
+
[
|
115
|
+
HEADER_THEME.fetch(@variant, HEADER_THEME[:default])[:subtitle],
|
116
|
+
HEADER_SIZES.fetch(@size, HEADER_SIZES[:medium])[:subtitle],
|
117
|
+
HEADER_ALIGNMENTS.fetch(@align, HEADER_ALIGNMENTS[:left]),
|
118
|
+
"bui-header-subtitle-base"
|
119
|
+
].compact.join(" ")
|
120
|
+
end
|
121
|
+
|
122
|
+
# Genera le classi per il divisore
|
123
|
+
def divider_classes
|
124
|
+
[
|
125
|
+
"bui-header-divider-base",
|
126
|
+
HEADER_THEME.fetch(@variant, HEADER_THEME[:default])[:divider]
|
127
|
+
].compact.join(" ")
|
128
|
+
end
|
129
|
+
|
130
|
+
# Genera le classi per il container
|
131
|
+
def container_classes
|
132
|
+
@with_divider ? "bui-header-container-with-divider" : "bui-header-container-base"
|
133
|
+
end
|
134
|
+
|
135
|
+
# Helper per determinare la dimensione dell'icona in base alla dimensione dell'heading
|
136
|
+
def get_icon_size
|
137
|
+
case @size
|
138
|
+
when :large
|
139
|
+
:medium
|
140
|
+
when :small
|
141
|
+
:xsmall
|
142
|
+
else
|
143
|
+
:small
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class IconComponent < ViewComponent::Base
|
4
|
+
# Dimensioni disponibili
|
5
|
+
ICON_SIZES = {
|
6
|
+
xsmall: "bui-icon-xsmall",
|
7
|
+
small: "bui-icon-small",
|
8
|
+
medium: "bui-icon-medium",
|
9
|
+
large: "bui-icon-large",
|
10
|
+
xlarge: "bui-icon-xlarge"
|
11
|
+
}
|
12
|
+
|
13
|
+
# Stili disponibili
|
14
|
+
ICON_STYLES = {
|
15
|
+
solid: "bui-icon-solid",
|
16
|
+
regular: "bui-icon-regular",
|
17
|
+
light: "bui-icon-light",
|
18
|
+
brands: "bui-icon-brands",
|
19
|
+
duotone: "bui-icon-duotone"
|
20
|
+
}
|
21
|
+
|
22
|
+
# Inizializzazione del componente
|
23
|
+
def initialize(
|
24
|
+
name:,
|
25
|
+
size: :medium,
|
26
|
+
style: :solid,
|
27
|
+
fixed_width: false,
|
28
|
+
spin: false,
|
29
|
+
pulse: false,
|
30
|
+
border: false,
|
31
|
+
flip: nil,
|
32
|
+
rotation: nil,
|
33
|
+
classes: nil
|
34
|
+
)
|
35
|
+
@name = name.to_s.gsub('_', '-') # Convertiamo da snake_case a kebab-case per Font Awesome
|
36
|
+
@size = size.to_sym
|
37
|
+
@style = style.to_sym
|
38
|
+
@fixed_width = fixed_width
|
39
|
+
@spin = spin
|
40
|
+
@pulse = pulse
|
41
|
+
@border = border
|
42
|
+
@flip = flip
|
43
|
+
@rotation = rotation
|
44
|
+
@classes = classes
|
45
|
+
end
|
46
|
+
|
47
|
+
# Classe CSS per lo stile dell'icona
|
48
|
+
def style_class
|
49
|
+
ICON_STYLES[@style] || ICON_STYLES[:solid]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Classe CSS per la dimensione
|
53
|
+
def size_class
|
54
|
+
ICON_SIZES[@size] || ICON_SIZES[:medium]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Classe per rotazione
|
58
|
+
def rotation_class
|
59
|
+
return "" unless @rotation
|
60
|
+
"bui-icon-rotate-#{@rotation}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Classe per rovesciamento
|
64
|
+
def flip_class
|
65
|
+
return "" unless @flip
|
66
|
+
"bui-icon-flip-#{@flip}"
|
67
|
+
end
|
68
|
+
|
69
|
+
# Classi per animazioni
|
70
|
+
def animation_classes
|
71
|
+
classes = []
|
72
|
+
classes << "bui-icon-spin" if @spin
|
73
|
+
classes << "bui-icon-pulse" if @pulse
|
74
|
+
classes.join(" ")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Classi per caratteristiche aggiuntive
|
78
|
+
def feature_classes
|
79
|
+
classes = []
|
80
|
+
classes << "bui-icon-fw" if @fixed_width
|
81
|
+
classes << "bui-icon-border" if @border
|
82
|
+
classes.join(" ")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Combinazione di tutte le classi
|
86
|
+
def combined_classes
|
87
|
+
[
|
88
|
+
style_class,
|
89
|
+
"fa-#{@name}", # Questa classe deve rimanere specifica di Font Awesome
|
90
|
+
size_class,
|
91
|
+
rotation_class,
|
92
|
+
flip_class,
|
93
|
+
animation_classes,
|
94
|
+
feature_classes,
|
95
|
+
@classes
|
96
|
+
].reject(&:blank?).join(" ")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<% if link? %>
|
2
|
+
<%= link_to href, **link_attributes do %>
|
3
|
+
<% if render_icon %>
|
4
|
+
<span class="bui-link-icon-wrapper"><%= render_icon %></span>
|
5
|
+
<% end %>
|
6
|
+
<span><%= label %></span>
|
7
|
+
<%= content if content.present? %>
|
8
|
+
<% end %>
|
9
|
+
<% else %>
|
10
|
+
<span class="<%= component_classes %>" <%= "aria-current='page'" if active? %>>
|
11
|
+
<% if render_icon %>
|
12
|
+
<span class="bui-link-icon-wrapper"><%= render_icon %></span>
|
13
|
+
<% end %>
|
14
|
+
<span><%= label %></span>
|
15
|
+
<%= content if content.present? %>
|
16
|
+
</span>
|
17
|
+
<% end %>
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class LinkComponent < ViewComponent::Base
|
4
|
+
attr_reader :label, :href, :theme, :icon, :classes, :active, :data, :method, :target
|
5
|
+
|
6
|
+
# Temi di colore disponibili
|
7
|
+
LINK_THEME = {
|
8
|
+
default: {
|
9
|
+
link: "bui-link-default-link",
|
10
|
+
active: "bui-link-default-active",
|
11
|
+
text: "bui-link-default-text"
|
12
|
+
},
|
13
|
+
white: {
|
14
|
+
link: "bui-link-white-link",
|
15
|
+
active: "bui-link-white-active",
|
16
|
+
text: "bui-link-white-text"
|
17
|
+
},
|
18
|
+
red: {
|
19
|
+
link: "bui-link-red-link",
|
20
|
+
active: "bui-link-red-active",
|
21
|
+
text: "bui-link-red-text"
|
22
|
+
},
|
23
|
+
rose: {
|
24
|
+
link: "bui-link-rose-link",
|
25
|
+
active: "bui-link-rose-active",
|
26
|
+
text: "bui-link-rose-text"
|
27
|
+
},
|
28
|
+
orange: {
|
29
|
+
link: "bui-link-orange-link",
|
30
|
+
active: "bui-link-orange-active",
|
31
|
+
text: "bui-link-orange-text"
|
32
|
+
},
|
33
|
+
green: {
|
34
|
+
link: "bui-link-green-link",
|
35
|
+
active: "bui-link-green-active",
|
36
|
+
text: "bui-link-green-text"
|
37
|
+
},
|
38
|
+
blue: {
|
39
|
+
link: "bui-link-blue-link",
|
40
|
+
active: "bui-link-blue-active",
|
41
|
+
text: "bui-link-blue-text"
|
42
|
+
},
|
43
|
+
yellow: {
|
44
|
+
link: "bui-link-yellow-link",
|
45
|
+
active: "bui-link-yellow-active",
|
46
|
+
text: "bui-link-yellow-text"
|
47
|
+
},
|
48
|
+
violet: {
|
49
|
+
link: "bui-link-violet-link",
|
50
|
+
active: "bui-link-violet-active",
|
51
|
+
text: "bui-link-violet-text"
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
# Inizializzazione del componente
|
56
|
+
def initialize(
|
57
|
+
label:,
|
58
|
+
href: nil,
|
59
|
+
theme: :default,
|
60
|
+
icon: nil,
|
61
|
+
classes: nil,
|
62
|
+
active: false,
|
63
|
+
data: {},
|
64
|
+
method: nil,
|
65
|
+
target: nil
|
66
|
+
)
|
67
|
+
@label = label
|
68
|
+
@href = href
|
69
|
+
@theme = theme.to_sym
|
70
|
+
@icon = icon
|
71
|
+
@classes = classes
|
72
|
+
@active = active
|
73
|
+
@data = data || {}
|
74
|
+
@method = method
|
75
|
+
@target = target
|
76
|
+
end
|
77
|
+
|
78
|
+
# Determina se è un link attivo/corrente
|
79
|
+
def active?
|
80
|
+
@active
|
81
|
+
end
|
82
|
+
|
83
|
+
# Determina se è un link o solo testo
|
84
|
+
def link?
|
85
|
+
@href.present?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Genera le classi per il componente
|
89
|
+
def component_classes
|
90
|
+
theme_classes = LINK_THEME.fetch(@theme, LINK_THEME[:default])
|
91
|
+
|
92
|
+
base_classes = ["bui-link-base"]
|
93
|
+
|
94
|
+
if active?
|
95
|
+
base_classes << theme_classes[:active]
|
96
|
+
elsif link?
|
97
|
+
base_classes << theme_classes[:link]
|
98
|
+
else
|
99
|
+
base_classes << theme_classes[:text]
|
100
|
+
end
|
101
|
+
|
102
|
+
base_classes << @classes if @classes.present?
|
103
|
+
|
104
|
+
base_classes.compact.join(" ")
|
105
|
+
end
|
106
|
+
|
107
|
+
# Restituisce gli attributi per il link
|
108
|
+
def link_attributes
|
109
|
+
attrs = {
|
110
|
+
class: component_classes
|
111
|
+
}
|
112
|
+
|
113
|
+
attrs[:data] = @data.merge(turbo_method: @method) if @method.present?
|
114
|
+
attrs[:data] = @data if @data.present? && !@method.present?
|
115
|
+
attrs[:target] = @target if @target.present?
|
116
|
+
|
117
|
+
attrs
|
118
|
+
end
|
119
|
+
|
120
|
+
# Renderizza l'icona
|
121
|
+
def render_icon
|
122
|
+
return nil unless @icon.present?
|
123
|
+
|
124
|
+
if @icon.is_a?(String)
|
125
|
+
render BetterUi::General::IconComponent.new(name: @icon)
|
126
|
+
else
|
127
|
+
@icon # Assumiamo che sia già un componente renderizzato
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="<%= panel_classes %>">
|
2
|
+
<% if @header.present? %>
|
3
|
+
<div class="<%= header_classes %>">
|
4
|
+
<%= raw @header %>
|
5
|
+
</div>
|
6
|
+
<% elsif @title.present? %>
|
7
|
+
<div class="<%= header_classes %>">
|
8
|
+
<div class="<%= title_classes %>"><%= @title %></div>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% if @body.present? %>
|
13
|
+
<div class="<%= body_classes %>">
|
14
|
+
<%= raw @body %>
|
15
|
+
</div>
|
16
|
+
<% elsif content.present? %>
|
17
|
+
<div class="<%= body_classes %>">
|
18
|
+
<%= content %>
|
19
|
+
</div>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<% if @footer.present? %>
|
23
|
+
<div class="<%= footer_classes %>">
|
24
|
+
<%= raw @footer %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class PanelComponent < ViewComponent::Base
|
4
|
+
attr_reader :header, :footer, :body, :title, :padding, :variant, :rounded
|
5
|
+
|
6
|
+
# Opzioni di padding disponibili
|
7
|
+
PANEL_PADDING = {
|
8
|
+
none: 'bui-panel-padding-none',
|
9
|
+
small: 'bui-panel-padding-small',
|
10
|
+
medium: 'bui-panel-padding-medium',
|
11
|
+
large: 'bui-panel-padding-large'
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
# Temi di colore per l'header
|
15
|
+
PANEL_HEADER_THEME = {
|
16
|
+
default: 'bui-panel-default-header',
|
17
|
+
white: 'bui-panel-white-header',
|
18
|
+
red: 'bui-panel-red-header',
|
19
|
+
rose: 'bui-panel-rose-header',
|
20
|
+
orange: 'bui-panel-orange-header',
|
21
|
+
green: 'bui-panel-green-header',
|
22
|
+
blue: 'bui-panel-blue-header',
|
23
|
+
yellow: 'bui-panel-yellow-header',
|
24
|
+
violet: 'bui-panel-violet-header'
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# Temi di colore per il footer
|
28
|
+
PANEL_FOOTER_THEME = {
|
29
|
+
default: 'bui-panel-default-footer',
|
30
|
+
white: 'bui-panel-white-footer',
|
31
|
+
red: 'bui-panel-red-footer',
|
32
|
+
rose: 'bui-panel-rose-footer',
|
33
|
+
orange: 'bui-panel-orange-footer',
|
34
|
+
green: 'bui-panel-green-footer',
|
35
|
+
blue: 'bui-panel-blue-footer',
|
36
|
+
yellow: 'bui-panel-yellow-footer',
|
37
|
+
violet: 'bui-panel-violet-footer'
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
# Opzioni di bordi arrotondati standardizzati
|
41
|
+
PANEL_RADIUS = {
|
42
|
+
none: 'bui-panel-radius-none',
|
43
|
+
small: 'bui-panel-radius-small',
|
44
|
+
medium: 'bui-panel-radius-medium',
|
45
|
+
large: 'bui-panel-radius-large',
|
46
|
+
full: 'bui-panel-radius-full'
|
47
|
+
}.freeze
|
48
|
+
|
49
|
+
def initialize(title: nil, body: nil, header: nil, footer: nil, padding: :medium, variant: :default, rounded: :small)
|
50
|
+
@title = title
|
51
|
+
@body = body
|
52
|
+
@header = header
|
53
|
+
@footer = footer
|
54
|
+
@padding = padding.to_sym
|
55
|
+
@variant = variant.to_sym
|
56
|
+
@rounded = rounded.to_sym
|
57
|
+
end
|
58
|
+
|
59
|
+
def panel_classes
|
60
|
+
[
|
61
|
+
'bui-panel-base',
|
62
|
+
get_border_radius_class
|
63
|
+
].compact.join(' ')
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_border_radius_class
|
67
|
+
PANEL_RADIUS[@rounded] || PANEL_RADIUS[:small]
|
68
|
+
end
|
69
|
+
|
70
|
+
def header_classes
|
71
|
+
[
|
72
|
+
'bui-panel-header',
|
73
|
+
PANEL_HEADER_THEME[@variant] || PANEL_HEADER_THEME[:default],
|
74
|
+
PANEL_PADDING.fetch(@padding, PANEL_PADDING[:medium])
|
75
|
+
].compact.join(' ')
|
76
|
+
end
|
77
|
+
|
78
|
+
def body_classes
|
79
|
+
[
|
80
|
+
'bui-panel-body',
|
81
|
+
'bui-panel-body-content',
|
82
|
+
PANEL_PADDING.fetch(@padding, PANEL_PADDING[:medium])
|
83
|
+
].compact.join(' ')
|
84
|
+
end
|
85
|
+
|
86
|
+
def footer_classes
|
87
|
+
[
|
88
|
+
'bui-panel-footer',
|
89
|
+
PANEL_FOOTER_THEME[@variant] || PANEL_FOOTER_THEME[:default],
|
90
|
+
PANEL_PADDING.fetch(@padding, PANEL_PADDING[:medium])
|
91
|
+
].compact.join(' ')
|
92
|
+
end
|
93
|
+
|
94
|
+
def title_classes
|
95
|
+
'bui-panel-title'
|
96
|
+
end
|
97
|
+
|
98
|
+
def render?
|
99
|
+
@body.present? || @header.present? || @footer.present? || content.present?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div <%= spinner_attributes.to_s.html_safe %>>
|
2
|
+
<div class="bui-spinner-animation"></div>
|
3
|
+
|
4
|
+
<% if @label.present? %>
|
5
|
+
<div class="bui-spinner-label">
|
6
|
+
<%= @label %>
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<% if content.present? %>
|
11
|
+
<div class="bui-spinner-content">
|
12
|
+
<%= content %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
class SpinnerComponent < ViewComponent::Base
|
4
|
+
attr_reader :size, :theme, :fullscreen, :label, :classes, :id
|
5
|
+
|
6
|
+
# Temi di colore disponibili
|
7
|
+
SPINNER_THEME = {
|
8
|
+
default: "bui-spinner-default",
|
9
|
+
white: "bui-spinner-white",
|
10
|
+
red: "bui-spinner-red",
|
11
|
+
rose: "bui-spinner-rose",
|
12
|
+
orange: "bui-spinner-orange",
|
13
|
+
green: "bui-spinner-green",
|
14
|
+
blue: "bui-spinner-blue",
|
15
|
+
yellow: "bui-spinner-yellow",
|
16
|
+
violet: "bui-spinner-violet"
|
17
|
+
}
|
18
|
+
|
19
|
+
# Dimensioni disponibili
|
20
|
+
SPINNER_SIZES = {
|
21
|
+
small: "bui-spinner-small",
|
22
|
+
medium: "bui-spinner-medium",
|
23
|
+
large: "bui-spinner-large"
|
24
|
+
}
|
25
|
+
|
26
|
+
# Stati e comportamenti dello spinner
|
27
|
+
SPINNER_STATES = {
|
28
|
+
fullscreen: "bui-spinner-fullscreen"
|
29
|
+
}
|
30
|
+
|
31
|
+
# Inizializzazione del componente
|
32
|
+
def initialize(
|
33
|
+
size: :medium,
|
34
|
+
theme: :default,
|
35
|
+
fullscreen: false,
|
36
|
+
label: nil,
|
37
|
+
classes: nil,
|
38
|
+
id: nil
|
39
|
+
)
|
40
|
+
@size = size.to_sym
|
41
|
+
@theme = theme.to_sym
|
42
|
+
@fullscreen = fullscreen
|
43
|
+
@label = label
|
44
|
+
@classes = classes
|
45
|
+
@id = id
|
46
|
+
end
|
47
|
+
|
48
|
+
# Combina tutte le classi
|
49
|
+
def combined_classes
|
50
|
+
[
|
51
|
+
"bui-spinner", # Classe base per tutti gli spinner
|
52
|
+
get_spinner_theme_class,
|
53
|
+
get_spinner_size_class,
|
54
|
+
@fullscreen ? SPINNER_STATES[:fullscreen] : "",
|
55
|
+
@classes
|
56
|
+
].compact.join(" ")
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_spinner_theme_class
|
60
|
+
SPINNER_THEME[@theme] || SPINNER_THEME[:default]
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_spinner_size_class
|
64
|
+
SPINNER_SIZES[@size] || SPINNER_SIZES[:medium]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Restituisce gli attributi per lo spinner
|
68
|
+
def spinner_attributes
|
69
|
+
attrs = {
|
70
|
+
class: combined_classes,
|
71
|
+
id: @id,
|
72
|
+
role: "status"
|
73
|
+
}
|
74
|
+
|
75
|
+
attrs
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
<div class="<%= table_container_classes %>">
|
2
|
+
<table class="<%= table_classes %>">
|
3
|
+
<% if caption.present? %>
|
4
|
+
<caption class="<%= caption_classes %>">
|
5
|
+
<%= caption %>
|
6
|
+
</caption>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<thead class="<%= thead_classes %>">
|
10
|
+
<% if header_rows_partial.present? %>
|
11
|
+
<%= render partial: header_rows_partial, locals: {
|
12
|
+
component: self,
|
13
|
+
headers: headers_for_display
|
14
|
+
} %>
|
15
|
+
<% else %>
|
16
|
+
<tr>
|
17
|
+
<% headers_for_display.each do |header| %>
|
18
|
+
<th scope="col" class="<%= th_classes %>">
|
19
|
+
<%= header.to_s.humanize %>
|
20
|
+
</th>
|
21
|
+
<% end %>
|
22
|
+
</tr>
|
23
|
+
<% end %>
|
24
|
+
</thead>
|
25
|
+
|
26
|
+
<tbody class="<%= tbody_classes %>">
|
27
|
+
<% data.each_with_index do |row, index| %>
|
28
|
+
<% if body_row_partial.present? %>
|
29
|
+
<%= render partial: body_row_partial, locals: {
|
30
|
+
component: self,
|
31
|
+
row: row,
|
32
|
+
index: index,
|
33
|
+
headers: headers_for_display
|
34
|
+
} %>
|
35
|
+
<% else %>
|
36
|
+
<tr class="<%= tr_classes(index) %>">
|
37
|
+
<% headers_for_display.each do |header| %>
|
38
|
+
<td class="<%= td_classes %>">
|
39
|
+
<% if row.is_a?(Hash) %>
|
40
|
+
<%= row[header.to_s] || row[header.to_sym] %>
|
41
|
+
<% elsif row.respond_to?(header.to_sym) %>
|
42
|
+
<%= row.send(header.to_sym) %>
|
43
|
+
<% else %>
|
44
|
+
—
|
45
|
+
<% end %>
|
46
|
+
</td>
|
47
|
+
<% end %>
|
48
|
+
</tr>
|
49
|
+
<% end %>
|
50
|
+
<% end %>
|
51
|
+
</tbody>
|
52
|
+
|
53
|
+
<% if footer.present? %>
|
54
|
+
<tfoot class="<%= tfoot_classes %>">
|
55
|
+
<% if footer_rows_partial.present? %>
|
56
|
+
<%= render partial: footer_rows_partial, locals: {
|
57
|
+
component: self,
|
58
|
+
footer: footer,
|
59
|
+
headers: headers_for_display
|
60
|
+
} %>
|
61
|
+
<% else %>
|
62
|
+
<tr>
|
63
|
+
<% footer.each_with_index do |value, index| %>
|
64
|
+
<td class="<%= tf_classes %>">
|
65
|
+
<%= value || "—" %>
|
66
|
+
</td>
|
67
|
+
<% end %>
|
68
|
+
</tr>
|
69
|
+
<% end %>
|
70
|
+
</tfoot>
|
71
|
+
<% end %>
|
72
|
+
</table>
|
73
|
+
</div>
|