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 +4 -4
- data/app/components/m9sh/backdrop_component.rb +99 -0
- data/app/javascript/controllers/m9sh/backdrop_controller.js +137 -0
- data/lib/m9sh/registry.rb +1 -1
- data/lib/m9sh/registry.yml +10 -0
- data/lib/m9sh/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60a17049e08e32e54ff30a314c07e746712f7d0cf10c84daef8794c44ac53520
|
4
|
+
data.tar.gz: 8331db49172a68f2605c2b4cdc6d4feadfafc97a0199143a974f007646ccb69a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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"],
|
data/lib/m9sh/registry.yml
CHANGED
@@ -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
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.
|
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
|