import * as React from 'react' import ChartPanel from '../ChartPanel' import ReactSplitPaneImport from 'react-split-pane' import Tree from '../Tree' import { AppState } from '../../reducers' import { ChartParameters } from '../../reducers/Charts' import { connect } from 'react-redux' import { List } from 'immutable' import { Sidebar } from '../Sidebar' import { useResizeDetector } from 'react-resize-detector' import MobileTabs from './MobileTabs' // Type cast to any to work around React 18 compatibility issues with react-split-pane 0.1.x const ReactSplitPane = ReactSplitPaneImport as any interface Props { heightProperty: any paneDefaults: any connectionId?: string chartPanelItems: List } function ContentView(props: Props) { // Use different defaults for mobile viewports (<=768px width) // Use state for mobile detection that updates on resize const [isMobile, setIsMobile] = React.useState(() => typeof window !== 'undefined' && window.innerWidth <= 768) const [mobileTab, setMobileTab] = React.useState(0) // 0 = topics, 1 = details const [height, setHeight] = React.useState('100%') const [sidebarWidth, setSidebarWidth] = React.useState(isMobile ? '100%' : '40%') const [detectedHeight, setDetectedHeight] = React.useState(0) const [detectedSidebarWidth, setDetectedSidebarWidth] = React.useState(0) // Update mobile state on resize React.useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth <= 768) } // Set initial state handleResize() window.addEventListener('resize', handleResize) return () => window.removeEventListener('resize', handleResize) }, []) const { height: resizeHeight, ref: heightRef } = useResizeDetector() const { width: resizeWidth, ref: widthRef } = useResizeDetector() React.useEffect(() => { if (resizeHeight) setDetectedHeight(resizeHeight) }, [resizeHeight]) React.useEffect(() => { if (resizeWidth) setDetectedSidebarWidth(resizeWidth) }, [resizeWidth]) const detectSize = React.useCallback((width: any, newHeight: any) => { setDetectedHeight(newHeight) }, []) const detectSidebarSize = React.useCallback((width: any) => { setDetectedSidebarWidth(width) }, []) const closeDrawerCompletelyIfItSitsOnTheEdge = React.useCallback(() => { if (detectedHeight < 30) { setHeight('100%') } }, [detectedHeight]) const closeSidebarCompletelyIfItSitsOnTheEdge = React.useCallback(() => { if (detectedSidebarWidth < 30) { setSidebarWidth('0%') } }, [detectedSidebarWidth]) // Open chart panel on start and when a new chart is added but the panel is closed React.useEffect(() => { const almostClosed = !isNaN(height as any) && detectedHeight < 30 if ((!height || height === '100%' || almostClosed) && props.chartPanelItems.count() > 0) { setHeight('calc(100% - 250px)') } if (props.chartPanelItems.count() === 0) { setHeight('100%') } }, [props.chartPanelItems]) // Mobile view with tab switcher if (isMobile) { // Expose tab switching functions for other components to call React.useEffect(() => { if (typeof window !== 'undefined') { (window as any).switchToDetailsTab = () => setMobileTab(1) (window as any).switchToTopicsTab = () => setMobileTab(0) } return () => { if (typeof window !== 'undefined') { delete (window as any).switchToDetailsTab delete (window as any).switchToTopicsTab } } }, []) const mobileContainerStyle: React.CSSProperties = { display: 'flex', flexDirection: 'column', height: 'calc(100vh - 64px)', // Full viewport minus titlebar width: '100%', } const tabContentStyle: React.CSSProperties = { flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, // Critical for flex children with overflow width: '100%', overflow: 'hidden', position: 'relative', } // Tree container needs explicit height for the Tree component's height: 100% to work const treeContainerStyle: React.CSSProperties = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, width: '100%', height: '100%', } const sidebarContainerStyle: React.CSSProperties = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, width: '100%', height: '100%', overflow: 'auto', } return (
{/* Topics tab */} {mobileTab === 0 && (
)} {/* Details tab */} {mobileTab === 1 && (
)}
) } // Desktop view with split panes return (
setSidebarWidth(size)} onDragFinished={closeSidebarCompletelyIfItSitsOnTheEdge} allowResize={true} style={{ height: '100%' }} pane1Style={{ overflowX: 'hidden' }} resizerStyle={{ height: '100%' }} > setHeight(size)} onDragFinished={closeDrawerCompletelyIfItSitsOnTheEdge} > {/** Passing height constraints via flex options down */}
{/** Resize detector must not be in the scroll zone, it needs to detect actual available size */}
) } const mapStateToProps = (state: AppState) => { return { chartPanelItems: state.charts.get('charts'), } } export default connect(mapStateToProps)(ContentView)