1+ let minimizedModalsByType = { } ;
2+ let modalCounter = 0 ;
3+
14export default {
2- show ( { id = "custom-modal" , title = "" , content = "" , buttons = [ ] } ) {
5+ show ( {
6+ id = "custom-modal" ,
7+ title = "" ,
8+ content = "" ,
9+ buttons = [ ] ,
10+ type = "default" ,
11+ } ) {
312 this . setNoSelect ( ) ;
4-
5- let modal = document . getElementById ( id ) ;
6- if ( ! modal ) {
7- modal = document . createElement ( "div" ) ;
8- modal . id = id ;
9- modal . className =
10- "fixed bottom-0 left-0 w-full bg-white shadow-xl rounded-t-xl transform translate-y-full transition-transform duration-300 z-50" ;
11- modal . innerHTML = `
13+ if ( document . getElementById ( id ) ) {
14+ id = id + "-" + ++ modalCounter ;
15+ }
16+ let modal = document . createElement ( "div" ) ;
17+ modal . id = id ;
18+ modal . dataset . type = type ;
19+ modal . className =
20+ "fixed bottom-0 left-0 w-full bg-white shadow-xl rounded-t-xl transform translate-y-full transition-transform duration-300 z-50" ;
21+ modal . innerHTML = `
1222 <div class="cursor-pointer w-full bg-gray-300 h-1.5 rounded-full mt-2 mx-auto max-w-16"></div>
1323 <div class="mx-auto p-4 border-b">
1424 <div class="max-w-7xl mx-auto flex items-center justify-between">
@@ -20,25 +30,21 @@ export default {
2030 ${ content }
2131 </div>
2232 ` ;
23- document . body . appendChild ( modal ) ;
24-
25- this . updateButtons ( id , buttons ) ;
26-
27- this . enableDrag ( id ) ;
28-
29- setTimeout ( ( ) => {
30- modal . style . transform = "translateY(0)" ;
31- } , 10 ) ;
32- }
33+ document . body . appendChild ( modal ) ;
34+ this . updateButtons ( id , buttons ) ;
35+ this . enableDrag ( id ) ;
36+ setTimeout ( ( ) => {
37+ modal . style . transform = "translateY(0px)" ;
38+ } , 10 ) ;
3339 } ,
3440
3541 hide ( id = "custom-modal" ) {
3642 this . removeNoSelect ( ) ;
37-
3843 const modal = document . getElementById ( id ) ;
3944 if ( modal ) {
4045 modal . style . transform = "translateY(100%)" ;
4146 setTimeout ( ( ) => modal . remove ( ) , 300 ) ;
47+ this . _removeMinimized ( modal ) ;
4248 }
4349 } ,
4450
@@ -50,15 +56,21 @@ export default {
5056 updateButtons ( id , buttons ) {
5157 const buttonsContainer = document . getElementById ( `${ id } -buttons` ) ;
5258 if ( ! buttonsContainer ) return ;
53-
5459 buttonsContainer . innerHTML = "" ;
55- buttons . forEach ( ( { id, text, onClick, hidden = false } ) => {
60+ buttons . forEach ( ( { id, text, icon , onClick, hidden = false } ) => {
5661 const btn = document . createElement ( "button" ) ;
5762 btn . id = `${ id } ` ;
58- btn . textContent = text ;
59- btn . className = `px-4 py-1 rounded ${
60- hidden ? "hidden" : ""
61- } bg-blue-500 text-white hover:bg-blue-600`;
63+ if ( icon ) {
64+ btn . innerHTML = `<span class="material-symbols-outlined" aria-label="${ text } ">${ icon } </span>` ;
65+ btn . className = `px-4 py-1 rounded ${
66+ hidden ? "hidden" : ""
67+ } text-gray-700`;
68+ } else {
69+ btn . textContent = text ;
70+ btn . className = `px-4 py-1 rounded ${
71+ hidden ? "hidden" : ""
72+ } bg-blue-500 text-white hover:bg-blue-600`;
73+ }
6274 btn . addEventListener ( "click" , onClick ) ;
6375 buttonsContainer . appendChild ( btn ) ;
6476 } ) ;
@@ -74,39 +86,99 @@ export default {
7486 isDragging = false ;
7587 let modal = document . getElementById ( id ) ;
7688 let pill = modal . querySelector ( ".cursor-pointer" ) ;
77-
78- let initialTransform = 100 ;
79- let currentTransform = initialTransform ;
80-
89+ let initialTransform = 0 ;
90+ let currentTransform = 0 ;
91+ const anchorThreshold = 150 ;
8192 pill . addEventListener ( "mousedown" , ( e ) => {
8293 isDragging = true ;
8394 startY = e . clientY ;
84- initialTransform =
85- parseFloat ( getComputedStyle ( modal ) . transform . split ( "," ) [ 5 ] ) || 0 ;
95+ const transform = getComputedStyle ( modal ) . transform ;
96+ if ( transform !== "none" ) {
97+ const matrix = transform . match ( / m a t r i x .* \( ( .+ ) \) / ) [ 1 ] . split ( ", " ) ;
98+ initialTransform = parseFloat ( matrix [ 5 ] ) ;
99+ } else {
100+ initialTransform = 0 ;
101+ }
86102 modal . style . transition = "none" ;
87103 } ) ;
88-
89104 document . addEventListener ( "mousemove" , ( e ) => {
90105 if ( ! isDragging ) return ;
91106 let diff = e . clientY - startY ;
92- let newTransform = Math . min ( Math . max ( initialTransform + diff , 0 ) , 100 ) ;
93- modal . style . transform = `translateY(${ newTransform } %)` ;
107+ let newTransform = initialTransform + diff ;
108+ newTransform = Math . max ( newTransform , 0 ) ;
109+ modal . style . transform = `translateY(${ newTransform } px)` ;
94110 currentTransform = newTransform ;
95111 } ) ;
96-
97112 document . addEventListener ( "mouseup" , ( ) => {
98113 if ( ! isDragging ) return ;
99114 isDragging = false ;
100- modal . style . transition = "transform 0.3s ease" ;
101- if ( currentTransform > 70 ) {
102- modal . style . transform = "translateY(100%)" ;
103- setTimeout ( ( ) => modal . remove ( ) , 300 ) ;
115+ modal . style . transition = "all 0.3s ease" ;
116+ if ( currentTransform >= anchorThreshold ) {
117+ this . minimizeModal ( modal ) ;
104118 } else {
105- modal . style . transform = "translateY(0 )" ;
119+ modal . style . transform = "translateY(0px )" ;
106120 }
107121 } ) ;
108122 } ,
109123
124+ minimizeModal ( modal ) {
125+ modal . style . transform = "translateY(0px)" ;
126+ modal . style . height = "74px" ;
127+ modal . style . width = "200px" ;
128+ modal . style . bottom = "10px" ;
129+ modal . style . zIndex = "0" ;
130+ let type = modal . dataset . type || "default" ;
131+ if ( ! minimizedModalsByType [ type ] ) {
132+ minimizedModalsByType [ type ] = [ ] ;
133+ }
134+ const arr = minimizedModalsByType [ type ] ;
135+ const index = arr . length ;
136+ arr . push ( modal ) ;
137+ const spacing = 10 ;
138+ const modalWidth = 200 ;
139+ let left = 10 + index * ( modalWidth + spacing ) ;
140+ const maxLeft = window . innerWidth - modalWidth - 10 ;
141+ if ( left > maxLeft ) left = maxLeft ;
142+ modal . style . left = `${ left } px` ;
143+ modal . classList . add ( "rounded-xl" ) ;
144+ const title = modal . querySelector ( ".font-semibold" ) ;
145+ if ( title ) {
146+ title . classList . add ( "truncate" , "text-sm" ) ;
147+ }
148+ const restoreHandler = ( e ) => {
149+ modal . style . transition = "all 0.3s ease" ;
150+ modal . style . height = "" ;
151+ modal . style . width = "100%" ;
152+ modal . style . left = "0" ;
153+ modal . style . zIndex = "50" ;
154+ modal . classList . remove ( "rounded-xl" ) ;
155+ if ( title ) {
156+ title . classList . remove ( "truncate" , "text-sm" ) ;
157+ }
158+ modal . removeEventListener ( "click" , restoreHandler ) ;
159+ this . _removeMinimized ( modal ) ;
160+ } ;
161+ modal . addEventListener ( "click" , restoreHandler ) ;
162+ modal . _restoreHandler = restoreHandler ;
163+ } ,
164+
165+ _removeMinimized ( modal ) {
166+ let type = modal . dataset . type || "default" ;
167+ if ( minimizedModalsByType [ type ] ) {
168+ minimizedModalsByType [ type ] = minimizedModalsByType [ type ] . filter (
169+ ( m ) => m !== modal
170+ ) ;
171+ minimizedModalsByType [ type ] . forEach ( ( m , i ) => {
172+ const spacing = 10 ;
173+ const modalWidth = 200 ;
174+ let left = 10 + i * ( modalWidth + spacing ) ;
175+ const maxLeft = window . innerWidth - modalWidth - 10 ;
176+ if ( left > maxLeft ) left = maxLeft ;
177+ m . style . left = `${ left } px` ;
178+ } ) ;
179+ }
180+ } ,
181+
110182 setNoSelect ( ) {
111183 document . body . style . userSelect = "none" ;
112184 } ,
0 commit comments