EditorBaseLayout.tsx81 lines · main
1import { useParams } from 'common'
2import { usePathname } from 'next/navigation'
3import { ComponentProps, ReactNode } from 'react'
4import { cn } from 'ui'
5
6import { ProjectLayoutWithAuth } from '../ProjectLayout'
7import { CollapseButton } from '../Tabs/CollapseButton'
8import { EditorTabs } from '../Tabs/Tabs'
9import { useEditorType } from './EditorsLayout.hooks'
10import { useTabsStateSnapshot } from '@/state/tabs'
11
12export interface ExplorerLayoutProps extends ComponentProps<typeof ProjectLayoutWithAuth> {
13 children: ReactNode
14 title?: string
15 product?: string
16 productMenuClassName?: string
17}
18
19export const EditorBaseLayout = ({
20 children,
21 title,
22 product,
23 productMenuClassName,
24 productMenu,
25 browserTitle,
26}: ExplorerLayoutProps) => {
27 const { ref } = useParams()
28 const pathname = usePathname()
29 const editor = useEditorType()
30 const tabs = useTabsStateSnapshot()
31
32 const hasNoOpenTabs =
33 editor === 'table' ? tabs.openTabs.filter((x) => !x.startsWith('sql')).length === 0 : false
34 const hideTabs =
35 pathname === `/project/${ref}/editor` || pathname === `/project/${ref}/sql` || hasNoOpenTabs
36
37 const activeEditorTab = tabs.activeTab ? tabs.tabsMap[tabs.activeTab] : undefined
38 // Prefer the live tab label so browser titles update immediately after a rename,
39 // even when persisted tab metadata is still catching up.
40 const activeEditorTabLabel = activeEditorTab?.label ?? activeEditorTab?.metadata?.name
41 const activeEditorTabEntity =
42 activeEditorTab === undefined
43 ? undefined
44 : editor === 'sql'
45 ? activeEditorTab.type === 'sql'
46 ? activeEditorTabLabel
47 : undefined
48 : editor === 'table'
49 ? activeEditorTab.type !== 'sql'
50 ? activeEditorTabLabel
51 : undefined
52 : undefined
53
54 const mergedBrowserTitle = {
55 ...browserTitle,
56 section: title ?? browserTitle?.section,
57 entity: browserTitle?.entity ?? activeEditorTabEntity,
58 }
59
60 return (
61 <ProjectLayoutWithAuth
62 resizableSidebar
63 product={product}
64 browserTitle={mergedBrowserTitle}
65 productMenuClassName={productMenuClassName}
66 productMenu={productMenu}
67 >
68 <div className="flex flex-col h-full">
69 <div
70 className={cn(
71 'h-10 md:min-h-(--header-height) flex items-center',
72 !hideTabs ? 'bg-surface-200 dark:bg-alternative' : 'bg-surface-100'
73 )}
74 >
75 {hideTabs ? <CollapseButton hideTabs={hideTabs} /> : <EditorTabs />}
76 </div>
77 <div className="h-full">{children}</div>
78 </div>
79 </ProjectLayoutWithAuth>
80 )
81}