mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 20:35:07 +03:00
mobile nav
This commit is contained in:
2 files changed
+80
-28
No files matched your search
@@ -1,15 +1,20 @@
|
||||
import { useParams } from 'common'
|
||||
import { Plug } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { parseAsBoolean, useQueryState } from 'nuqs'
|
||||
import { Button, cn, Sidebar, SidebarContent, SidebarHeader } from 'ui'
|
||||
import { ShimmeringLoader } from 'ui-patterns'
|
||||
|
||||
import { NavGroup } from './NavGroup'
|
||||
import { useAppSidebarNavItems, type AppSidebarScope } from './useAppSidebarNavItems'
|
||||
import { ConnectSheet } from '@/components/interfaces/ConnectSheet/ConnectSheet'
|
||||
import { OrgSelector } from '@/components/layouts/Navigation/NavigationBar/OrgSelector'
|
||||
import { ProjectBranchSelector } from '@/components/layouts/Navigation/NavigationBar/ProjectBranchSelector'
|
||||
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
|
||||
import { useProjectDetailQuery } from '@/data/projects/project-detail-query'
|
||||
import { useHideSidebar } from '@/hooks/misc/useHideSidebar'
|
||||
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
||||
import { IS_PLATFORM } from '@/lib/constants'
|
||||
|
||||
export type { AppSidebarScope }
|
||||
@@ -28,6 +33,8 @@ function AppSidebarNavBody({ scope, variant = 'desktop' }: AppSidebarNavBodyProp
|
||||
const [, setShowConnect] = useQueryState('showConnect', parseAsBoolean.withDefault(false))
|
||||
const { slug: orgRouteSlug } = useParams()
|
||||
const { data: selectedOrganization } = useSelectedOrganizationQuery()
|
||||
const { isPending: isLoadingOrganizations } = useOrganizationsQuery()
|
||||
const { data: project, isPending: isLoadingProject } = useSelectedProjectQuery()
|
||||
|
||||
const {
|
||||
isProjectScope,
|
||||
@@ -40,31 +47,57 @@ function AppSidebarNavBody({ scope, variant = 'desktop' }: AppSidebarNavBodyProp
|
||||
organizationItems,
|
||||
} = useAppSidebarNavItems({ scope })
|
||||
|
||||
const isMobileSheet = variant === 'mobile-sheet'
|
||||
const selectorHeaderClass = cn('flex-col gap-2', isMobileSheet ? 'flex' : 'hidden md:flex')
|
||||
const isBranch = project != null && project.parentRef !== project.ref
|
||||
const { data: parentProject, isPending: isLoadingParentProject } = useProjectDetailQuery(
|
||||
{ ref: project?.parent_project_ref },
|
||||
{ enabled: Boolean(isProjectScope && isBranch && project?.parent_project_ref) }
|
||||
)
|
||||
const selectedProject = parentProject ?? project
|
||||
|
||||
const isOrgSelectorLoading = isLoadingOrganizations
|
||||
const isProjectSelectorLoading =
|
||||
isLoadingProject || (isBranch && isLoadingParentProject) || !selectedProject
|
||||
|
||||
const shouldShowOrgSelector =
|
||||
!isProjectScope && IS_PLATFORM && (Boolean(orgRouteSlug) || Boolean(selectedOrganization))
|
||||
|
||||
const isHeaderLoading =
|
||||
(shouldShowOrgSelector && isOrgSelectorLoading) || (isProjectScope && isProjectSelectorLoading)
|
||||
|
||||
const isMobileSheet = variant === 'mobile-sheet'
|
||||
const selectorHeaderClass = cn('flex-col gap-2', isMobileSheet ? 'flex' : 'hidden md:flex')
|
||||
|
||||
return (
|
||||
<>
|
||||
<SidebarHeader className={selectorHeaderClass}>
|
||||
{shouldShowOrgSelector && <OrgSelector />}
|
||||
{isProjectScope && (
|
||||
{isHeaderLoading ? (
|
||||
<ShimmeringLoader
|
||||
className={
|
||||
isProjectScope
|
||||
? 'p-2 md:mr-2 md:w-[90px]'
|
||||
: cn('p-2 md:mr-2 w-[90px]', isMobileSheet && 'w-full max-w-none')
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<ProjectBranchSelector />
|
||||
<div className="flex items-center px-0.5">
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
disabled={!isActiveHealthy}
|
||||
onClick={() => setShowConnect(true)}
|
||||
className="h-7 flex-1 justify-center gap-0 pl-2"
|
||||
icon={<Plug className="rotate-90" strokeWidth={1.5} />}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
{shouldShowOrgSelector && <OrgSelector />}
|
||||
{isProjectScope && (
|
||||
<>
|
||||
<ProjectBranchSelector />
|
||||
<div className="flex items-center px-0.5">
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
disabled={!isActiveHealthy}
|
||||
onClick={() => setShowConnect(true)}
|
||||
className="h-7 flex-1 justify-center gap-0 pl-2"
|
||||
icon={<Plug className="rotate-90" strokeWidth={1.5} />}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</SidebarHeader>
|
||||
@@ -125,12 +158,17 @@ export function AppSidebarV2({ scope }: AppSidebarV2Props = {}) {
|
||||
|
||||
/**
|
||||
* Full-height V2 navigation for `StudioMobileSheetNav`, opened via `registerOpenMenu` from
|
||||
* {@link ProjectLayoutV2}. Mirrors desktop {@link AppSidebarV2} structure.
|
||||
* {@link ProjectLayoutV2}. Scope follows the current route like {@link DefaultLayoutV2}.
|
||||
*/
|
||||
export function AppSidebarMobileSheetMenu() {
|
||||
const router = useRouter()
|
||||
const sheetScope: AppSidebarScope = router.pathname.startsWith('/project')
|
||||
? 'project'
|
||||
: 'organization'
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-0 flex-col bg-sidebar text-foreground">
|
||||
<AppSidebarNavBody scope="project" variant="mobile-sheet" />
|
||||
<AppSidebarNavBody scope={sheetScope} variant="mobile-sheet" />
|
||||
<ConnectSheet />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ import { useEditorType } from '../editors/EditorsLayout.hooks'
|
||||
import { useSetMainScrollContainer } from '../MainScrollContainerContext'
|
||||
import { useMobileSheet } from '../Navigation/NavigationBar/MobileSheetContext'
|
||||
import ProductMenuBar from '../Navigation/ProductMenuBar'
|
||||
import { AppSidebarMobileSheetMenu } from '../NavigationV2/AppSidebar'
|
||||
import BuildingState from './BuildingState'
|
||||
import ConnectingState from './ConnectingState'
|
||||
import { getSectionKeyFromPathname, MobileMenuContent } from './LayoutHeader/MobileMenuContent'
|
||||
@@ -37,6 +38,7 @@ import RestartingState from './RestartingState'
|
||||
import { RestoreFailedState } from './RestoreFailedState'
|
||||
import { RestoringState } from './RestoringState'
|
||||
import { UpgradingState } from './UpgradingState'
|
||||
import { useIsNavigationV2Enabled } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { CreateBranchModal } from '@/components/interfaces/BranchManagement/CreateBranchModal'
|
||||
import { ProjectAPIDocs } from '@/components/interfaces/ProjectAPIDocs/ProjectAPIDocs'
|
||||
import { BannerFreeMicroUpgrade } from '@/components/ui/BannerStack/Banners/BannerFreeMicroUpgrade'
|
||||
@@ -134,6 +136,7 @@ export const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<Projec
|
||||
)
|
||||
const { showSidebar } = useAppStateSnapshot()
|
||||
const { setContent: setMobileSheetContent, registerOpenMenu } = useMobileSheet()
|
||||
const isNavigationV2 = useIsNavigationV2Enabled()
|
||||
|
||||
const pathname = getPathnameWithoutQuery(router.asPath, router.pathname)
|
||||
const currentSectionKey = getSectionKeyFromPathname(pathname)
|
||||
@@ -199,17 +202,28 @@ export const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<Projec
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const unregister = registerOpenMenu(() => {
|
||||
setMobileSheetContent(
|
||||
<MobileMenuContent
|
||||
currentProductMenu={productMenu ?? null}
|
||||
currentProduct={product}
|
||||
currentSectionKey={currentSectionKey}
|
||||
onCloseSheet={() => setMobileSheetContent(null)}
|
||||
/>
|
||||
)
|
||||
if (isNavigationV2) {
|
||||
setMobileSheetContent(<AppSidebarMobileSheetMenu />)
|
||||
} else {
|
||||
setMobileSheetContent(
|
||||
<MobileMenuContent
|
||||
currentProductMenu={productMenu ?? null}
|
||||
currentProduct={product}
|
||||
currentSectionKey={currentSectionKey}
|
||||
onCloseSheet={() => setMobileSheetContent(null)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
return unregister
|
||||
}, [registerOpenMenu, productMenu, product, currentSectionKey, setMobileSheetContent])
|
||||
}, [
|
||||
registerOpenMenu,
|
||||
productMenu,
|
||||
product,
|
||||
currentSectionKey,
|
||||
setMobileSheetContent,
|
||||
isNavigationV2,
|
||||
])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in new issue
Block a user