fix(sidebar): turn sidebar to responsive for mobile (#658)

This commit is contained in:
Guy Ben-Aharon
2025-04-13 16:23:49 +03:00
committed by GitHub
parent f15dc77f33
commit ce2389f135
7 changed files with 199 additions and 72 deletions

View File

@@ -11,6 +11,7 @@ import type { Diagram } from '@/lib/domain/diagram';
import { cn } from '@/lib/utils';
import { SidebarProvider } from '@/components/sidebar/sidebar';
import { EditorSidebar } from './editor-sidebar/editor-sidebar';
import { TopNavbar } from './top-navbar/top-navbar';
export interface EditorDesktopLayoutProps {
initialDiagram?: Diagram;
@@ -21,32 +22,35 @@ export const EditorDesktopLayout: React.FC<EditorDesktopLayoutProps> = ({
const { isSidePanelShowed } = useLayout();
return (
<SidebarProvider
defaultOpen={false}
open={false}
className="h-full min-h-0"
>
<EditorSidebar />
<ResizablePanelGroup direction="horizontal">
<ResizablePanel
defaultSize={25}
minSize={25}
maxSize={isSidePanelShowed ? 99 : 0}
className={cn('transition-[flex-grow] duration-200', {
'min-w-[350px]': isSidePanelShowed,
})}
>
<SidePanel />
</ResizablePanel>
<ResizableHandle
disabled={!isSidePanelShowed}
className={!isSidePanelShowed ? 'hidden' : ''}
/>
<ResizablePanel defaultSize={75}>
<Canvas initialTables={initialDiagram?.tables ?? []} />
</ResizablePanel>
</ResizablePanelGroup>
</SidebarProvider>
<>
<TopNavbar />
<SidebarProvider
defaultOpen={false}
open={false}
className="h-full min-h-0"
>
<EditorSidebar />
<ResizablePanelGroup direction="horizontal">
<ResizablePanel
defaultSize={25}
minSize={25}
maxSize={isSidePanelShowed ? 99 : 0}
className={cn('transition-[flex-grow] duration-200', {
'min-w-[350px]': isSidePanelShowed,
})}
>
<SidePanel />
</ResizablePanel>
<ResizableHandle
disabled={!isSidePanelShowed}
className={!isSidePanelShowed ? 'hidden' : ''}
/>
<ResizablePanel defaultSize={75}>
<Canvas initialTables={initialDiagram?.tables ?? []} />
</ResizablePanel>
</ResizablePanelGroup>
</SidebarProvider>
</>
);
};

View File

@@ -11,6 +11,9 @@ import {
} from '@/components/drawer/drawer';
import { Separator } from '@/components/separator/separator';
import type { Diagram } from '@/lib/domain/diagram';
import { TopNavbarMobile } from './top-navbar/top-navbar-mobile';
import { SidebarProvider } from '@/components/sidebar/sidebar';
import { EditorSidebar } from './editor-sidebar/editor-sidebar';
export interface EditorMobileLayoutProps {
initialDiagram?: Diagram;
@@ -21,19 +24,30 @@ export const EditorMobileLayout: React.FC<EditorMobileLayoutProps> = ({
const { isSidePanelShowed, hideSidePanel } = useLayout();
return (
<>
<Drawer open={isSidePanelShowed} onClose={() => hideSidePanel()}>
<DrawerContent className="h-full" fullScreen>
<DrawerHeader>
<DrawerTitle>Manage Diagram</DrawerTitle>
<DrawerDescription>
Manage your diagram objects
</DrawerDescription>
</DrawerHeader>
<Separator orientation="horizontal" />
<SidePanel data-vaul-no-drag />
</DrawerContent>
</Drawer>
<Canvas initialTables={initialDiagram?.tables ?? []} />
<SidebarProvider
defaultOpen={false}
open={false}
className="flex-col"
>
<EditorSidebar />
<TopNavbarMobile />
<Drawer
open={isSidePanelShowed}
onClose={() => hideSidePanel()}
>
<DrawerContent className="h-full" fullScreen>
<DrawerHeader>
<DrawerTitle>Manage Diagram</DrawerTitle>
<DrawerDescription>
Manage your diagram objects
</DrawerDescription>
</DrawerHeader>
<Separator orientation="horizontal" />
<SidePanel data-vaul-no-drag />
</DrawerContent>
</Drawer>
<Canvas initialTables={initialDiagram?.tables ?? []} />
</SidebarProvider>
</>
);
};

View File

@@ -1,5 +1,4 @@
import React, { Suspense, useCallback, useEffect, useRef } from 'react';
import { TopNavbar } from './top-navbar/top-navbar';
import { useParams } from 'react-router-dom';
import { useChartDB } from '@/hooks/use-chartdb';
import { useDialog } from '@/hooks/use-dialog';
@@ -30,6 +29,7 @@ import { CanvasProvider } from '@/context/canvas-context/canvas-provider';
import { HIDE_BUCKLE_DOT_DEV } from '@/lib/env';
import { useDiagramLoader } from './use-diagram-loader';
import { DiffProvider } from '@/context/diff-context/diff-provider';
import { TopNavbarMock } from './top-navbar/top-navbar-mock';
const OPEN_STAR_US_AFTER_SECONDS = 30;
const SHOW_STAR_US_AGAIN_AFTER_DAYS = 1;
@@ -166,12 +166,16 @@ const EditorPageComponent: React.FC = () => {
<section
className={`bg-background ${isDesktop ? 'h-screen w-screen' : 'h-dvh w-dvw'} flex select-none flex-col overflow-x-hidden`}
>
<TopNavbar />
<Suspense
fallback={
<div className="flex flex-1 items-center justify-center">
<Spinner size={isDesktop ? 'large' : 'medium'} />
</div>
<>
<TopNavbarMock />
<div className="flex flex-1 items-center justify-center">
<Spinner
size={isDesktop ? 'large' : 'medium'}
/>
</div>
</>
}
>
{isDesktop ? (

View File

@@ -5,7 +5,7 @@ import {
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
@@ -15,6 +15,10 @@ import { SquareStack, Table, Workflow } from 'lucide-react';
import { useLayout } from '@/hooks/use-layout';
import { useTranslation } from 'react-i18next';
import { DiscordLogoIcon } from '@radix-ui/react-icons';
import { useBreakpoint } from '@/hooks/use-breakpoint';
import ChartDBLogo from '@/assets/logo-light.png';
import ChartDBDarkLogo from '@/assets/logo-dark.png';
import { useTheme } from '@/hooks/use-theme';
export interface SidebarItem {
title: string;
@@ -30,6 +34,8 @@ export const EditorSidebar: React.FC<EditorSidebarProps> = () => {
const { selectSidebarSection, selectedSidebarSection, showSidePanel } =
useLayout();
const { t } = useTranslation();
const { isMd: isDesktop } = useBreakpoint('md');
const { effectiveTheme } = useTheme();
const items: SidebarItem[] = useMemo(
() => [
{
@@ -96,9 +102,28 @@ export const EditorSidebar: React.FC<EditorSidebarProps> = () => {
variant="sidebar"
className="relative h-full"
>
{!isDesktop ? (
<SidebarHeader>
<a
href="https://chartdb.io"
className="cursor-pointer"
rel="noreferrer"
>
<img
src={
effectiveTheme === 'light'
? ChartDBLogo
: ChartDBDarkLogo
}
alt="chartDB"
className="h-4 max-w-fit"
/>
</a>
</SidebarHeader>
) : null}
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel />
{/* <SidebarGroupLabel /> */}
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (

View File

@@ -0,0 +1,64 @@
import React, { useCallback } from 'react';
import ChartDBLogo from '@/assets/logo-2.png';
import { DiagramName } from './diagram-name';
import { LanguageNav } from './language-nav/language-nav';
import { Menu } from './menu/menu';
import { Button } from '@/components/button/button';
import { useSidebar } from '@/components/sidebar/use-sidebar';
import { MenuIcon } from 'lucide-react';
export interface TopNavbarMobileProps {}
export const TopNavbarMobile: React.FC<TopNavbarMobileProps> = () => {
const renderStars = useCallback(() => {
return (
<iframe
src="https://ghbtns.com/github-btn.html?user=chartdb&repo=chartdb&type=star&size=small&text=false"
width="25"
height="20"
title="GitHub"
></iframe>
);
}, []);
const { toggleSidebar } = useSidebar();
return (
<nav className="flex flex-col justify-between border-b px-3 md:h-12 md:flex-row md:items-center md:px-4">
<div className="flex flex-1 flex-col justify-between gap-x-1 md:flex-row md:justify-normal">
<div className="flex items-center justify-between pt-[8px] font-primary md:py-[10px]">
<div className="flex items-center gap-2">
<Button
size={'icon'}
variant="ghost"
onClick={toggleSidebar}
>
<MenuIcon className="size-5" />
</Button>
<a
href="https://chartdb.io"
className="cursor-pointer"
rel="noreferrer"
>
<img
src={ChartDBLogo}
alt="chartDB"
className="h-4 max-w-fit"
/>
</a>
</div>
<div className="flex items-center gap-2">
{renderStars()}
<LanguageNav />
</div>
</div>
<Menu />
</div>
<div className="flex flex-1 justify-center pb-2 pt-1">
<DiagramName />
</div>
</nav>
);
};

View File

@@ -0,0 +1,32 @@
import React from 'react';
import ChartDBLogo from '@/assets/logo-light.png';
import ChartDBDarkLogo from '@/assets/logo-dark.png';
import { useTheme } from '@/hooks/use-theme';
export const TopNavbarMock: React.FC = () => {
const { effectiveTheme } = useTheme();
return (
<nav className="flex h-[105px] flex-col justify-between border-b px-3 md:h-12 md:flex-row md:items-center md:px-4">
<div className="flex flex-1 flex-col justify-between gap-x-1 md:flex-row md:justify-normal">
<div className="flex items-center justify-between pt-[8px] font-primary md:py-[10px]">
<a
href="https://chartdb.io"
className="cursor-pointer"
rel="noreferrer"
>
<img
src={
effectiveTheme === 'light'
? ChartDBLogo
: ChartDBDarkLogo
}
alt="chartDB"
className="h-4 max-w-fit"
/>
</a>
</div>
</div>
</nav>
);
};

View File

@@ -1,7 +1,6 @@
import React, { useCallback } from 'react';
import ChartDBLogo from '@/assets/logo-light.png';
import ChartDBDarkLogo from '@/assets/logo-dark.png';
import { useBreakpoint } from '@/hooks/use-breakpoint';
import { useTheme } from '@/hooks/use-theme';
import { DiagramName } from './diagram-name';
import { LastSaved } from './last-saved';
@@ -12,18 +11,17 @@ export interface TopNavbarProps {}
export const TopNavbar: React.FC<TopNavbarProps> = () => {
const { effectiveTheme } = useTheme();
const { isMd: isDesktop } = useBreakpoint('md');
const renderStars = useCallback(() => {
return (
<iframe
src={`https://ghbtns.com/github-btn.html?user=chartdb&repo=chartdb&type=star&size=${isDesktop ? 'large' : 'small'}&text=false`}
width={isDesktop ? '40' : '25'}
height={isDesktop ? '30' : '20'}
src={`https://ghbtns.com/github-btn.html?user=chartdb&repo=chartdb&type=star&size=large&text=false`}
width="40"
height="30"
title="GitHub"
></iframe>
);
}, [isDesktop]);
}, []);
return (
<nav className="flex flex-col justify-between border-b px-3 md:h-12 md:flex-row md:items-center md:px-4">
@@ -44,29 +42,15 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
className="h-4 max-w-fit"
/>
</a>
{!isDesktop ? (
<div className="flex items-center gap-2">
{renderStars()}
<LanguageNav />
</div>
) : null}
</div>
<Menu />
</div>
{isDesktop ? (
<>
<DiagramName />
<div className="hidden flex-1 items-center justify-end gap-2 sm:flex">
<LastSaved />
{renderStars()}
<LanguageNav />
</div>
</>
) : (
<div className="flex flex-1 justify-center pb-2 pt-1">
<DiagramName />
</div>
)}
<DiagramName />
<div className="hidden flex-1 items-center justify-end gap-2 sm:flex">
<LastSaved />
{renderStars()}
<LanguageNav />
</div>
</nav>
);
};