mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: sidebar responsiveness.
This commit is contained in:
parent
5ebd64d729
commit
496a2340c5
@ -8,6 +8,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { Breadcrumbs } from "@plane/ui";
|
import { Breadcrumbs } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Settings } from "lucide-react";
|
import { Settings } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { SidebarHamburgerToggle } from "components/sidebar/sidebar-menu-hamburger-toogle";
|
||||||
|
|
||||||
export const InstanceHeader: FC = observer(() => {
|
export const InstanceHeader: FC = observer(() => {
|
||||||
const pathName = usePathname();
|
const pathName = usePathname();
|
||||||
@ -35,6 +37,7 @@ export const InstanceHeader: FC = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-sidebar-border-200 bg-custom-sidebar-background-100 p-4">
|
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-sidebar-border-200 bg-custom-sidebar-background-100 p-4">
|
||||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||||
|
<SidebarHamburgerToggle />
|
||||||
{title && (
|
{title && (
|
||||||
<div>
|
<div>
|
||||||
<Breadcrumbs>
|
<Breadcrumbs>
|
||||||
@ -42,7 +45,6 @@ export const InstanceHeader: FC = observer(() => {
|
|||||||
type="text"
|
type="text"
|
||||||
icon={<Settings className="h-4 w-4 text-custom-text-300" />}
|
icon={<Settings className="h-4 w-4 text-custom-text-300" />}
|
||||||
label="Settings"
|
label="Settings"
|
||||||
link="/"
|
|
||||||
/>
|
/>
|
||||||
<Breadcrumbs.BreadcrumbItem type="text" label={title} />
|
<Breadcrumbs.BreadcrumbItem type="text" label={title} />
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FC } from "react";
|
import { FC, useEffect, useRef } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import useAppTheme from "hooks/use-theme";
|
import useAppTheme from "hooks/use-theme";
|
||||||
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// components
|
// components
|
||||||
import { HelpSection, SidebarMenu, SidebarDropdown } from "components/sidebar";
|
import { HelpSection, SidebarMenu, SidebarDropdown } from "components/sidebar";
|
||||||
|
|
||||||
@ -11,15 +12,42 @@ export interface IInstanceSidebar {}
|
|||||||
|
|
||||||
export const InstanceSidebar: FC<IInstanceSidebar> = observer(() => {
|
export const InstanceSidebar: FC<IInstanceSidebar> = observer(() => {
|
||||||
// store
|
// store
|
||||||
const { sidebarCollapsed } = useAppTheme();
|
const themeStore = useAppTheme();
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useOutsideClickDetector(ref, () => {
|
||||||
|
if (themeStore.sidebarCollapsed === false) {
|
||||||
|
if (window.innerWidth < 768) {
|
||||||
|
themeStore.toggleSidebar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth <= 768) {
|
||||||
|
themeStore.toggleSidebar(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
};
|
||||||
|
}, [themeStore]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`inset-y-0 z-20 flex h-full flex-shrink-0 flex-grow-0 flex-col border-r border-custom-sidebar-border-200 bg-custom-sidebar-background-100 duration-300 md:relative ${
|
className={`inset-y-0 z-20 flex h-full flex-shrink-0 flex-grow-0 flex-col border-r border-custom-sidebar-border-200 bg-custom-sidebar-background-100 duration-300
|
||||||
sidebarCollapsed ? "" : "md:w-[280px]"
|
fixed md:relative
|
||||||
} ${sidebarCollapsed ? "left-0" : "-left-full md:left-0"}`}
|
${themeStore.sidebarCollapsed ? "-ml-[280px]" : ""}
|
||||||
|
sm:${themeStore.sidebarCollapsed ? "-ml-[280px]" : ""}
|
||||||
|
md:ml-0 ${themeStore.sidebarCollapsed ? "w-[80px]" : "w-[280px]"}
|
||||||
|
lg:ml-0 ${themeStore.sidebarCollapsed ? "w-[80px]" : "w-[280px]"}
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
<div className="flex h-full w-full flex-1 flex-col">
|
<div ref={ref} className="flex h-full w-full flex-1 flex-col">
|
||||||
<SidebarDropdown />
|
<SidebarDropdown />
|
||||||
<SidebarMenu />
|
<SidebarMenu />
|
||||||
<HelpSection />
|
<HelpSection />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FC, useState, useRef } from "react";
|
import { FC, useState, useRef } from "react";
|
||||||
import { Transition } from "@headlessui/react";
|
import { Transition } from "@headlessui/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { FileText, HelpCircle, MessagesSquare, MoveLeft } from "lucide-react";
|
import { FileText, HelpCircle, MoveLeft } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useAppTheme } from "hooks/use-theme";
|
import { useAppTheme } from "hooks/use-theme";
|
||||||
// icons
|
// icons
|
||||||
@ -25,12 +25,6 @@ const helpOptions = [
|
|||||||
href: "https://github.com/makeplane/plane/issues/new/choose",
|
href: "https://github.com/makeplane/plane/issues/new/choose",
|
||||||
Icon: GithubIcon,
|
Icon: GithubIcon,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Chat with us",
|
|
||||||
href: null,
|
|
||||||
onClick: () => (window as any).$crisp.push(["do", "chat:show"]),
|
|
||||||
Icon: MessagesSquare,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const HelpSection: FC = () => {
|
export const HelpSection: FC = () => {
|
||||||
@ -100,7 +94,7 @@ export const HelpSection: FC = () => {
|
|||||||
ref={helpOptionsRef}
|
ref={helpOptionsRef}
|
||||||
>
|
>
|
||||||
<div className="space-y-1 pb-2">
|
<div className="space-y-1 pb-2">
|
||||||
{helpOptions.map(({ name, Icon, href, onClick }) => {
|
{helpOptions.map(({ name, Icon, href }) => {
|
||||||
if (href)
|
if (href)
|
||||||
return (
|
return (
|
||||||
<Link href={href} key={name} target="_blank">
|
<Link href={href} key={name} target="_blank">
|
||||||
@ -120,7 +114,6 @@ export const HelpSection: FC = () => {
|
|||||||
<button
|
<button
|
||||||
key={name}
|
key={name}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick ?? undefined}
|
|
||||||
className="flex w-full items-center gap-x-2 rounded px-2 py-1 text-xs hover:bg-custom-background-80"
|
className="flex w-full items-center gap-x-2 rounded px-2 py-1 text-xs hover:bg-custom-background-80"
|
||||||
>
|
>
|
||||||
<div className="grid flex-shrink-0 place-items-center">
|
<div className="grid flex-shrink-0 place-items-center">
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
// hooks
|
||||||
|
import { useAppTheme } from "hooks/use-theme";
|
||||||
|
// icons
|
||||||
|
import { Menu } from "lucide-react";
|
||||||
|
|
||||||
|
export const SidebarHamburgerToggle: FC = observer(() => {
|
||||||
|
const { toggleSidebar } = useAppTheme();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="w-7 h-7 rounded flex justify-center items-center bg-custom-background-80 transition-all hover:bg-custom-background-90 cursor-pointer group md:hidden"
|
||||||
|
onClick={() => toggleSidebar()}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
size={14}
|
||||||
|
className="text-custom-text-200 group-hover:text-custom-text-100 transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -42,10 +42,16 @@ const INSTANCE_ADMIN_LINKS = [
|
|||||||
|
|
||||||
export const SidebarMenu = observer(() => {
|
export const SidebarMenu = observer(() => {
|
||||||
// store hooks
|
// store hooks
|
||||||
const { sidebarCollapsed } = useAppTheme();
|
const { sidebarCollapsed, toggleSidebar } = useAppTheme();
|
||||||
// router
|
// router
|
||||||
const pathName = usePathname();
|
const pathName = usePathname();
|
||||||
|
|
||||||
|
const handleItemClick = () => {
|
||||||
|
if (window.innerWidth < 768) {
|
||||||
|
toggleSidebar();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col gap-2.5 overflow-y-auto px-4 py-6">
|
<div className="flex h-full w-full flex-col gap-2.5 overflow-y-auto px-4 py-6">
|
||||||
{INSTANCE_ADMIN_LINKS.map((item, index) => {
|
{INSTANCE_ADMIN_LINKS.map((item, index) => {
|
||||||
@ -55,7 +61,7 @@ export const SidebarMenu = observer(() => {
|
|||||||
: pathName === item.href;
|
: pathName === item.href;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link key={index} href={item.href}>
|
<Link key={index} href={item.href} onClick={handleItemClick}>
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
tooltipContent={item.name}
|
tooltipContent={item.name}
|
||||||
|
19
god-mode/hooks/use-outside-click-detector.tsx
Normal file
19
god-mode/hooks/use-outside-click-detector.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
|
const useOutsideClickDetector = (ref: React.RefObject<HTMLElement>, callback: () => void) => {
|
||||||
|
const handleClick = (event: MouseEvent) => {
|
||||||
|
if (ref.current && !ref.current.contains(event.target as Node)) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener("mousedown", handleClick);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClick);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useOutsideClickDetector;
|
Loading…
Reference in New Issue
Block a user