mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
feat: add resizable inner sidebar (#21548)
* init * update import names * Update resizable.tsx * resizable bg now goes lighter on drag * only resizable for table editor and sql editor * Update ProjectLayout.tsx * Update index.tsx * Remove unneeded console.log. --------- Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
This commit is contained in:
1 parent
7c7b10d83d
commit
e1bbdd0ca7
7 files changed
+72
-44
No files matched your search
@@ -8,7 +8,7 @@ const ProductMenuBar = ({ title, children }: PropsWithChildren<ProductMenuBarPro
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'hide-scrollbar flex w-64 flex-col border-r', // Layout
|
||||
'hide-scrollbar flex flex-col w-full h-full', // Layout
|
||||
'bg-studio',
|
||||
'border-default ',
|
||||
].join(' ')}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ProjectContextProvider } from './ProjectContext'
|
||||
import ProjectPausedState from './ProjectPausedState'
|
||||
import RestoringState from './RestoringState'
|
||||
import UpgradingState from './UpgradingState'
|
||||
import { ResizableHandle, ResizablePanelGroup, ResizablePanel, cn } from 'ui'
|
||||
|
||||
// [Joshen] This is temporary while we unblock users from managing their project
|
||||
// if their project is not responding well for any reason. Eventually needs a bit of an overhaul
|
||||
@@ -57,6 +58,7 @@ export interface ProjectLayoutProps {
|
||||
hideHeader?: boolean
|
||||
hideIconBar?: boolean
|
||||
selectedTable?: string
|
||||
resizableSidebar?: boolean
|
||||
}
|
||||
|
||||
const ProjectLayout = ({
|
||||
@@ -69,6 +71,7 @@ const ProjectLayout = ({
|
||||
hideHeader = false,
|
||||
hideIconBar = false,
|
||||
selectedTable,
|
||||
resizableSidebar = false,
|
||||
}: PropsWithChildren<ProjectLayoutProps>) => {
|
||||
const router = useRouter()
|
||||
const { ref: projectRef } = useParams()
|
||||
@@ -105,26 +108,46 @@ const ProjectLayout = ({
|
||||
{/* Left-most navigation side bar to access products */}
|
||||
{!hideIconBar && <NavigationBar />}
|
||||
{/* Product menu bar */}
|
||||
{!showPausedState && (
|
||||
<MenuBarWrapper isLoading={isLoading} isBlocking={isBlocking} productMenu={productMenu}>
|
||||
<ProductMenuBar title={product}>{productMenu}</ProductMenuBar>
|
||||
</MenuBarWrapper>
|
||||
)}
|
||||
<main className="flex flex-col flex-1 w-full overflow-x-hidden">
|
||||
{!navLayoutV2 && !hideHeader && IS_PLATFORM && <LayoutHeader />}
|
||||
{showPausedState ? (
|
||||
<div className="mx-auto my-16 w-full h-full max-w-7xl flex items-center">
|
||||
<div className="w-full">
|
||||
<ProjectPausedState product={product} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<ContentWrapper isLoading={isLoading} isBlocking={isBlocking}>
|
||||
<ResourceExhaustionWarningBanner />
|
||||
{children}
|
||||
</ContentWrapper>
|
||||
<ResizablePanelGroup
|
||||
className="flex h-full"
|
||||
direction="horizontal"
|
||||
autoSaveId="project-layout"
|
||||
>
|
||||
{!showPausedState && productMenu && (
|
||||
<>
|
||||
<ResizablePanel
|
||||
className={cn(resizableSidebar ? 'min-w-64 max-w-[32rem]' : 'min-w-64 max-w-64')}
|
||||
defaultSize={1} // forces panel to smallest width possible, at w-64
|
||||
>
|
||||
<MenuBarWrapper
|
||||
isLoading={isLoading}
|
||||
isBlocking={isBlocking}
|
||||
productMenu={productMenu}
|
||||
>
|
||||
<ProductMenuBar title={product}>{productMenu}</ProductMenuBar>
|
||||
</MenuBarWrapper>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle disabled={resizableSidebar ? false : true} />
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
<ResizablePanel className="h-full">
|
||||
<main className="h-full flex flex-col flex-1 w-full overflow-x-hidden">
|
||||
{!navLayoutV2 && !hideHeader && IS_PLATFORM && <LayoutHeader />}
|
||||
{showPausedState ? (
|
||||
<div className="mx-auto my-16 w-full h-full max-w-7xl flex items-center">
|
||||
<div className="w-full">
|
||||
<ProjectPausedState product={product} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<ContentWrapper isLoading={isLoading} isBlocking={isBlocking}>
|
||||
<ResourceExhaustionWarningBanner />
|
||||
{children}
|
||||
</ContentWrapper>
|
||||
)}
|
||||
</main>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</div>
|
||||
|
||||
<EnableBranchingModal />
|
||||
|
||||
@@ -17,6 +17,7 @@ const SQLEditorLayout = ({ title, children }: SQLEditorLayoutProps) => {
|
||||
product="SQL Editor"
|
||||
productMenu={productMenu}
|
||||
isBlocking={false}
|
||||
resizableSidebar
|
||||
>
|
||||
{children}
|
||||
</ProjectLayout>
|
||||
|
||||
@@ -23,7 +23,12 @@ const TableEditorLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<ProjectLayoutWithAuth product="Table Editor" productMenu={tableEditorMenu} isBlocking={false}>
|
||||
<ProjectLayoutWithAuth
|
||||
product="Table Editor"
|
||||
productMenu={tableEditorMenu}
|
||||
isBlocking={false}
|
||||
resizableSidebar
|
||||
>
|
||||
{children}
|
||||
</ProjectLayoutWithAuth>
|
||||
)
|
||||
|
||||
Generated
+4
-20
@@ -838,7 +838,6 @@
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-simple-maps": "4.0.0-beta.6",
|
||||
"react-split": "^2.0.13",
|
||||
"react-tracked": "^1.7.11",
|
||||
"react-virtualized-auto-sizer": "^1.0.20",
|
||||
"react-window": "^1.8.6",
|
||||
@@ -30237,9 +30236,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-resizable-panels": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.0.9.tgz",
|
||||
"integrity": "sha512-ZylBvs7oG7Y/INWw3oYGolqgpFvoPW8MPeg9l1fURDeKpxrmUuCHBUmPj47BdZ11MODImu3kZYXG85rbySab7w==",
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.0.11.tgz",
|
||||
"integrity": "sha512-tA3OvGFEK/U9rKuEg6TpXcr+i+cN5X8B4UIvs7jqr5lby629pDTGvqRjo1EJLhBpRZfkg0Zz1INJlSYigaS99g==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0"
|
||||
@@ -30306,17 +30305,6 @@
|
||||
"react-dom": ">=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-split": {
|
||||
"version": "2.0.14",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.5.7",
|
||||
"split.js": "^1.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-style-singleton": {
|
||||
"version": "2.2.1",
|
||||
"license": "MIT",
|
||||
@@ -32990,10 +32978,6 @@
|
||||
"tiny-updater": "^3.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/split.js": {
|
||||
"version": "1.6.5",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"dev": true,
|
||||
@@ -37662,7 +37646,7 @@
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-resizable-panels": "^2.0.9",
|
||||
"react-resizable-panels": "^2.0.11",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tooltip": "^4.2.17",
|
||||
"reactflow": "^11.10.1",
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-resizable-panels": "^2.0.9",
|
||||
"react-resizable-panels": "^2.0.11",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tooltip": "^4.2.17",
|
||||
"reactflow": "^11.10.1",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import { GripVertical } from 'lucide-react'
|
||||
import * as ResizablePrimitive from 'react-resizable-panels'
|
||||
|
||||
import { cn } from '../../../lib/utils/cn'
|
||||
|
||||
const ResizablePanelGroup = ({
|
||||
@@ -24,16 +27,28 @@ const ResizableHandle = ({
|
||||
<ResizablePrimitive.PanelResizeHandle
|
||||
className={cn(
|
||||
'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
|
||||
'data-[resize-handle-state=drag]:bg-border-strong',
|
||||
'group',
|
||||
'transition-colors',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{withHandle && (
|
||||
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
|
||||
<div
|
||||
className={cn(
|
||||
'z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border focus:bg-surface-400',
|
||||
'opacity-0 transition-opacity duration-200',
|
||||
'group-data-[resize-handle-state=hover]:opacity-100',
|
||||
'hover:bg-surface-400',
|
||||
'group-data-[resize-handle-state=drag]:opacity-100',
|
||||
'group-data-[resize-handle-state=drag]:bg-foreground-muted'
|
||||
)}
|
||||
>
|
||||
<GripVertical className="h-2.5 w-2.5" />
|
||||
</div>
|
||||
)}
|
||||
</ResizablePrimitive.PanelResizeHandle>
|
||||
)
|
||||
|
||||
export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
|
||||
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
|
||||
Reference in new issue
Block a user