@@ -19,130 +19,103 @@ export function AnimatedSidepanelContainer({
1919 const panelNode = content ?? sidepanel ;
2020
2121 const [ mounted , setMounted ] = React . useState ( false ) ;
22- const [ isMobile , setIsMobile ] = React . useState < boolean > ( false ) ;
2322 const groupRef = React . useRef < ImperativePanelGroupHandle > ( null ) ;
2423
2524 React . useEffect ( ( ) => {
2625 setMounted ( true ) ;
2726 } , [ ] ) ;
2827
29- React . useLayoutEffect ( ( ) => {
30- const mql = window . matchMedia ( "(max-width: 1023px)" ) ;
31- const onChange = ( e : MediaQueryListEvent ) => {
32- setIsMobile ( e . matches ) ;
33- } ;
34- setIsMobile ( mql . matches ) ;
35- if ( typeof mql . addEventListener === "function" ) {
36- mql . addEventListener ( "change" , onChange ) ;
37- return ( ) => {
38- mql . removeEventListener ( "change" , onChange ) ;
39- } ;
40- } else if ( typeof ( mql as any ) . addListener === "function" ) {
41- ( mql as any ) . addListener ( onChange ) ;
42- return ( ) => ( mql as any ) . removeListener ( onChange ) ;
43- }
44- return ( ) => {
45- void mql . matches ;
46- } ;
47- } , [ ] ) ;
48-
4928 React . useEffect ( ( ) => {
50- if ( ! mounted || isMobile ) return ;
29+ if ( ! mounted ) return ;
5130
5231 if ( groupRef . current ) {
5332 groupRef . current . setLayout ( panelOpen ? [ 70 , 30 ] : [ 100 , 0 ] ) ;
5433 }
55- } , [ panelOpen , mounted , isMobile ] ) ;
56-
57- if ( ! mounted ) {
58- return < div className = "flex min-w-0 flex-1 md:pr-2" > { children } </ div > ;
59- }
34+ } , [ panelOpen , mounted ] ) ;
6035
61- if ( isMobile ) {
62- return (
63- < >
64- { children }
65- < div
66- aria-hidden
67- className = { cn (
68- "fixed inset-0 z-[80] bg-black/10 backdrop-blur-sm transition-opacity duration-200" ,
69- panelOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
70- ) }
71- onClick = { ( ) => {
72- clear ( ) ;
73- } }
74- />
75- < div
76- role = "dialog"
77- aria-modal = "true"
36+ return (
37+ < >
38+ { /* Desktop layout: resizable panels (hidden on mobile) */ }
39+ < PanelGroup ref = { groupRef } direction = "horizontal" className = "hidden md:flex md:flex-1" >
40+ < Panel defaultSize = { 100 } minSize = { 30 } className = "h-full overflow-hidden" >
41+ < div className = "flex min-w-0 flex-1 h-full" > { children } </ div >
42+ </ Panel >
43+ < PanelResizeHandle
7844 className = { cn (
79- "fixed inset-x-0 bottom-0 z-[90] origin-bottom rounded-t-2xl bg-[var(--gray-100)] shadow-2xl transition-transform duration-300 ease-out" ,
80- "max-h-[80vh] w-full" ,
81- panelOpen ? "translate-y-0" : "translate-y-full"
45+ "group relative w-4 bg-transparent transition-opacity duration-200" ,
46+ ! panelOpen && "pointer-events-none opacity-0"
8247 ) }
8348 >
84- < div className = "h-full max-h-[calc(80vh-0.5rem)] overflow-y-auto p-4" >
85- < div className = "w-full" > { panelNode } </ div >
49+ < div className = "absolute inset-y-0 left-1 flex flex-col items-center justify-center" >
50+ < div
51+ className = "absolute top-6 bottom-0 w-px transition-colors duration-200"
52+ style = { {
53+ background : "transparent"
54+ } }
55+ />
56+ < div
57+ className = "absolute top-6 bottom-0 w-px opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-data-[resize-handle-active]:opacity-100"
58+ style = { {
59+ background :
60+ "linear-gradient(to bottom, transparent 0%, var(--primary) 64px, var(--primary) 100%)"
61+ } }
62+ />
63+ < div
64+ className = "relative z-10 h-6 w-2 rounded-full border transition-colors duration-200"
65+ style = { {
66+ background : "var(--sidebar)" ,
67+ borderColor : "var(--gray-500)"
68+ } }
69+ />
70+ < div
71+ className = "absolute z-10 h-6 w-2 rounded-full border opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-data-[resize-handle-active]:opacity-100"
72+ style = { {
73+ background : "var(--primary)" ,
74+ borderColor : "var(--primary)"
75+ } }
76+ />
8677 </ div >
87- </ div >
88- </ >
89- ) ;
90- }
78+ </ PanelResizeHandle >
79+ < Panel
80+ defaultSize = { 0 }
81+ minSize = { 0 }
82+ maxSize = { 50 }
83+ className = { cn ( "sidepanel-container" , panelOpen && "pr-2" ) }
84+ style = { { minWidth : panelOpen ? "320px" : "0px" } }
85+ >
86+ < div className = "h-full" >
87+ < div className = "h-full w-full overflow-y-auto bg-[var(--gray-100)] transition-all duration-500 ease-out md:rounded-t-2xl" >
88+ { panelNode }
89+ </ div >
90+ </ div >
91+ </ Panel >
92+ </ PanelGroup >
9193
92- return (
93- < PanelGroup ref = { groupRef } direction = "horizontal" className = "flex-1" >
94- < Panel defaultSize = { 100 } minSize = { 30 } className = "h-full overflow-hidden" >
95- < div className = "flex min-w-0 flex-1 h-full" > { children } </ div >
96- </ Panel >
97- < PanelResizeHandle
94+ { /* Mobile layout: bottom sheet (hidden on desktop) */ }
95+ < div className = "flex md:hidden flex-1" > { children } </ div >
96+ < div
97+ aria-hidden
9898 className = { cn (
99- "group relative w-4 bg-transparent transition-opacity duration-200" ,
100- ! panelOpen && "pointer-events-none opacity-0"
99+ "md:hidden fixed inset-0 z-[80] bg-black/10 backdrop-blur-sm transition-opacity duration-200" ,
100+ panelOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
101+ ) }
102+ onClick = { ( ) => {
103+ clear ( ) ;
104+ } }
105+ />
106+ < div
107+ role = "dialog"
108+ aria-modal = "true"
109+ className = { cn (
110+ "md:hidden fixed inset-x-0 bottom-0 z-[90] origin-bottom rounded-t-2xl bg-[var(--gray-100)] shadow-2xl transition-transform duration-300 ease-out" ,
111+ "max-h-[80vh] w-full" ,
112+ panelOpen ? "translate-y-0" : "translate-y-full"
101113 ) }
102114 >
103- < div className = "absolute inset-y-0 left-1 flex flex-col items-center justify-center" >
104- < div
105- className = "absolute top-6 bottom-0 w-px transition-colors duration-200"
106- style = { {
107- background : "transparent"
108- } }
109- />
110- < div
111- className = "absolute top-6 bottom-0 w-px opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-data-[resize-handle-active]:opacity-100"
112- style = { {
113- background :
114- "linear-gradient(to bottom, transparent 0%, var(--primary) 64px, var(--primary) 100%)"
115- } }
116- />
117- < div
118- className = "relative z-10 h-6 w-2 rounded-full border transition-colors duration-200"
119- style = { {
120- background : "var(--sidebar)" ,
121- borderColor : "var(--gray-500)"
122- } }
123- />
124- < div
125- className = "absolute z-10 h-6 w-2 rounded-full border opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-data-[resize-handle-active]:opacity-100"
126- style = { {
127- background : "var(--primary)" ,
128- borderColor : "var(--primary)"
129- } }
130- />
131- </ div >
132- </ PanelResizeHandle >
133- < Panel
134- defaultSize = { 0 }
135- minSize = { 0 }
136- maxSize = { 50 }
137- className = { cn ( "sidepanel-container" , panelOpen && "pr-2" ) }
138- style = { { minWidth : panelOpen ? "320px" : "0px" } }
139- >
140- < div className = "h-full" >
141- < div className = "h-full w-full overflow-y-auto bg-[var(--gray-100)] transition-all duration-500 ease-out md:rounded-t-2xl" >
142- { panelNode }
143- </ div >
115+ < div className = "h-full max-h-[calc(80vh-0.5rem)] overflow-y-auto p-4" >
116+ < div className = "w-full" > { panelNode } </ div >
144117 </ div >
145- </ Panel >
146- </ PanelGroup >
118+ </ div >
119+ </ >
147120 ) ;
148121}
0 commit comments