better_ui 0.1.0 → 0.2.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/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/dropdown/component.html.erb +14 -0
- data/app/components/better_ui/general/dropdown/component.rb +219 -0
- data/app/components/better_ui/general/dropdown/divider_component.html.erb +1 -0
- data/app/components/better_ui/general/dropdown/divider_component.rb +41 -0
- data/app/components/better_ui/general/dropdown/item_component.html.erb +6 -0
- data/app/components/better_ui/general/dropdown/item_component.rb +118 -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/modal/component.html.erb +42 -0
- data/app/components/better_ui/general/modal/component.rb +165 -0
- data/app/components/better_ui/general/pagination/component.html.erb +85 -0
- data/app/components/better_ui/general/pagination/component.rb +216 -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/tabs/component.html.erb +3 -0
- data/app/components/better_ui/general/tabs/component.rb +102 -0
- data/app/components/better_ui/general/tabs/panel_component.html.erb +3 -0
- data/app/components/better_ui/general/tabs/panel_component.rb +37 -0
- data/app/components/better_ui/general/tabs/tab_component.html.erb +13 -0
- data/app/components/better_ui/general/tabs/tab_component.rb +111 -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 +51 -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/dropdown/divider_helper.rb +32 -0
- data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +79 -0
- data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +62 -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/modal/modal_helper.rb +95 -0
- data/app/helpers/better_ui/general/components/pagination/pagination_helper.rb +82 -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/tabs/panel_helper.rb +62 -0
- data/app/helpers/better_ui/general/components/tabs/tab_helper.rb +55 -0
- data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +62 -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 +155 -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,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BetterUi
|
4
|
+
module General
|
5
|
+
module Tabs
|
6
|
+
class PanelComponent < ViewComponent::Base
|
7
|
+
def initialize(id:, active: false, classes: '', **options)
|
8
|
+
@id = id
|
9
|
+
@active = active
|
10
|
+
@classes = classes
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :id, :active, :classes, :options
|
17
|
+
|
18
|
+
def panel_attributes
|
19
|
+
base_classes = [
|
20
|
+
'focus:outline-none',
|
21
|
+
active ? 'block' : 'hidden',
|
22
|
+
classes
|
23
|
+
].compact.join(' ')
|
24
|
+
|
25
|
+
{
|
26
|
+
class: base_classes,
|
27
|
+
role: 'tabpanel',
|
28
|
+
id: id,
|
29
|
+
'aria-labelledby': "tab-#{id}",
|
30
|
+
'data-bui-tabs-target': 'panel',
|
31
|
+
tabindex: '0'
|
32
|
+
}.merge(options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<button <%= tag.attributes(tab_attributes) %>>
|
2
|
+
<% if has_icon? %>
|
3
|
+
<%= bui_icon(name: icon, classes: 'w-5 h-5') %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<span><%= text %></span>
|
7
|
+
|
8
|
+
<% if has_badge? %>
|
9
|
+
<span class="ml-2 bg-red-100 text-red-800 text-xs font-medium px-2 py-0.5 rounded-full">
|
10
|
+
<%= badge %>
|
11
|
+
</span>
|
12
|
+
<% end %>
|
13
|
+
</button>
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BetterUi
|
4
|
+
module General
|
5
|
+
module Tabs
|
6
|
+
class TabComponent < ViewComponent::Base
|
7
|
+
include BetterUi::General::Components::Icon::IconHelper
|
8
|
+
|
9
|
+
TAB_THEME_ACTIVE = {
|
10
|
+
default: 'bg-white text-gray-900 shadow-sm',
|
11
|
+
blue: 'bg-blue-600 text-white',
|
12
|
+
red: 'bg-red-600 text-white',
|
13
|
+
green: 'bg-green-600 text-white',
|
14
|
+
yellow: 'bg-yellow-600 text-white',
|
15
|
+
violet: 'bg-violet-600 text-white',
|
16
|
+
orange: 'bg-orange-600 text-white',
|
17
|
+
rose: 'bg-rose-600 text-white',
|
18
|
+
white: 'bg-white text-gray-900'
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
TAB_THEME_INACTIVE = {
|
22
|
+
default: 'text-gray-500 hover:text-gray-700',
|
23
|
+
blue: 'text-blue-600 hover:text-blue-700',
|
24
|
+
red: 'text-red-600 hover:text-red-700',
|
25
|
+
green: 'text-green-600 hover:text-green-700',
|
26
|
+
yellow: 'text-yellow-600 hover:text-yellow-700',
|
27
|
+
violet: 'text-violet-600 hover:text-violet-700',
|
28
|
+
orange: 'text-orange-600 hover:text-orange-700',
|
29
|
+
rose: 'text-rose-600 hover:text-rose-700',
|
30
|
+
white: 'text-gray-600 hover:text-gray-700'
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
TAB_SIZE = {
|
34
|
+
small: 'px-3 py-1.5 text-sm',
|
35
|
+
medium: 'px-4 py-2 text-base',
|
36
|
+
large: 'px-6 py-3 text-lg'
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
def initialize(text:, target:, active: false, icon: nil, disabled: false, badge: nil,
|
40
|
+
theme: :default, size: :medium, classes: '', **options)
|
41
|
+
@text = text
|
42
|
+
@target = target
|
43
|
+
@active = active
|
44
|
+
@icon = icon
|
45
|
+
@disabled = disabled
|
46
|
+
@badge = badge
|
47
|
+
@theme = theme
|
48
|
+
@size = size
|
49
|
+
@classes = classes
|
50
|
+
@options = options
|
51
|
+
|
52
|
+
validate_params
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :text, :target, :active, :icon, :disabled, :badge, :theme, :size, :classes, :options
|
58
|
+
|
59
|
+
def validate_params
|
60
|
+
validate_theme
|
61
|
+
validate_size
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_theme
|
65
|
+
return if TAB_THEME_ACTIVE.key?(theme)
|
66
|
+
|
67
|
+
raise ArgumentError, "Invalid theme: #{theme}. Must be one of #{TAB_THEME_ACTIVE.keys}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_size
|
71
|
+
return if TAB_SIZE.key?(size)
|
72
|
+
|
73
|
+
raise ArgumentError, "Invalid size: #{size}. Must be one of #{TAB_SIZE.keys}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def tab_attributes
|
77
|
+
theme_classes = active ? TAB_THEME_ACTIVE[theme] : TAB_THEME_INACTIVE[theme]
|
78
|
+
|
79
|
+
base_classes = [
|
80
|
+
'inline-flex items-center justify-center gap-2 font-medium rounded-md transition-colors',
|
81
|
+
'focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500',
|
82
|
+
TAB_SIZE[size],
|
83
|
+
theme_classes,
|
84
|
+
disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',
|
85
|
+
classes
|
86
|
+
].compact.join(' ')
|
87
|
+
|
88
|
+
{
|
89
|
+
class: base_classes,
|
90
|
+
role: 'tab',
|
91
|
+
'aria-selected': active.to_s,
|
92
|
+
'aria-controls': target,
|
93
|
+
'data-bui-tabs-target': 'tab',
|
94
|
+
'data-target': target,
|
95
|
+
'data-action': disabled ? '' : 'click->bui-tabs#switchTab',
|
96
|
+
tabindex: active ? '0' : '-1',
|
97
|
+
id: "tab-#{target}"
|
98
|
+
}.merge(options)
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_icon?
|
102
|
+
icon.present?
|
103
|
+
end
|
104
|
+
|
105
|
+
def has_badge?
|
106
|
+
badge.present?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BetterUi
|
4
|
+
module General
|
5
|
+
module Tag
|
6
|
+
class Component < ViewComponent::Base
|
7
|
+
def initialize(text:, theme: :white, size: :medium, style: :filled, **options)
|
8
|
+
@text = text
|
9
|
+
@theme = theme.to_sym
|
10
|
+
@size = size.to_sym
|
11
|
+
@style = style.to_sym
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :text, :theme, :size, :style, :options
|
18
|
+
|
19
|
+
def tag_classes
|
20
|
+
base_classes = %w[
|
21
|
+
inline-flex
|
22
|
+
items-center
|
23
|
+
justify-center
|
24
|
+
font-medium
|
25
|
+
transition-colors
|
26
|
+
duration-200
|
27
|
+
bui-tag
|
28
|
+
]
|
29
|
+
|
30
|
+
base_classes.concat(size_classes)
|
31
|
+
base_classes.concat(theme_classes)
|
32
|
+
base_classes.concat(style_classes)
|
33
|
+
base_classes.join(" ")
|
34
|
+
end
|
35
|
+
|
36
|
+
def size_classes
|
37
|
+
case size
|
38
|
+
when :small
|
39
|
+
%w[text-xs px-2 py-1 rounded]
|
40
|
+
when :large
|
41
|
+
%w[text-base px-4 py-2 rounded-lg]
|
42
|
+
else # :medium
|
43
|
+
%w[text-sm px-3 py-1.5 rounded-md]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def theme_classes
|
48
|
+
case theme
|
49
|
+
when :default
|
50
|
+
%w[bg-gray-100 text-gray-800]
|
51
|
+
when :red
|
52
|
+
%w[bg-red-100 text-red-800]
|
53
|
+
when :rose
|
54
|
+
%w[bg-rose-100 text-rose-800]
|
55
|
+
when :orange
|
56
|
+
%w[bg-orange-100 text-orange-800]
|
57
|
+
when :green
|
58
|
+
%w[bg-green-100 text-green-800]
|
59
|
+
when :blue
|
60
|
+
%w[bg-blue-100 text-blue-800]
|
61
|
+
when :yellow
|
62
|
+
%w[bg-yellow-100 text-yellow-800]
|
63
|
+
when :violet
|
64
|
+
%w[bg-violet-100 text-violet-800]
|
65
|
+
else # :white
|
66
|
+
%w[bg-white text-gray-700 border border-gray-200]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def style_classes
|
71
|
+
case style
|
72
|
+
when :outline
|
73
|
+
outline_theme_classes
|
74
|
+
else # :filled
|
75
|
+
[]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def outline_theme_classes
|
80
|
+
case theme
|
81
|
+
when :default
|
82
|
+
%w[bg-transparent border-gray-300 text-gray-700 hover:bg-gray-50]
|
83
|
+
when :red
|
84
|
+
%w[bg-transparent border-red-300 text-red-700 hover:bg-red-50]
|
85
|
+
when :rose
|
86
|
+
%w[bg-transparent border-rose-300 text-rose-700 hover:bg-rose-50]
|
87
|
+
when :orange
|
88
|
+
%w[bg-transparent border-orange-300 text-orange-700 hover:bg-orange-50]
|
89
|
+
when :green
|
90
|
+
%w[bg-transparent border-green-300 text-green-700 hover:bg-green-50]
|
91
|
+
when :blue
|
92
|
+
%w[bg-transparent border-blue-300 text-blue-700 hover:bg-blue-50]
|
93
|
+
when :yellow
|
94
|
+
%w[bg-transparent border-yellow-300 text-yellow-700 hover:bg-yellow-50]
|
95
|
+
when :violet
|
96
|
+
%w[bg-transparent border-violet-300 text-violet-700 hover:bg-violet-50]
|
97
|
+
else # :white
|
98
|
+
%w[bg-transparent border-gray-300 text-gray-700 hover:bg-gray-50]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module General
|
3
|
+
module Tooltip
|
4
|
+
class Component < ViewComponent::Base
|
5
|
+
# Classi base sempre presenti
|
6
|
+
TOOLTIP_BASE_CLASSES = "relative inline-block"
|
7
|
+
|
8
|
+
# Classi base per il bubble del tooltip
|
9
|
+
TOOLTIP_BUBBLE_BASE_CLASSES = "absolute z-50 px-2 py-1 text-sm rounded shadow-lg opacity-0 pointer-events-none transition-opacity duration-200"
|
10
|
+
|
11
|
+
# Classi per la visibilità su hover
|
12
|
+
TOOLTIP_HOVER_CLASSES = "group-hover:opacity-100"
|
13
|
+
|
14
|
+
# Posizioni del tooltip con classi Tailwind dirette
|
15
|
+
TOOLTIP_POSITIONS = {
|
16
|
+
top: "bottom-full left-1/2 transform -translate-x-1/2 mb-2",
|
17
|
+
right: "left-full top-1/2 transform -translate-y-1/2 ml-2",
|
18
|
+
bottom: "top-full left-1/2 transform -translate-x-1/2 mt-2",
|
19
|
+
left: "right-full top-1/2 transform -translate-y-1/2 mr-2"
|
20
|
+
}
|
21
|
+
|
22
|
+
# Dimensioni del tooltip con classi Tailwind dirette
|
23
|
+
TOOLTIP_SIZES = {
|
24
|
+
small: "px-1.5 py-0.5 text-xs",
|
25
|
+
medium: "px-2 py-1 text-sm",
|
26
|
+
large: "px-3 py-2 text-base"
|
27
|
+
}
|
28
|
+
|
29
|
+
# Temi di tooltip con classi Tailwind dirette - Stile filled
|
30
|
+
TOOLTIP_FILLED_THEMES = {
|
31
|
+
default: "bg-gray-900 text-white",
|
32
|
+
white: "bg-white text-gray-900 border border-gray-200",
|
33
|
+
red: "bg-red-600 text-white",
|
34
|
+
rose: "bg-rose-600 text-white",
|
35
|
+
orange: "bg-orange-600 text-white",
|
36
|
+
green: "bg-green-600 text-white",
|
37
|
+
blue: "bg-blue-600 text-white",
|
38
|
+
yellow: "bg-yellow-600 text-white",
|
39
|
+
violet: "bg-violet-600 text-white"
|
40
|
+
}
|
41
|
+
|
42
|
+
# Temi di tooltip con classi Tailwind dirette - Stile outline
|
43
|
+
TOOLTIP_OUTLINE_THEMES = {
|
44
|
+
default: "bg-white text-gray-900 border border-gray-900",
|
45
|
+
white: "bg-gray-50 text-gray-900 border border-gray-300",
|
46
|
+
red: "bg-white text-red-600 border border-red-600",
|
47
|
+
rose: "bg-white text-rose-600 border border-rose-600",
|
48
|
+
orange: "bg-white text-orange-600 border border-orange-600",
|
49
|
+
green: "bg-white text-green-600 border border-green-600",
|
50
|
+
blue: "bg-white text-blue-600 border border-blue-600",
|
51
|
+
yellow: "bg-white text-yellow-600 border border-yellow-600",
|
52
|
+
violet: "bg-white text-violet-600 border border-violet-600"
|
53
|
+
}
|
54
|
+
|
55
|
+
# Classi per le frecce del tooltip - Filled
|
56
|
+
TOOLTIP_ARROW_BASE_CLASSES = "absolute w-2 h-2 transform rotate-45"
|
57
|
+
|
58
|
+
TOOLTIP_ARROW_POSITIONS = {
|
59
|
+
top: "top-full left-1/2 -translate-x-1/2 -mt-1",
|
60
|
+
right: "right-full top-1/2 -translate-y-1/2 -mr-1",
|
61
|
+
bottom: "bottom-full left-1/2 -translate-x-1/2 -mb-1",
|
62
|
+
left: "left-full top-1/2 -translate-y-1/2 -ml-1"
|
63
|
+
}
|
64
|
+
|
65
|
+
TOOLTIP_ARROW_FILLED_THEMES = {
|
66
|
+
default: "bg-gray-900",
|
67
|
+
white: "bg-white border border-gray-200",
|
68
|
+
red: "bg-red-600",
|
69
|
+
rose: "bg-rose-600",
|
70
|
+
orange: "bg-orange-600",
|
71
|
+
green: "bg-green-600",
|
72
|
+
blue: "bg-blue-600",
|
73
|
+
yellow: "bg-yellow-600",
|
74
|
+
violet: "bg-violet-600"
|
75
|
+
}
|
76
|
+
|
77
|
+
TOOLTIP_ARROW_OUTLINE_THEMES = {
|
78
|
+
default: "bg-white border border-gray-900",
|
79
|
+
white: "bg-gray-50 border border-gray-300",
|
80
|
+
red: "bg-white border border-red-600",
|
81
|
+
rose: "bg-white border border-rose-600",
|
82
|
+
orange: "bg-white border border-orange-600",
|
83
|
+
green: "bg-white border border-green-600",
|
84
|
+
blue: "bg-white border border-blue-600",
|
85
|
+
yellow: "bg-white border border-yellow-600",
|
86
|
+
violet: "bg-white border border-violet-600"
|
87
|
+
}
|
88
|
+
|
89
|
+
# @param text [String] testo del tooltip
|
90
|
+
# @param theme [Symbol] :default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet
|
91
|
+
# @param position [Symbol] :top, :right, :bottom, :left posizione del tooltip
|
92
|
+
# @param size [Symbol] :small, :medium, :large dimensione del tooltip
|
93
|
+
# @param style [Symbol] :filled, :outline stile del tooltip
|
94
|
+
# @param classes [String] classi CSS aggiuntive per il container
|
95
|
+
# @param html_options [Hash] opzioni HTML per il container
|
96
|
+
def initialize(
|
97
|
+
text: nil,
|
98
|
+
theme: :white,
|
99
|
+
position: :top,
|
100
|
+
size: :medium,
|
101
|
+
style: :filled,
|
102
|
+
classes: nil,
|
103
|
+
**html_options
|
104
|
+
)
|
105
|
+
@text = text
|
106
|
+
@theme = theme.to_sym
|
107
|
+
@position = position.to_sym
|
108
|
+
@size = size.to_sym
|
109
|
+
@style = style.to_sym
|
110
|
+
@classes = classes
|
111
|
+
@html_options = html_options
|
112
|
+
|
113
|
+
validate_params
|
114
|
+
end
|
115
|
+
|
116
|
+
# Combina tutte le classi per il container
|
117
|
+
def combined_classes
|
118
|
+
[
|
119
|
+
TOOLTIP_BASE_CLASSES,
|
120
|
+
"group", # Necessario per il trigger hover
|
121
|
+
@classes,
|
122
|
+
@html_options[:class]
|
123
|
+
].compact.join(" ")
|
124
|
+
end
|
125
|
+
|
126
|
+
# Combina tutte le classi per il bubble del tooltip
|
127
|
+
def bubble_classes
|
128
|
+
[
|
129
|
+
TOOLTIP_BUBBLE_BASE_CLASSES,
|
130
|
+
get_position_class,
|
131
|
+
get_size_class,
|
132
|
+
get_theme_class,
|
133
|
+
TOOLTIP_HOVER_CLASSES
|
134
|
+
].compact.join(" ")
|
135
|
+
end
|
136
|
+
|
137
|
+
# Combina tutte le classi per la freccia del tooltip
|
138
|
+
def arrow_classes
|
139
|
+
[
|
140
|
+
TOOLTIP_ARROW_BASE_CLASSES,
|
141
|
+
get_arrow_position_class,
|
142
|
+
get_arrow_theme_class
|
143
|
+
].compact.join(" ")
|
144
|
+
end
|
145
|
+
|
146
|
+
# Restituisce gli attributi per il container del tooltip
|
147
|
+
def tooltip_attributes
|
148
|
+
attrs = {
|
149
|
+
class: combined_classes,
|
150
|
+
role: "tooltip",
|
151
|
+
"data-tooltip": @text
|
152
|
+
}
|
153
|
+
|
154
|
+
# Aggiungi altri attributi HTML se presenti
|
155
|
+
@html_options.except(:class).each do |key, value|
|
156
|
+
attrs[key] = value
|
157
|
+
end
|
158
|
+
|
159
|
+
attrs
|
160
|
+
end
|
161
|
+
|
162
|
+
# Genera le classi per la posizione
|
163
|
+
def get_position_class
|
164
|
+
TOOLTIP_POSITIONS[@position] || TOOLTIP_POSITIONS[:top]
|
165
|
+
end
|
166
|
+
|
167
|
+
# Genera le classi per la dimensione
|
168
|
+
def get_size_class
|
169
|
+
TOOLTIP_SIZES[@size] || TOOLTIP_SIZES[:medium]
|
170
|
+
end
|
171
|
+
|
172
|
+
# Genera le classi per il tema
|
173
|
+
def get_theme_class
|
174
|
+
if @style == :outline
|
175
|
+
TOOLTIP_OUTLINE_THEMES[@theme] || TOOLTIP_OUTLINE_THEMES[:white]
|
176
|
+
else
|
177
|
+
TOOLTIP_FILLED_THEMES[@theme] || TOOLTIP_FILLED_THEMES[:white]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Genera le classi per la posizione della freccia
|
182
|
+
def get_arrow_position_class
|
183
|
+
TOOLTIP_ARROW_POSITIONS[@position] || TOOLTIP_ARROW_POSITIONS[:top]
|
184
|
+
end
|
185
|
+
|
186
|
+
# Genera le classi per il tema della freccia
|
187
|
+
def get_arrow_theme_class
|
188
|
+
if @style == :outline
|
189
|
+
TOOLTIP_ARROW_OUTLINE_THEMES[@theme] || TOOLTIP_ARROW_OUTLINE_THEMES[:white]
|
190
|
+
else
|
191
|
+
TOOLTIP_ARROW_FILLED_THEMES[@theme] || TOOLTIP_ARROW_FILLED_THEMES[:white]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Verifica se il componente deve essere renderizzato
|
196
|
+
def render?
|
197
|
+
@text.present? && content.present?
|
198
|
+
end
|
199
|
+
|
200
|
+
private
|
201
|
+
|
202
|
+
def validate_params
|
203
|
+
validate_theme
|
204
|
+
validate_position
|
205
|
+
validate_size
|
206
|
+
validate_style
|
207
|
+
end
|
208
|
+
|
209
|
+
def validate_theme
|
210
|
+
valid_themes = TOOLTIP_FILLED_THEMES.keys
|
211
|
+
unless valid_themes.include?(@theme)
|
212
|
+
raise ArgumentError, "Il tema deve essere uno tra: #{valid_themes.join(', ')}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def validate_position
|
217
|
+
valid_positions = TOOLTIP_POSITIONS.keys
|
218
|
+
unless valid_positions.include?(@position)
|
219
|
+
raise ArgumentError, "La posizione deve essere una tra: #{valid_positions.join(', ')}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def validate_size
|
224
|
+
valid_sizes = TOOLTIP_SIZES.keys
|
225
|
+
unless valid_sizes.include?(@size)
|
226
|
+
raise ArgumentError, "La dimensione deve essere una tra: #{valid_sizes.join(', ')}"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def validate_style
|
231
|
+
valid_styles = [ :filled, :outline ]
|
232
|
+
unless valid_styles.include?(@style)
|
233
|
+
raise ArgumentError, "Lo stile deve essere uno tra: #{valid_styles.join(', ')}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BetterUi
|
4
|
+
module Application
|
5
|
+
module Components
|
6
|
+
module Card
|
7
|
+
module CardHelper
|
8
|
+
# Helper per creare una card per metriche e statistiche nelle dashboard applicative
|
9
|
+
#
|
10
|
+
# @param title [String] Il titolo/etichetta della metrica
|
11
|
+
# @param value [String] Il valore principale da visualizzare
|
12
|
+
# @param trend [Symbol, nil] La direzione del trend (:up, :down, nil), default nil
|
13
|
+
# @param change [String, nil] Il valore del cambiamento (es. "+12%"), default nil
|
14
|
+
# @param color [Symbol] Il colore del trend (:green, :red, :blue, :yellow, :purple, :indigo, :gray), default :green
|
15
|
+
# @param theme [Symbol] Il tema della card (:default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet, :purple), default :default
|
16
|
+
# @param size [Symbol] La dimensione della card (:small, :medium, :large), default :medium
|
17
|
+
# @param rounded [Symbol] Il livello di arrotondamento (:none, :small, :medium, :large, :full), default :medium
|
18
|
+
# @param shadow [Symbol] Il tipo di ombra (:none, :small, :medium, :large), default :small
|
19
|
+
# @param classes [String, nil] Classi CSS aggiuntive per il contenitore principale
|
20
|
+
# @param form [Nil] Parametro form per compatibilità con form builder (non utilizzato)
|
21
|
+
# @param options [Hash] Attributi HTML aggiuntivi da passare al div principale
|
22
|
+
#
|
23
|
+
# @return [String] HTML della card per metriche
|
24
|
+
#
|
25
|
+
# @example Card base con solo titolo e valore
|
26
|
+
# <%= bui_card(title: "Utenti Attivi", value: "1.234") %>
|
27
|
+
#
|
28
|
+
# @example Card con trend positivo
|
29
|
+
# <%= bui_card(
|
30
|
+
# title: "Vendite Totali",
|
31
|
+
# value: "€ 45.231",
|
32
|
+
# trend: :up,
|
33
|
+
# change: "+12%",
|
34
|
+
# color: :green
|
35
|
+
# ) %>
|
36
|
+
#
|
37
|
+
# @example Card con trend negativo
|
38
|
+
# <%= bui_card(
|
39
|
+
# title: "Conversioni",
|
40
|
+
# value: "2.8%",
|
41
|
+
# trend: :down,
|
42
|
+
# change: "-5%",
|
43
|
+
# color: :red
|
44
|
+
# ) %>
|
45
|
+
#
|
46
|
+
# @example Card con tema e dimensioni personalizzate
|
47
|
+
# <%= bui_card(
|
48
|
+
# title: "Revenue",
|
49
|
+
# value: "$89,432",
|
50
|
+
# theme: :primary,
|
51
|
+
# size: :large,
|
52
|
+
# rounded: :large,
|
53
|
+
# shadow: :medium
|
54
|
+
# ) %>
|
55
|
+
#
|
56
|
+
# @example Card con attributi HTML aggiuntivi
|
57
|
+
# <%= bui_card(
|
58
|
+
# title: "Performance",
|
59
|
+
# value: "98.5%",
|
60
|
+
# classes: "transition-all hover:shadow-lg",
|
61
|
+
# data: { controller: "stats" },
|
62
|
+
# id: "performance-card"
|
63
|
+
# ) %>
|
64
|
+
def bui_card(
|
65
|
+
title:,
|
66
|
+
value:,
|
67
|
+
trend: nil,
|
68
|
+
change: nil,
|
69
|
+
color: :green,
|
70
|
+
theme: :default,
|
71
|
+
size: :medium,
|
72
|
+
rounded: :medium,
|
73
|
+
shadow: :small,
|
74
|
+
classes: nil,
|
75
|
+
form: nil,
|
76
|
+
**options
|
77
|
+
)
|
78
|
+
render BetterUi::Application::Card::Component.new(
|
79
|
+
title: title,
|
80
|
+
value: value,
|
81
|
+
trend: trend,
|
82
|
+
change: change,
|
83
|
+
color: color,
|
84
|
+
theme: theme,
|
85
|
+
size: size,
|
86
|
+
rounded: rounded,
|
87
|
+
shadow: shadow,
|
88
|
+
classes: classes,
|
89
|
+
**options
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module BetterUi
|
2
|
+
module Application
|
3
|
+
module Components
|
4
|
+
module Main
|
5
|
+
module MainHelper
|
6
|
+
# Helper per creare il contenitore principale dell'applicazione
|
7
|
+
#
|
8
|
+
# @param padding [Boolean] Se applicare il padding al contenitore principale, default true
|
9
|
+
# @param inner_padding [Boolean] Se applicare il padding al contenitore interno, default true
|
10
|
+
# @param rounded [Symbol] Tipo di border-radius del contenitore interno (:none, :small, :medium, :large, :full), default :small
|
11
|
+
# @param shadow [Symbol] Tipo di ombra del contenitore interno (:none, :small, :medium, :large), default :medium
|
12
|
+
# @param with_sidebar [Boolean] Se lasciare lo spazio per la sidebar, default true
|
13
|
+
# @param sidebar_width [Symbol] Larghezza della sidebar (:sm, :md, :lg, :xl), default :md
|
14
|
+
# @param classes [String] Classi CSS aggiuntive per il contenitore principale
|
15
|
+
# @param form [Nil] Parametro form per compatibilità con form builder (non utilizzato)
|
16
|
+
# @param block [Proc] Blocco contenente il contenuto del main
|
17
|
+
#
|
18
|
+
# @return [String] HTML del componente main
|
19
|
+
#
|
20
|
+
# @example Main base
|
21
|
+
# <%= bui_main %>
|
22
|
+
#
|
23
|
+
# @example Main con tema
|
24
|
+
# <%= bui_main(rounded: :medium, shadow: :lg) %>
|
25
|
+
#
|
26
|
+
# @example Main senza sidebar
|
27
|
+
# <%= bui_main(with_sidebar: false) %>
|
28
|
+
#
|
29
|
+
# @example Main con padding personalizzati
|
30
|
+
# <%= bui_main(padding: false, inner_padding: true) %>
|
31
|
+
#
|
32
|
+
# @example Main con classi aggiuntive
|
33
|
+
# <%= bui_main(
|
34
|
+
# classes: "my-8",
|
35
|
+
# data: { controller: "main" }
|
36
|
+
# ) %>
|
37
|
+
def bui_main(
|
38
|
+
padding: true,
|
39
|
+
inner_padding: true,
|
40
|
+
rounded: :small,
|
41
|
+
shadow: :medium,
|
42
|
+
with_sidebar: true,
|
43
|
+
sidebar_width: :md,
|
44
|
+
classes: nil,
|
45
|
+
form: nil,
|
46
|
+
**options,
|
47
|
+
&block
|
48
|
+
)
|
49
|
+
render BetterUi::Application::Main::Component.new(
|
50
|
+
padding: padding,
|
51
|
+
inner_padding: inner_padding,
|
52
|
+
rounded: rounded,
|
53
|
+
shadow: shadow,
|
54
|
+
with_sidebar: with_sidebar,
|
55
|
+
sidebar_width: sidebar_width,
|
56
|
+
classes: classes,
|
57
|
+
**options
|
58
|
+
), &block
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|