better_ui 0.5.0 → 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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +137 -245
  3. data/app/assets/stylesheets/better_ui/_base.scss +9 -0
  4. data/app/assets/stylesheets/better_ui/_components.scss +2 -0
  5. data/app/assets/stylesheets/better_ui/_utilities.scss +14 -0
  6. data/app/assets/stylesheets/better_ui/application.css +3 -1
  7. data/app/assets/stylesheets/better_ui/components/_avatar.scss +200 -0
  8. data/app/assets/stylesheets/better_ui/components/_badge.scss +154 -0
  9. data/app/assets/stylesheets/better_ui/components/_breadcrumb.scss +106 -0
  10. data/app/assets/stylesheets/better_ui/components/_button.scss +105 -0
  11. data/app/assets/stylesheets/better_ui/components/_card.scss +60 -0
  12. data/app/assets/stylesheets/better_ui/components/_heading.scss +81 -0
  13. data/app/assets/stylesheets/better_ui/components/_icon.scss +134 -0
  14. data/app/assets/stylesheets/better_ui/components/_index.scss +17 -0
  15. data/app/assets/stylesheets/better_ui/components/_link.scss +100 -0
  16. data/app/assets/stylesheets/better_ui/components/_panel.scss +104 -0
  17. data/app/assets/stylesheets/better_ui/components/_spinner.scss +129 -0
  18. data/app/assets/stylesheets/better_ui/components/_table.scss +156 -0
  19. data/app/assets/stylesheets/better_ui/components/_variables.scss +1 -0
  20. data/app/assets/stylesheets/better_ui.scss +4 -0
  21. data/app/components/better_ui/general/avatar_component.html.erb +2 -2
  22. data/app/components/better_ui/general/avatar_component.rb +29 -29
  23. data/app/components/better_ui/general/badge_component.html.erb +3 -3
  24. data/app/components/better_ui/general/badge_component.rb +32 -20
  25. data/app/components/better_ui/general/breadcrumb_component.html.erb +2 -2
  26. data/app/components/better_ui/general/breadcrumb_component.rb +23 -23
  27. data/app/components/better_ui/general/button_component.html.erb +6 -6
  28. data/app/components/better_ui/general/button_component.rb +20 -22
  29. data/app/components/better_ui/general/heading_component.html.erb +1 -25
  30. data/app/components/better_ui/general/heading_component.rb +17 -116
  31. data/app/components/better_ui/general/icon_component.html.erb +1 -1
  32. data/app/components/better_ui/general/icon_component.rb +33 -56
  33. data/app/components/better_ui/general/link_component.html.erb +4 -4
  34. data/app/components/better_ui/general/link_component.rb +28 -28
  35. data/app/components/better_ui/general/panel_component.rb +30 -41
  36. data/app/components/better_ui/general/spinner_component.html.erb +3 -3
  37. data/app/components/better_ui/general/spinner_component.rb +13 -13
  38. data/app/components/better_ui/general/table_component.rb +35 -59
  39. data/app/helpers/better_ui/general/components/avatar_helper.rb +17 -0
  40. data/app/helpers/better_ui/general/components/badge_helper.rb +17 -0
  41. data/app/helpers/better_ui/general/components/breadcrumb_helper.rb +17 -0
  42. data/app/helpers/better_ui/general/components/button_helper.rb +17 -0
  43. data/app/helpers/better_ui/general/components/heading_helper.rb +17 -0
  44. data/app/helpers/better_ui/general/components/icon_helper.rb +17 -0
  45. data/app/helpers/better_ui/general/components/link_helper.rb +17 -0
  46. data/app/helpers/better_ui/general/components/panel_helper.rb +16 -0
  47. data/app/helpers/better_ui/general/components/spinner_helper.rb +17 -0
  48. data/app/helpers/better_ui/general/components/table_helper.rb +17 -0
  49. data/app/helpers/better_ui/general_helper.rb +15 -0
  50. data/app/helpers/better_ui_helper.rb +12 -0
  51. data/config/routes.rb +2 -13
  52. data/lib/better_ui/engine.rb +67 -11
  53. data/lib/better_ui/version.rb +1 -1
  54. data/lib/better_ui.rb +10 -2
  55. data/lib/generators/better_ui/install_generator.rb +103 -0
  56. data/lib/generators/better_ui/stylesheet_generator.rb +93 -30
  57. data/lib/generators/better_ui/templates/README +74 -5
  58. data/lib/generators/better_ui/templates/components/_avatar.scss +199 -150
  59. data/lib/generators/better_ui/templates/components/_badge.scss +153 -141
  60. data/lib/generators/better_ui/templates/components/_breadcrumb.scss +105 -106
  61. data/lib/generators/better_ui/templates/components/_button.scss +104 -101
  62. data/lib/generators/better_ui/templates/components/_card.scss +56 -65
  63. data/lib/generators/better_ui/templates/components/_heading.scss +80 -179
  64. data/lib/generators/better_ui/templates/components/_icon.scss +133 -89
  65. data/lib/generators/better_ui/templates/components/_index.scss +17 -0
  66. data/lib/generators/better_ui/templates/components/_link.scss +99 -129
  67. data/lib/generators/better_ui/templates/components/_panel.scss +103 -143
  68. data/lib/generators/better_ui/templates/components/_spinner.scss +127 -130
  69. data/lib/generators/better_ui/templates/components/_table.scss +156 -105
  70. data/lib/generators/better_ui/templates/components/_variables.scss +0 -33
  71. data/lib/generators/better_ui/templates/components_stylesheet.scss +25 -56
  72. data/lib/generators/better_ui/templates/index.scss +18 -0
  73. data/lib/generators/better_ui/templates/initializer.rb +41 -0
  74. metadata +91 -49
  75. data/app/assets/javascripts/better_ui/controllers/navbar_controller.js +0 -138
  76. data/app/assets/javascripts/better_ui/controllers/sidebar_controller.js +0 -211
  77. data/app/assets/javascripts/better_ui/controllers/toast_controller.js +0 -161
  78. data/app/assets/javascripts/better_ui/index.js +0 -159
  79. data/app/assets/javascripts/better_ui/toast_manager.js +0 -77
  80. data/app/components/better_ui/theme_helper.rb +0 -171
  81. data/app/controllers/better_ui/docs_controller.rb +0 -34
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - alessiobussolari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-04 00:00:00.000000000 Z
11
+ date: 2025-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -28,44 +28,44 @@ dependencies:
28
28
  name: view_component
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0
33
+ version: '3.22'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0
40
+ version: '3.22'
41
41
  - !ruby/object:Gem::Dependency
42
- name: redcarpet
42
+ name: tailwindcss-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.6'
47
+ version: '4.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.6'
54
+ version: '4.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: tailwindcss-rails
56
+ name: redcarpet
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.0'
61
+ version: '3.6'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.0'
68
+ version: '3.6'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: coderay
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,86 +86,101 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 6.5.1
89
+ version: '6.5'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 6.5.1
96
+ version: '6.5'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: lookbook
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '2.1'
104
- type: :runtime
103
+ version: '2.3'
104
+ type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '2.1'
110
+ version: '2.3'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: listen
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ">="
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :runtime
117
+ version: '3.9'
118
+ type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ">="
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: '3.9'
125
125
  - !ruby/object:Gem::Dependency
126
- name: actioncable
126
+ name: sqlite3
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :runtime
131
+ version: '1.6'
132
+ type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: '1.6'
139
139
  - !ruby/object:Gem::Dependency
140
- name: sqlite3
140
+ name: puma
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ">="
143
+ - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: '6.4'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ">="
150
+ - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: '6.4'
153
153
  - !ruby/object:Gem::Dependency
154
- name: puma
154
+ name: rspec-rails
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - ">="
157
+ - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '0'
159
+ version: '6.1'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - ">="
164
+ - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '0'
167
- description: A Rails gem that works as a mountable engine containing reusable UI components
168
- and documentation pages
166
+ version: '6.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1.59'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.59'
181
+ description: Better UI is a Rails gem that works as a mountable engine containing
182
+ reusable UI components, built with ViewComponent and Tailwind CSS, following the
183
+ BEM methodology. It includes documentation and interactive previews with Lookbook.
169
184
  email:
170
185
  - alessio.bussolari@pandev.it
171
186
  executables: []
@@ -175,12 +190,24 @@ files:
175
190
  - MIT-LICENSE
176
191
  - README.md
177
192
  - Rakefile
178
- - app/assets/javascripts/better_ui/controllers/navbar_controller.js
179
- - app/assets/javascripts/better_ui/controllers/sidebar_controller.js
180
- - app/assets/javascripts/better_ui/controllers/toast_controller.js
181
- - app/assets/javascripts/better_ui/index.js
182
- - app/assets/javascripts/better_ui/toast_manager.js
193
+ - app/assets/stylesheets/better_ui.scss
194
+ - app/assets/stylesheets/better_ui/_base.scss
195
+ - app/assets/stylesheets/better_ui/_components.scss
196
+ - app/assets/stylesheets/better_ui/_utilities.scss
183
197
  - app/assets/stylesheets/better_ui/application.css
198
+ - app/assets/stylesheets/better_ui/components/_avatar.scss
199
+ - app/assets/stylesheets/better_ui/components/_badge.scss
200
+ - app/assets/stylesheets/better_ui/components/_breadcrumb.scss
201
+ - app/assets/stylesheets/better_ui/components/_button.scss
202
+ - app/assets/stylesheets/better_ui/components/_card.scss
203
+ - app/assets/stylesheets/better_ui/components/_heading.scss
204
+ - app/assets/stylesheets/better_ui/components/_icon.scss
205
+ - app/assets/stylesheets/better_ui/components/_index.scss
206
+ - app/assets/stylesheets/better_ui/components/_link.scss
207
+ - app/assets/stylesheets/better_ui/components/_panel.scss
208
+ - app/assets/stylesheets/better_ui/components/_spinner.scss
209
+ - app/assets/stylesheets/better_ui/components/_table.scss
210
+ - app/assets/stylesheets/better_ui/components/_variables.scss
184
211
  - app/components/better_ui/application/alert_component.html.erb
185
212
  - app/components/better_ui/application/alert_component.rb
186
213
  - app/components/better_ui/application/card_component.html.erb
@@ -215,9 +242,19 @@ files:
215
242
  - app/components/better_ui/general/spinner_component.rb
216
243
  - app/components/better_ui/general/table_component.html.erb
217
244
  - app/components/better_ui/general/table_component.rb
218
- - app/components/better_ui/theme_helper.rb
219
245
  - app/controllers/better_ui/application_controller.rb
220
- - app/controllers/better_ui/docs_controller.rb
246
+ - app/helpers/better_ui/general/components/avatar_helper.rb
247
+ - app/helpers/better_ui/general/components/badge_helper.rb
248
+ - app/helpers/better_ui/general/components/breadcrumb_helper.rb
249
+ - app/helpers/better_ui/general/components/button_helper.rb
250
+ - app/helpers/better_ui/general/components/heading_helper.rb
251
+ - app/helpers/better_ui/general/components/icon_helper.rb
252
+ - app/helpers/better_ui/general/components/link_helper.rb
253
+ - app/helpers/better_ui/general/components/panel_helper.rb
254
+ - app/helpers/better_ui/general/components/spinner_helper.rb
255
+ - app/helpers/better_ui/general/components/table_helper.rb
256
+ - app/helpers/better_ui/general_helper.rb
257
+ - app/helpers/better_ui_helper.rb
221
258
  - app/jobs/better_ui/application_job.rb
222
259
  - app/mailers/better_ui/application_mailer.rb
223
260
  - app/models/better_ui/application_record.rb
@@ -230,6 +267,7 @@ files:
230
267
  - lib/better_ui.rb
231
268
  - lib/better_ui/engine.rb
232
269
  - lib/better_ui/version.rb
270
+ - lib/generators/better_ui/install_generator.rb
233
271
  - lib/generators/better_ui/stylesheet_generator.rb
234
272
  - lib/generators/better_ui/templates/README
235
273
  - lib/generators/better_ui/templates/components/_avatar.scss
@@ -239,12 +277,15 @@ files:
239
277
  - lib/generators/better_ui/templates/components/_card.scss
240
278
  - lib/generators/better_ui/templates/components/_heading.scss
241
279
  - lib/generators/better_ui/templates/components/_icon.scss
280
+ - lib/generators/better_ui/templates/components/_index.scss
242
281
  - lib/generators/better_ui/templates/components/_link.scss
243
282
  - lib/generators/better_ui/templates/components/_panel.scss
244
283
  - lib/generators/better_ui/templates/components/_spinner.scss
245
284
  - lib/generators/better_ui/templates/components/_table.scss
246
285
  - lib/generators/better_ui/templates/components/_variables.scss
247
286
  - lib/generators/better_ui/templates/components_stylesheet.scss
287
+ - lib/generators/better_ui/templates/index.scss
288
+ - lib/generators/better_ui/templates/initializer.rb
248
289
  - lib/tasks/better_ui_tasks.rake
249
290
  homepage: https://github.com/alessiobussolari/better_ui
250
291
  licenses:
@@ -254,6 +295,7 @@ metadata:
254
295
  homepage_uri: https://github.com/alessiobussolari/better_ui
255
296
  source_code_uri: https://github.com/alessiobussolari/better_ui
256
297
  changelog_uri: https://github.com/alessiobussolari/better_ui/blob/main/CHANGELOG.md
298
+ rubygems_mfa_required: 'true'
257
299
  post_install_message:
258
300
  rdoc_options: []
259
301
  require_paths:
@@ -262,7 +304,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
262
304
  requirements:
263
305
  - - ">="
264
306
  - !ruby/object:Gem::Version
265
- version: '0'
307
+ version: '3.0'
266
308
  required_rubygems_version: !ruby/object:Gem::Requirement
267
309
  requirements:
268
310
  - - ">="
@@ -272,5 +314,5 @@ requirements: []
272
314
  rubygems_version: 3.5.11
273
315
  signing_key:
274
316
  specification_version: 4
275
- summary: Reusable UI components for Rails with integrated documentation
317
+ summary: Elegant and reusable UI components for Rails with integrated documentation
276
318
  test_files: []
@@ -1,138 +0,0 @@
1
- // Navbar controller per gestire il comportamento del menu mobile e dei dropdown
2
- import { Controller } from "@hotwired/stimulus"
3
-
4
- export default class extends Controller {
5
- static targets = ["menu", "dropdown", "submenu"]
6
-
7
- connect() {
8
- // Verifica se siamo su mobile e aggiorna lo stato del menu
9
- this.updateMenuState();
10
-
11
- // Aggiungi un event listener per il resize della finestra
12
- window.addEventListener("resize", this.updateMenuState.bind(this));
13
-
14
- // Chiudi menu quando si clicca su un link (solo su mobile)
15
- if (this.hasMenuTarget) {
16
- const links = this.menuTarget.querySelectorAll("a");
17
- links.forEach(link => {
18
- link.addEventListener("click", () => {
19
- // Se siamo su mobile, chiudi il menu
20
- if (window.innerWidth < 768) {
21
- this.closeMenu();
22
- }
23
- });
24
- });
25
- }
26
-
27
- // Aggiungi listener per i click all'esterno del menu
28
- document.addEventListener("click", this.handleClickOutside.bind(this))
29
- }
30
-
31
- disconnect() {
32
- // Rimuovi event listener per il resize della finestra
33
- window.removeEventListener("resize", this.updateMenuState.bind(this));
34
-
35
- // Rimuovi listener al disconnette
36
- document.removeEventListener("click", this.handleClickOutside.bind(this))
37
- }
38
-
39
- // Metodo per alternare l'apertura/chiusura del menu
40
- toggleMenu(event) {
41
- event.stopPropagation()
42
- const isExpanded = this.menuTarget.classList.contains("hidden") === false
43
-
44
- if (isExpanded) {
45
- this.closeMenu()
46
- } else {
47
- this.openMenu()
48
- }
49
- }
50
-
51
- // Metodo per chiudere il menu
52
- closeMenu() {
53
- this.menuTarget.classList.add("hidden")
54
-
55
- // Aggiorna l'attributo aria-expanded
56
- const button = this.element.querySelector("[aria-controls='navbar-menu']")
57
- if (button) {
58
- button.setAttribute("aria-expanded", "false")
59
- }
60
- }
61
-
62
- // Metodo per aggiornare lo stato del menu in base alla dimensione della finestra
63
- updateMenuState() {
64
- if (this.hasMenuTarget) {
65
- // Se siamo su desktop (md breakpoint - 768px)
66
- if (window.innerWidth >= 768) {
67
- // Assicurati che il menu sia visibile su desktop
68
- this.menuTarget.classList.remove("hidden");
69
- this.menuTarget.classList.add("md:block");
70
- } else {
71
- // Su mobile, nascondi il menu di default
72
- this.menuTarget.classList.add("hidden");
73
- }
74
-
75
- // Aggiorna l'attributo aria-expanded
76
- const button = this.element.querySelector("[aria-controls='navbar-menu']");
77
- if (button) {
78
- const isExpanded = window.innerWidth >= 768 ? "true" : "false";
79
- button.setAttribute("aria-expanded", isExpanded);
80
- }
81
- }
82
- }
83
-
84
- openMenu() {
85
- this.menuTarget.classList.remove("hidden")
86
-
87
- // Chiudi tutti i dropdown nel menu mobile
88
- if (this.hasSubmenuTarget) {
89
- this.submenuTargets.forEach(submenu => {
90
- submenu.classList.add("hidden")
91
- })
92
- }
93
-
94
- // Aggiorna stato del pulsante
95
- event.currentTarget.setAttribute("aria-expanded", "true")
96
- }
97
-
98
- toggleDropdown(event) {
99
- event.stopPropagation()
100
- const button = event.currentTarget
101
- const dropdownId = button.getAttribute("aria-controls")
102
- const dropdown = document.getElementById(dropdownId)
103
-
104
- if (dropdown) {
105
- const isExpanded = button.getAttribute("aria-expanded") === "true"
106
-
107
- if (isExpanded) {
108
- dropdown.classList.add("hidden")
109
- button.setAttribute("aria-expanded", "false")
110
- } else {
111
- // Chiudi tutti gli altri dropdown prima di aprire quello corrente
112
- if (this.hasSubmenuTarget) {
113
- this.submenuTargets.forEach(submenu => {
114
- if (submenu.id !== dropdownId) {
115
- submenu.classList.add("hidden")
116
-
117
- // Trova e aggiorna il pulsante associato
118
- const associatedButton = this.element.querySelector(`[aria-controls='${submenu.id}']`)
119
- if (associatedButton) {
120
- associatedButton.setAttribute("aria-expanded", "false")
121
- }
122
- }
123
- })
124
- }
125
-
126
- dropdown.classList.remove("hidden")
127
- button.setAttribute("aria-expanded", "true")
128
- }
129
- }
130
- }
131
-
132
- handleClickOutside(event) {
133
- // Chiudi il menu se si fa clic all'esterno
134
- if (this.element.contains(event.target) === false) {
135
- this.closeMenu()
136
- }
137
- }
138
- }
@@ -1,211 +0,0 @@
1
- // Sidebar controller per gestire il comportamento del menu laterale
2
- import { Controller } from "@hotwired/stimulus"
3
-
4
- export default class extends Controller {
5
- static targets = ["container", "overlay", "toggleButton", "toggleIcon", "dropdown", "submenu", "chevron"]
6
- static values = {
7
- collapsed: { type: Boolean, default: false },
8
- position: { type: String, default: "left" },
9
- overlayOnMobile: { type: Boolean, default: true }
10
- }
11
-
12
- connect() {
13
- // Applica lo stato iniziale
14
- if (this.collapsedValue) {
15
- this.collapse();
16
- } else {
17
- // Assicuriamo che la sidebar sia espansa all'inizio
18
- this.containerTarget.style.transform = "translateX(0)";
19
- }
20
-
21
- // Imposta i listener per il ridimensionamento della finestra
22
- window.addEventListener("resize", this.handleResize.bind(this));
23
-
24
- // Gestisci lo stato iniziale in base alla dimensione della finestra
25
- this.handleResize();
26
-
27
- // Trova e apri i sottomenu con elementi attivi
28
- this.openSubmenuWithActiveItems();
29
- }
30
-
31
- disconnect() {
32
- // Rimuovi i listener all'uscita
33
- window.removeEventListener("resize", this.handleResize.bind(this));
34
- }
35
-
36
- // Toggle dell'intera sidebar
37
- toggle() {
38
- if (this.isCollapsed()) {
39
- this.expand();
40
- } else {
41
- this.collapse();
42
- }
43
- }
44
-
45
- // Espandi la sidebar
46
- expand() {
47
- // Mostra la sidebar completa
48
- this.containerTarget.classList.remove("transform-translate");
49
- this.containerTarget.style.transform = "translateX(0)";
50
-
51
- // Ruota l'icona del toggle button
52
- if (this.hasToggleIconTarget) {
53
- if (this.positionValue === "left") {
54
- this.toggleIconTarget.style.transform = "rotate(0deg)";
55
- } else {
56
- this.toggleIconTarget.style.transform = "rotate(0deg)";
57
- }
58
- }
59
-
60
- // Aggiorna lo stato
61
- this.collapsedValue = false;
62
- }
63
-
64
- // Contrai la sidebar
65
- collapse() {
66
- const width = this.containerTarget.offsetWidth;
67
- // Usa un valore più piccolo per mantenere visibile una parte della sidebar
68
- const translateValue = this.positionValue === "left" ? `-${width - 10}px` : `${width - 10}px`;
69
-
70
- // Nascondi la sidebar
71
- this.containerTarget.classList.add("transform-translate");
72
- this.containerTarget.style.transform = `translateX(${translateValue})`;
73
-
74
- // Ruota l'icona del toggle button
75
- if (this.hasToggleIconTarget) {
76
- if (this.positionValue === "left") {
77
- this.toggleIconTarget.style.transform = "rotate(180deg)";
78
- } else {
79
- this.toggleIconTarget.style.transform = "rotate(180deg)";
80
- }
81
- }
82
-
83
- // Aggiorna lo stato
84
- this.collapsedValue = true;
85
- }
86
-
87
- // Apri la sidebar
88
- open() {
89
- // Mostra la sidebar
90
- this.containerTarget.style.transform = "translateX(0)";
91
-
92
- // Mostra l'overlay se necessario
93
- if (this.overlayOnMobileValue && window.innerWidth < 768) {
94
- this.overlayTarget.classList.remove("hidden");
95
- this.overlayTarget.classList.add("opacity-100");
96
- document.body.classList.add("overflow-hidden");
97
- }
98
-
99
- // Aggiorna lo stato
100
- this.collapsedValue = false;
101
- }
102
-
103
- // Chiudi la sidebar
104
- close() {
105
- // Se è già contratta su desktop, non fare nulla
106
- if (this.collapsedValue && window.innerWidth >= 768) {
107
- return;
108
- }
109
-
110
- // Su mobile, nascondi completamente
111
- if (window.innerWidth < 768) {
112
- const width = this.containerTarget.offsetWidth;
113
- const translateValue = this.positionValue === "left" ? `-${width}px` : `${width}px`;
114
- this.containerTarget.style.transform = `translateX(${translateValue})`;
115
-
116
- // Nascondi l'overlay
117
- this.overlayTarget.classList.add("hidden");
118
- this.overlayTarget.classList.remove("opacity-100");
119
- document.body.classList.remove("overflow-hidden");
120
- } else {
121
- // Su desktop, contrai
122
- this.collapse();
123
- }
124
- }
125
-
126
- // Verifica se la sidebar è contratta
127
- isCollapsed() {
128
- return this.collapsedValue;
129
- }
130
-
131
- // Handler per il ridimensionamento della finestra
132
- handleResize() {
133
- // Su mobile, mostra l'overlay se la sidebar è aperta
134
- if (window.innerWidth < 768) {
135
- const isHidden = this.containerTarget.style.transform.includes("translateX");
136
-
137
- if (!isHidden && this.overlayOnMobileValue) {
138
- this.overlayTarget.classList.remove("hidden");
139
- } else {
140
- this.overlayTarget.classList.add("hidden");
141
- }
142
- } else {
143
- // Su desktop, nascondi l'overlay
144
- this.overlayTarget.classList.add("hidden");
145
- document.body.classList.remove("overflow-hidden");
146
-
147
- // Ripristina lo stato della sidebar in base al valore di collapsed
148
- if (this.collapsedValue) {
149
- this.collapse();
150
- } else {
151
- this.expand();
152
- }
153
- }
154
- }
155
-
156
- // Toggle di un sottomenu
157
- toggleSubmenu(event) {
158
- const button = event.currentTarget;
159
- const submenuId = button.getAttribute("aria-controls");
160
- const submenu = document.getElementById(submenuId);
161
- const chevron = button.querySelector("[data-sidebar-target='chevron']");
162
-
163
- if (submenu) {
164
- const isExpanded = button.getAttribute("aria-expanded") === "true";
165
-
166
- if (isExpanded) {
167
- // Chiudi il sottomenu
168
- submenu.classList.add("hidden");
169
- button.setAttribute("aria-expanded", "false");
170
- if (chevron) {
171
- chevron.querySelector("svg").style.transform = "rotate(0deg)";
172
- }
173
- } else {
174
- // Apri il sottomenu
175
- submenu.classList.remove("hidden");
176
- button.setAttribute("aria-expanded", "true");
177
- if (chevron) {
178
- chevron.querySelector("svg").style.transform = "rotate(180deg)";
179
- }
180
- }
181
- }
182
- }
183
-
184
- // Apri automaticamente i sottomenu che contengono elementi attivi
185
- openSubmenuWithActiveItems() {
186
- // Trova tutti i dropdown
187
- if (this.hasDropdownTarget) {
188
- this.dropdownTargets.forEach(dropdown => {
189
- const submenuId = dropdown.getAttribute("aria-controls");
190
- const submenu = document.getElementById(submenuId);
191
-
192
- if (submenu) {
193
- // Verifica se il sottomenu contiene elementi attivi
194
- const activeItems = submenu.querySelectorAll(".bg-gray-100, .bg-gray-700, .bg-orange-700, .bg-blue-700");
195
-
196
- if (activeItems.length > 0) {
197
- // Apri il sottomenu
198
- submenu.classList.remove("hidden");
199
- dropdown.setAttribute("aria-expanded", "true");
200
-
201
- // Ruota l'icona chevron se presente
202
- const chevron = dropdown.querySelector("[data-sidebar-target='chevron']");
203
- if (chevron) {
204
- chevron.querySelector("svg").style.transform = "rotate(180deg)";
205
- }
206
- }
207
- }
208
- });
209
- }
210
- }
211
- }