| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- import { LOCAL_STORAGE_KEYS, useBreakpoint, useParams } from 'common'
- import { useRouter } from 'next/router'
- import { PropsWithChildren, useEffect, useState } from 'react'
- import { ResizablePanel, ResizablePanelGroup, SidebarProvider } from 'ui'
- import { BannerStack } from '../ui/BannerStack/BannerStack'
- import { LayoutHeader } from './Navigation/LayoutHeader/LayoutHeader'
- import MobileNavigationBar from './Navigation/NavigationBar/MobileNavigationBar'
- import { MobileSheetProvider } from './Navigation/NavigationBar/MobileSheetContext'
- import { StudioMobileSheetNav } from './Navigation/NavigationBar/StudioMobileSheetNav'
- import { LayoutSidebar } from './ProjectLayout/LayoutSidebar'
- import { LayoutSidebarProvider } from './ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
- import { ProjectContextProvider } from './ProjectLayout/ProjectContext'
- import { AppBannerWrapper } from '@/components/interfaces/App/AppBannerWrapper'
- import { Sidebar } from '@/components/interfaces/Sidebar'
- import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
- import { useCheckLatestDeploy } from '@/hooks/use-check-latest-deploy'
- import { IS_PLATFORM } from '@/lib/constants'
- import { useAppStateSnapshot } from '@/state/app-state'
- export interface DefaultLayoutProps {
- headerTitle?: string
- hideMobileMenu?: boolean
- }
- /**
- * Base layout for all project pages in the dashboard, rendered as the first child on all page files within a project.
- *
- * A second layout as the child to this is required, and the layout depends on which section of the dashboard the page is on. (e.g Auth - AuthLayout)
- *
- * The base layout handles rendering the following UI components:
- * - App banner (e.g for notices or incidents)
- * - Mobile navigation bar
- * - First level side navigation bar (e.g For navigating to Table Editor, SQL Editor, Database page, etc)
- */
- export const DefaultLayout = ({
- children,
- headerTitle,
- hideMobileMenu,
- }: PropsWithChildren<DefaultLayoutProps>) => {
- const { ref } = useParams()
- const router = useRouter()
- const appSnap = useAppStateSnapshot()
- const [lastVisitedOrganization] = useLocalStorageQuery(
- LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION,
- ''
- )
- const backToDashboardURL = router.pathname.startsWith('/account')
- ? appSnap.lastRouteBeforeVisitingAccountPage.length > 0
- ? appSnap.lastRouteBeforeVisitingAccountPage
- : IS_PLATFORM && !!lastVisitedOrganization
- ? `/org/${lastVisitedOrganization}`
- : IS_PLATFORM
- ? '/organizations'
- : '/project/default'
- : undefined
- useCheckLatestDeploy()
- const isMobile = useBreakpoint('md')
- const contentMinSizePercentage = 50
- const contentMaxSizePercentage = 70
- const [isMounted, setIsMounted] = useState(false)
- useEffect(() => {
- setIsMounted(true)
- }, [])
- // This is required to prevent layout shift when rendering resizable panels (they initially render at 50%, then shift
- // to whatever is specified).
- if (!isMounted) {
- return null
- }
- return (
- <SidebarProvider defaultOpen={false}>
- <LayoutSidebarProvider>
- <ProjectContextProvider projectRef={ref}>
- <MobileSheetProvider>
- <div className="flex flex-col h-screen w-screen">
- {/* Top Banner */}
- <AppBannerWrapper />
- <div className="shrink-0">
- {isMobile && (
- <MobileNavigationBar
- hideMobileMenu={hideMobileMenu}
- backToDashboardURL={backToDashboardURL}
- />
- )}
- <LayoutHeader headerTitle={headerTitle} backToDashboardURL={backToDashboardURL} />
- </div>
- {/* Main Content Area */}
- <div className="flex flex-1 w-full overflow-y-hidden">
- {/* Sidebar - Only show for project pages, not account pages */}
- {!router.pathname.startsWith('/account') && <Sidebar />}
- {/* Main Content with Layout Sidebar */}
- <ResizablePanelGroup
- orientation="horizontal"
- className="h-full w-full overflow-x-hidden flex-1 flex flex-row gap-0"
- autoSaveId="default-layout-content"
- >
- <ResizablePanel
- id="panel-content"
- className="w-full"
- minSize={`${contentMinSizePercentage}`}
- maxSize={`${contentMaxSizePercentage}`}
- defaultSize={`${contentMaxSizePercentage}`}
- >
- <div className="h-full overflow-y-auto">{children}</div>
- </ResizablePanel>
- <LayoutSidebar
- minSize={`${100 - contentMaxSizePercentage}`}
- maxSize={`${100 - contentMinSizePercentage}`}
- defaultSize={`${100 - contentMaxSizePercentage}`}
- />
- </ResizablePanelGroup>
- </div>
- </div>
- <BannerStack />
- <StudioMobileSheetNav />
- </MobileSheetProvider>
- </ProjectContextProvider>
- </LayoutSidebarProvider>
- </SidebarProvider>
- )
- }
- export default DefaultLayout
|