m9sh 0.2.3 → 0.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2943f1ea814ee67959d6641c70faafff3cd1679436893f0e5e6bd0346a87bd1
4
- data.tar.gz: 19596194b09be430dab2ece4179bf7a7adb748f9e47016dd4e74b5420eac087a
3
+ metadata.gz: 60a17049e08e32e54ff30a314c07e746712f7d0cf10c84daef8794c44ac53520
4
+ data.tar.gz: 8331db49172a68f2605c2b4cdc6d4feadfafc97a0199143a974f007646ccb69a
5
5
  SHA512:
6
- metadata.gz: 6082841e10731ac6b1f8524a3e8c2c3f6ea402a385d543c180bbee82308778a393b04b87569792689c7ab49d383e756fdcf40bc15586571c2482a60402a040c9
7
- data.tar.gz: b5ddcde073cd21ab9956c713eba54582ec28adbf1cb6a9cec76410e571dccd3575ccfa351043c4e1798bc3605b4b567770e2fd2fdcbe43a5f863e0115af49fc9
6
+ metadata.gz: b64d1a98d913d375cdc090d050177164c88037a75286723754a25f1f4b668c2f68873c6730b5baec9e76d3b83769c4e82f5b85a899b6607f57bcb5ad706c7a54
7
+ data.tar.gz: e47067baeeed55078b0340573d333ec5d677d45cee791a6b33679a97b095f6194504f12f99647ccfcecf2b8254e22c08ddc2780e016badde22e6a18768ea7422
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module M9sh
4
+ class BackdropComponent < M9sh::BaseComponent
5
+ renders_one :navbar
6
+ renders_one :left_sidebar
7
+ renders_one :right_sidebar
8
+ renders_one :main_content
9
+
10
+ def initialize(
11
+ show_left_sidebar: true,
12
+ show_right_sidebar: true,
13
+ left_sidebar_width: "w-[300px]",
14
+ right_sidebar_width: "w-[300px]",
15
+ **extra_attrs
16
+ )
17
+ @show_left_sidebar = show_left_sidebar
18
+ @show_right_sidebar = show_right_sidebar
19
+ @left_sidebar_width = left_sidebar_width
20
+ @right_sidebar_width = right_sidebar_width
21
+ super(**extra_attrs)
22
+ end
23
+
24
+ def call
25
+ tag.div(**component_attrs("h-screen w-screen flex flex-col overflow-hidden"), data: { controller: "m9sh--backdrop" }) do
26
+ safe_join([
27
+ render_navbar_section,
28
+ render_overlay,
29
+ render_content_area
30
+ ].compact)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def render_navbar_section
37
+ return unless navbar?
38
+
39
+ # Render navbar with toggle buttons passed as slots
40
+ navbar.to_s.html_safe
41
+ end
42
+
43
+ def render_content_area
44
+ tag.div(class: "flex-1 flex overflow-hidden") do
45
+ safe_join([
46
+ render_left_sidebar_section,
47
+ render_main_content_section,
48
+ render_right_sidebar_section
49
+ ].compact)
50
+ end
51
+ end
52
+
53
+ def render_left_sidebar_section
54
+ return unless @show_left_sidebar && left_sidebar?
55
+
56
+ # Convert width to responsive: w-[300px] -> w-screen md:w-[300px]
57
+ desktop_width = @left_sidebar_width.start_with?('w-') ? "md:#{@left_sidebar_width}" : "md:w-[300px]"
58
+
59
+ tag.div(
60
+ class: "pt-16 w-screen #{desktop_width} flex-shrink-0 overflow-y-auto fixed md:relative left-0 md:left-auto -translate-x-full md:translate-x-0 top-0 bottom-0 md:bottom-auto z-40 md:z-auto transition-all duration-300 ease-in-out bg-transparent md:bg-background shadow-xl md:shadow-none md:border-r md:border-transparent",
61
+ data: { m9sh__backdrop_target: "leftSidebar" }
62
+ ) do
63
+ left_sidebar.to_s.html_safe
64
+ end
65
+ end
66
+
67
+ def render_main_content_section
68
+ return unless main_content?
69
+
70
+ tag.div(class: "pt-16 flex-1 overflow-auto") do
71
+ main_content.to_s.html_safe
72
+ end
73
+ end
74
+
75
+ def render_right_sidebar_section
76
+ return unless @show_right_sidebar && right_sidebar?
77
+
78
+ # Convert width to responsive: w-[300px] -> w-screen md:w-[300px]
79
+ desktop_width = @right_sidebar_width.start_with?('w-') ? "md:#{@right_sidebar_width}" : "md:w-[300px]"
80
+
81
+ tag.div(
82
+ class: "pt-16 w-screen #{desktop_width} flex-shrink-0 overflow-y-auto fixed md:relative right-0 md:right-auto translate-x-full md:translate-x-0 top-0 bottom-0 md:bottom-auto z-40 md:z-auto transition-all duration-300 ease-in-out bg-transparent md:bg-background shadow-xl md:shadow-none md:border-l md:border-transparent",
83
+ data: { m9sh__backdrop_target: "rightSidebar" }
84
+ ) do
85
+ right_sidebar.to_s.html_safe
86
+ end
87
+ end
88
+
89
+ def render_overlay
90
+ tag.div(
91
+ class: "hidden fixed top-16 left-0 right-0 bottom-0 bg-background/80 backdrop-blur-sm z-30 md:hidden",
92
+ data: {
93
+ m9sh__backdrop_target: "overlay",
94
+ action: "click->m9sh--backdrop#closeAll"
95
+ }
96
+ )
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,137 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["leftSidebar", "rightSidebar", "overlay", "leftToggle", "rightToggle"]
5
+ static values = {
6
+ leftOpen: { type: Boolean, default: false },
7
+ rightOpen: { type: Boolean, default: false }
8
+ }
9
+
10
+ connect() {
11
+ // Check if mobile
12
+ this.checkMobile()
13
+
14
+ // Apply initial state to ensure proper desktop display
15
+ this.applyState()
16
+
17
+ // Listen for resize events
18
+ window.addEventListener("resize", this.checkMobile.bind(this))
19
+ }
20
+
21
+ disconnect() {
22
+ window.removeEventListener("resize", this.checkMobile.bind(this))
23
+ }
24
+
25
+ checkMobile() {
26
+ this.isMobile = window.innerWidth < 768
27
+
28
+ // If switching to desktop, close all mobile sidebars
29
+ if (!this.isMobile) {
30
+ this.leftOpenValue = false
31
+ this.rightOpenValue = false
32
+ this.applyState()
33
+ }
34
+ }
35
+
36
+ toggleLeft() {
37
+ if (!this.isMobile) return
38
+
39
+ this.leftOpenValue = !this.leftOpenValue
40
+
41
+ // Close right sidebar if opening left
42
+ if (this.leftOpenValue) {
43
+ this.rightOpenValue = false
44
+ }
45
+
46
+ this.applyState()
47
+ }
48
+
49
+ toggleRight() {
50
+ if (!this.isMobile) return
51
+
52
+ this.rightOpenValue = !this.rightOpenValue
53
+
54
+ // Close left sidebar if opening right
55
+ if (this.rightOpenValue) {
56
+ this.leftOpenValue = false
57
+ }
58
+
59
+ this.applyState()
60
+ }
61
+
62
+ closeAll() {
63
+ this.leftOpenValue = false
64
+ this.rightOpenValue = false
65
+ this.applyState()
66
+ }
67
+
68
+ applyState() {
69
+ const anyOpen = this.leftOpenValue || this.rightOpenValue
70
+
71
+ // Update overlay
72
+ if (this.hasOverlayTarget) {
73
+ if (anyOpen && this.isMobile) {
74
+ this.overlayTarget.classList.remove("hidden")
75
+ } else {
76
+ this.overlayTarget.classList.add("hidden")
77
+ }
78
+ }
79
+
80
+ // Update left sidebar (only on mobile, desktop handled by CSS)
81
+ if (this.hasLeftSidebarTarget && this.isMobile) {
82
+ if (this.leftOpenValue) {
83
+ // Slide into view from left edge
84
+ this.leftSidebarTarget.classList.remove("-translate-x-full")
85
+ this.leftSidebarTarget.classList.add("translate-x-0")
86
+ } else {
87
+ // Slide out to left edge
88
+ this.leftSidebarTarget.classList.remove("translate-x-0")
89
+ this.leftSidebarTarget.classList.add("-translate-x-full")
90
+ }
91
+ }
92
+
93
+ // Update right sidebar (only on mobile, desktop handled by CSS)
94
+ if (this.hasRightSidebarTarget && this.isMobile) {
95
+ if (this.rightOpenValue) {
96
+ // Slide into view from right edge
97
+ this.rightSidebarTarget.classList.remove("translate-x-full")
98
+ this.rightSidebarTarget.classList.add("translate-x-0")
99
+ } else {
100
+ // Slide out to right edge
101
+ this.rightSidebarTarget.classList.remove("translate-x-0")
102
+ this.rightSidebarTarget.classList.add("translate-x-full")
103
+ }
104
+ }
105
+
106
+ // Update toggle button icons rotation (chevrons)
107
+ if (this.hasLeftToggleTarget) {
108
+ const icon = this.leftToggleTarget.querySelector("svg")
109
+ if (icon) {
110
+ if (this.leftOpenValue) {
111
+ icon.style.transform = "rotate(180deg)"
112
+ } else {
113
+ icon.style.transform = "rotate(0deg)"
114
+ }
115
+ }
116
+ }
117
+
118
+ if (this.hasRightToggleTarget) {
119
+ const icon = this.rightToggleTarget.querySelector("svg")
120
+ if (icon) {
121
+ if (this.rightOpenValue) {
122
+ icon.style.transform = "rotate(180deg)"
123
+ } else {
124
+ icon.style.transform = "rotate(0deg)"
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ leftOpenValueChanged() {
131
+ this.applyState()
132
+ }
133
+
134
+ rightOpenValueChanged() {
135
+ this.applyState()
136
+ }
137
+ }
data/lib/m9sh/registry.rb CHANGED
@@ -93,7 +93,7 @@ module M9sh
93
93
  categories = {
94
94
  "Base" => ["base", "utilities", "icon"],
95
95
  "Form Components" => ["button", "input", "label", "checkbox", "textarea", "select", "switch", "slider", "radio_group"],
96
- "Layout Components" => ["card", "table", "separator", "main"],
96
+ "Layout Components" => ["card", "table", "separator", "main", "backdrop"],
97
97
  "Feedback Components" => ["alert", "toast", "toaster", "progress", "spinner", "skeleton"],
98
98
  "Navigation Components" => ["breadcrumb", "navigation_menu", "navbar", "sidebar", "tabs", "menu"],
99
99
  "Display Components" => ["avatar", "badge", "typography"],
@@ -419,3 +419,13 @@ components:
419
419
  - icon
420
420
  - button
421
421
  - dropdown_menu
422
+
423
+ backdrop:
424
+ name: "Backdrop"
425
+ description: "Full-screen layout with navbar, sidebars, and main content area"
426
+ files:
427
+ - app/components/m9sh/backdrop_component.rb
428
+ - app/javascript/controllers/m9sh/backdrop_controller.js
429
+ dependencies:
430
+ - base
431
+ - utilities
data/lib/m9sh/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module M9sh
4
- VERSION = "0.2.3"
4
+ VERSION = "0.2.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: m9sh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcin Urbanski
@@ -135,6 +135,7 @@ files:
135
135
  - app/components/m9sh/alert_component.rb
136
136
  - app/components/m9sh/alert_dialog_component.rb
137
137
  - app/components/m9sh/avatar_component.rb
138
+ - app/components/m9sh/backdrop_component.rb
138
139
  - app/components/m9sh/badge_component.rb
139
140
  - app/components/m9sh/base_component.rb
140
141
  - app/components/m9sh/breadcrumb_component.rb
@@ -210,6 +211,7 @@ files:
210
211
  - app/javascript/controllers/index.js
211
212
  - app/javascript/controllers/m9sh/accordion_controller.js
212
213
  - app/javascript/controllers/m9sh/alert_dialog_controller.js
214
+ - app/javascript/controllers/m9sh/backdrop_controller.js
213
215
  - app/javascript/controllers/m9sh/collapsible_controller.js
214
216
  - app/javascript/controllers/m9sh/dialog_controller.js
215
217
  - app/javascript/controllers/m9sh/dropdown_menu_controller.js