mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
style/responsive sidebar (#3505)
* style: added sidebar toggle in all the screens for mobile responsive * chore: close sidebar on click of empty space when opened * chore: setting the sidebar collapsed in smaller screens
This commit is contained in:
parent
9debd81a50
commit
c6d6b9a0e9
@ -0,0 +1,16 @@
|
||||
import { FC } from "react";
|
||||
import { Menu } from "lucide-react";
|
||||
import { useApplication } from "hooks/store";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
export const SidebarHamburgerToggle: FC = observer (() => {
|
||||
const { theme: themStore } = useApplication();
|
||||
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={() => themStore.toggleSidebar()}
|
||||
>
|
||||
<Menu size={14} className="text-custom-text-200 group-hover:text-custom-text-100 transition-all" />
|
||||
</div>
|
||||
);
|
||||
});
|
@ -63,34 +63,27 @@ export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||
|
||||
return (
|
||||
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full grid grid-cols-4 p-0.5 hover:shadow-custom-shadow-4xl duration-300">
|
||||
{STATS_LIST.map((stat, index) => {
|
||||
const isFirst = index === 0;
|
||||
const isLast = index === STATS_LIST.length - 1;
|
||||
const isMiddle = !isFirst && !isLast;
|
||||
|
||||
return (
|
||||
<div key={stat.key} className="flex relative">
|
||||
{!isLast && (
|
||||
<div className="absolute right-0 top-1/2 -translate-y-1/2 h-3/5 w-[0.5px] bg-custom-border-200" />
|
||||
)}
|
||||
<Link
|
||||
href={stat.link}
|
||||
className={cn(
|
||||
`py-4 hover:bg-custom-background-80 duration-300 rounded-[10px] w-full break-words flex flex-col justify-center`,
|
||||
{
|
||||
"pl-11 pr-[4.725rem] mr-0.5": isFirst,
|
||||
"px-[4.725rem] mx-0.5": isMiddle,
|
||||
"px-[4.725rem] ml-0.5": isLast,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<h5 className="font-semibold text-xl">{stat.count}</h5>
|
||||
<p className="text-custom-text-300 text-sm xl:text-base">{stat.title}</p>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div
|
||||
className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-2 grid-cols-2 p-0.5 hover:shadow-custom-shadow-4xl duration-300
|
||||
[&>div>a>div]:border-r
|
||||
[&>div:last-child>a>div]:border-0
|
||||
[&>div>a>div]:border-custom-border-200
|
||||
[&>div:nth-child(2)>a>div]:border-0
|
||||
[&>div:nth-child(2)>a>div]:lg:border-r
|
||||
"
|
||||
>
|
||||
{STATS_LIST.map((stat) => (
|
||||
<div className="w-full flex flex-col gap-2 hover:bg-custom-background-80 rounded-[10px]">
|
||||
<Link href={stat.link} className="py-4 duration-300 rounded-[10px] w-full ">
|
||||
<div className={`relative flex justify-center items-center`}>
|
||||
<div>
|
||||
<h5 className="font-semibold text-xl">{stat.count}</h5>
|
||||
<p className="text-custom-text-300 text-sm xl:text-base">{stat.title}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -17,6 +17,7 @@ import useLocalStorage from "hooks/use-local-storage";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||
import { ProjectAnalyticsModal } from "components/analytics";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, ContrastIcon, CustomMenu } from "@plane/ui";
|
||||
// icons
|
||||
@ -146,6 +147,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
||||
/>
|
||||
<div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<SidebarHamburgerToggle />
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
|
@ -9,6 +9,8 @@ import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui";
|
||||
// helpers
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
import { EUserProjectRoles } from "constants/project";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const CyclesHeader: FC = observer(() => {
|
||||
// router
|
||||
@ -30,6 +32,7 @@ export const CyclesHeader: FC = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -7,6 +7,7 @@ import { useLabel, useMember, useUser, useIssues } from "hooks/store";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues";
|
||||
import { CreateUpdateWorkspaceViewModal } from "components/workspace";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, LayersIcon, PhotoFilterIcon, Tooltip } from "@plane/ui";
|
||||
// icons
|
||||
@ -106,7 +107,8 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
|
||||
<>
|
||||
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
|
||||
<div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div>
|
||||
<div className="relative flex gap-2">
|
||||
<SidebarHamburgerToggle/>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
|
@ -17,6 +17,7 @@ import useLocalStorage from "hooks/use-local-storage";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||
import { ProjectAnalyticsModal } from "components/analytics";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, CustomMenu, DiceIcon } from "@plane/ui";
|
||||
// icons
|
||||
@ -149,6 +150,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
/>
|
||||
<div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<SidebarHamburgerToggle />
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
|
@ -11,6 +11,8 @@ import { renderEmoji } from "helpers/emoji.helper";
|
||||
// constants
|
||||
import { MODULE_VIEW_LAYOUTS } from "constants/module";
|
||||
import { EUserProjectRoles } from "constants/project";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const ModulesListHeader: React.FC = observer(() => {
|
||||
// router
|
||||
@ -31,6 +33,7 @@ export const ModulesListHeader: React.FC = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -8,6 +8,8 @@ import { useApplication, usePage, useProject } from "hooks/store";
|
||||
import { Breadcrumbs, Button } from "@plane/ui";
|
||||
// helpers
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export interface IPagesHeaderProps {
|
||||
showButton?: boolean;
|
||||
@ -27,6 +29,7 @@ export const PageDetailsHeader: FC<IPagesHeaderProps> = observer((props) => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -9,6 +9,8 @@ import { Breadcrumbs, Button } from "@plane/ui";
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
// constants
|
||||
import { EUserProjectRoles } from "constants/project";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const PagesHeader = observer(() => {
|
||||
// router
|
||||
@ -29,6 +31,7 @@ export const PagesHeader = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -14,6 +14,8 @@ import { ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
import { IssueArchiveService } from "services/issue";
|
||||
// helpers
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
const issueArchiveService = new IssueArchiveService();
|
||||
|
||||
@ -39,6 +41,7 @@ export const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -10,6 +10,7 @@ import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } f
|
||||
import { Breadcrumbs, LayersIcon } from "@plane/ui";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// helpers
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
// types
|
||||
@ -70,6 +71,7 @@ export const ProjectArchivedIssuesHeader: FC = observer(() => {
|
||||
return (
|
||||
<div className="relative z-10 flex h-14 w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
|
@ -5,6 +5,7 @@ import { observer } from "mobx-react-lite";
|
||||
import { useIssues, useLabel, useMember, useProject, useProjectState } from "hooks/store";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// ui
|
||||
import { Breadcrumbs, LayersIcon } from "@plane/ui";
|
||||
// helper
|
||||
@ -74,6 +75,7 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -8,6 +8,7 @@ import { useProject } from "hooks/store";
|
||||
import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
|
||||
// components
|
||||
import { CreateInboxIssueModal } from "components/inbox";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// helper
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
|
||||
@ -23,6 +24,7 @@ export const ProjectInboxHeader: FC = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -12,6 +12,8 @@ import { renderEmoji } from "helpers/emoji.helper";
|
||||
import { IssueService } from "services/issue";
|
||||
// constants
|
||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
// services
|
||||
const issueService = new IssueService();
|
||||
@ -33,6 +35,7 @@ export const ProjectIssueDetailsHeader: FC = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -8,6 +8,7 @@ import { useApplication, useLabel, useProject, useProjectState, useUser, useInbo
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||
import { ProjectAnalyticsModal } from "components/analytics";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
|
||||
// types
|
||||
@ -105,6 +106,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
||||
/>
|
||||
<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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
|
@ -9,6 +9,8 @@ import { renderEmoji } from "helpers/emoji.helper";
|
||||
import { useProject, useUser } from "hooks/store";
|
||||
// constants
|
||||
import { EUserProjectRoles } from "constants/project";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export interface IProjectSettingHeader {
|
||||
title: string;
|
||||
@ -30,6 +32,7 @@ export const ProjectSettingHeader: FC<IProjectSettingHeader> = observer((props)
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
} from "hooks/store";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, CustomMenu, PhotoFilterIcon } from "@plane/ui";
|
||||
// helpers
|
||||
@ -107,6 +108,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
return (
|
||||
<div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<SidebarHamburgerToggle />
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
type="text"
|
||||
|
@ -5,6 +5,7 @@ import { Plus } from "lucide-react";
|
||||
import { useApplication, useProject, useUser } from "hooks/store";
|
||||
// components
|
||||
import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
// helpers
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
// constants
|
||||
@ -30,6 +31,7 @@ export const ProjectViewsHeader: React.FC = observer(() => {
|
||||
<>
|
||||
<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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -6,6 +6,8 @@ import { useApplication, useProject, useUser } from "hooks/store";
|
||||
import { Breadcrumbs, Button } from "@plane/ui";
|
||||
// constants
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const ProjectsHeader = observer(() => {
|
||||
// store hooks
|
||||
@ -23,6 +25,7 @@ export const ProjectsHeader = observer(() => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -1,9 +1,12 @@
|
||||
// ui
|
||||
import { Breadcrumbs } from "@plane/ui";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const UserProfileHeader = () => (
|
||||
<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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem type="text" label="Activity Overview" link="/profile" />
|
||||
|
@ -3,10 +3,12 @@ import { observer } from "mobx-react-lite";
|
||||
import { Breadcrumbs, ContrastIcon } from "@plane/ui";
|
||||
// icons
|
||||
import { Crown } from "lucide-react";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const WorkspaceActiveCycleHeader = observer(() => (
|
||||
<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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle />
|
||||
<div className="flex items-center gap-2">
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -2,6 +2,8 @@ import { useRouter } from "next/router";
|
||||
import { ArrowLeft, BarChart2 } from "lucide-react";
|
||||
// ui
|
||||
import { Breadcrumbs } from "@plane/ui";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const WorkspaceAnalyticsHeader = () => {
|
||||
const router = useRouter();
|
||||
@ -12,6 +14,7 @@ export const WorkspaceAnalyticsHeader = () => {
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4`}
|
||||
>
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle />
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
|
@ -8,10 +8,11 @@ import githubWhiteImage from "/public/logos/github-white.png";
|
||||
// components
|
||||
import { ProductUpdatesModal } from "components/common";
|
||||
import { Breadcrumbs } from "@plane/ui";
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export const WorkspaceDashboardHeader = () => {
|
||||
const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false);
|
||||
// theme
|
||||
// hooks
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
return (
|
||||
@ -19,6 +20,7 @@ export const WorkspaceDashboardHeader = () => {
|
||||
<ProductUpdatesModal isOpen={isProductUpdatesModalOpen} setIsOpen={setIsProductUpdatesModalOpen} />
|
||||
<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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle />
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { FC } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
// ui
|
||||
import { Breadcrumbs } from "@plane/ui";
|
||||
import { Settings } from "lucide-react";
|
||||
|
||||
// hooks
|
||||
import { observer } from "mobx-react-lite";
|
||||
// components
|
||||
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
|
||||
|
||||
export interface IWorkspaceSettingHeader {
|
||||
title: string;
|
||||
@ -22,6 +21,7 @@ export const WorkspaceSettingHeader: FC<IWorkspaceSettingHeader> = observer((pro
|
||||
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-border-200 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<SidebarHamburgerToggle/>
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.BreadcrumbItem
|
||||
|
@ -131,6 +131,12 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
setLeaveProjectModal(false);
|
||||
};
|
||||
|
||||
const handleProjectClick = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
themeStore.toggleSidebar();
|
||||
}
|
||||
};
|
||||
|
||||
useOutsideClickDetector(actionSectionRef, () => setIsMenuActive(false));
|
||||
|
||||
if (!project) return null;
|
||||
@ -143,9 +149,8 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
{({ open }) => (
|
||||
<>
|
||||
<div
|
||||
className={`group relative flex w-full items-center rounded-md px-2 py-1 text-custom-sidebar-text-10 hover:bg-custom-sidebar-background-80 ${
|
||||
snapshot?.isDragging ? "opacity-60" : ""
|
||||
} ${isMenuActive ? "!bg-custom-sidebar-background-80" : ""}`}
|
||||
className={`group relative flex w-full items-center rounded-md px-2 py-1 text-custom-sidebar-text-10 hover:bg-custom-sidebar-background-80 ${snapshot?.isDragging ? "opacity-60" : ""
|
||||
} ${isMenuActive ? "!bg-custom-sidebar-background-80" : ""}`}
|
||||
>
|
||||
{provided && (
|
||||
<Tooltip
|
||||
@ -154,11 +159,9 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`absolute -left-2.5 top-1/2 hidden -translate-y-1/2 rounded p-0.5 text-custom-sidebar-text-400 ${
|
||||
isCollapsed ? "" : "group-hover:!flex"
|
||||
} ${project.sort_order === null ? "cursor-not-allowed opacity-60" : ""} ${
|
||||
isMenuActive ? "!flex" : ""
|
||||
}`}
|
||||
className={`absolute -left-2.5 top-1/2 hidden -translate-y-1/2 rounded p-0.5 text-custom-sidebar-text-400 ${isCollapsed ? "" : "group-hover:!flex"
|
||||
} ${project.sort_order === null ? "cursor-not-allowed opacity-60" : ""} ${isMenuActive ? "!flex" : ""
|
||||
}`}
|
||||
{...provided?.dragHandleProps}
|
||||
>
|
||||
<MoreVertical className="h-3.5" />
|
||||
@ -169,14 +172,12 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
<Tooltip tooltipContent={`${project.name}`} position="right" className="ml-2" disabled={!isCollapsed}>
|
||||
<Disclosure.Button
|
||||
as="div"
|
||||
className={`flex flex-grow cursor-pointer select-none items-center truncate text-left text-sm font-medium ${
|
||||
isCollapsed ? "justify-center" : `justify-between`
|
||||
}`}
|
||||
className={`flex flex-grow cursor-pointer select-none items-center truncate text-left text-sm font-medium ${isCollapsed ? "justify-center" : `justify-between`
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`flex w-full flex-grow items-center gap-x-2 truncate ${
|
||||
isCollapsed ? "justify-center" : ""
|
||||
}`}
|
||||
className={`flex w-full flex-grow items-center gap-x-2 truncate ${isCollapsed ? "justify-center" : ""
|
||||
}`}
|
||||
>
|
||||
{project.emoji ? (
|
||||
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded uppercase">
|
||||
@ -196,9 +197,8 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
</div>
|
||||
{!isCollapsed && (
|
||||
<ChevronDown
|
||||
className={`hidden h-4 w-4 flex-shrink-0 ${open ? "rotate-180" : ""} ${
|
||||
isMenuActive ? "!block" : ""
|
||||
} mb-0.5 text-custom-sidebar-text-400 duration-300 group-hover:!block`}
|
||||
className={`hidden h-4 w-4 flex-shrink-0 ${open ? "rotate-180" : ""} ${isMenuActive ? "!block" : ""
|
||||
} mb-0.5 text-custom-sidebar-text-400 duration-300 group-hover:!block`}
|
||||
/>
|
||||
)}
|
||||
</Disclosure.Button>
|
||||
@ -313,7 +313,7 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
return;
|
||||
|
||||
return (
|
||||
<Link key={item.name} href={item.href}>
|
||||
<Link key={item.name} href={item.href} onClick={handleProjectClick}>
|
||||
<span className="block w-full">
|
||||
<Tooltip
|
||||
tooltipContent={`${project?.name}: ${item.name}`}
|
||||
@ -322,11 +322,10 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
||||
disabled={!isCollapsed}
|
||||
>
|
||||
<div
|
||||
className={`group flex items-center gap-2.5 rounded-md px-2 py-1.5 text-xs font-medium outline-none ${
|
||||
router.asPath.includes(item.href)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-300 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
} ${isCollapsed ? "justify-center" : ""}`}
|
||||
className={`group flex items-center gap-2.5 rounded-md px-2 py-1.5 text-xs font-medium outline-none ${router.asPath.includes(item.href)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-300 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
} ${isCollapsed ? "justify-center" : ""}`}
|
||||
>
|
||||
<item.Icon className="h-4 w-4 stroke-[1.5]" />
|
||||
{!isCollapsed && item.name}
|
||||
|
@ -56,7 +56,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
const { workspaceSlug } = router.query;
|
||||
// store hooks
|
||||
const {
|
||||
theme: { sidebarCollapsed },
|
||||
theme: { sidebarCollapsed, toggleSidebar },
|
||||
eventTracker: { setTrackElement },
|
||||
} = useApplication();
|
||||
const { currentUser, updateCurrentUser, isUserInstanceAdmin, signOut } = useUser();
|
||||
@ -86,6 +86,13 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
);
|
||||
};
|
||||
|
||||
const handleItemClick = () => {
|
||||
console.log('CLICKED')
|
||||
if (window.innerWidth < 768) {
|
||||
toggleSidebar();
|
||||
}
|
||||
};
|
||||
|
||||
const workspacesList = Object.values(workspaces ?? {});
|
||||
|
||||
// TODO: fix workspaces list scroll
|
||||
@ -96,15 +103,13 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
<>
|
||||
<Menu.Button className="group/menu-button h-full w-full truncate rounded-md text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:outline-none">
|
||||
<div
|
||||
className={`flex items-center gap-x-2 truncate rounded p-1 ${
|
||||
sidebarCollapsed ? "justify-center" : "justify-between"
|
||||
}`}
|
||||
className={`flex items-center gap-x-2 truncate rounded p-1 ${sidebarCollapsed ? "justify-center" : "justify-between"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 truncate">
|
||||
<div
|
||||
className={`relative grid h-6 w-6 flex-shrink-0 place-items-center uppercase ${
|
||||
!activeWorkspace?.logo && "rounded bg-custom-primary-500 text-white"
|
||||
}`}
|
||||
className={`relative grid h-6 w-6 flex-shrink-0 place-items-center uppercase ${!activeWorkspace?.logo && "rounded bg-custom-primary-500 text-white"
|
||||
}`}
|
||||
>
|
||||
{activeWorkspace?.logo && activeWorkspace.logo !== "" ? (
|
||||
<img
|
||||
@ -126,9 +131,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
|
||||
{!sidebarCollapsed && (
|
||||
<ChevronDown
|
||||
className={`mx-1 hidden h-4 w-4 flex-shrink-0 group-hover/menu-button:block ${
|
||||
open ? "rotate-180" : ""
|
||||
} text-custom-sidebar-text-400 duration-300`}
|
||||
className={`mx-1 hidden h-4 w-4 flex-shrink-0 group-hover/menu-button:block ${open ? "rotate-180" : ""
|
||||
} text-custom-sidebar-text-400 duration-300`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@ -156,7 +160,10 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
<Link
|
||||
key={workspace.id}
|
||||
href={`/${workspace.slug}`}
|
||||
onClick={() => handleWorkspaceNavigation(workspace)}
|
||||
onClick={() => {
|
||||
handleWorkspaceNavigation(workspace);
|
||||
handleItemClick();
|
||||
}}
|
||||
className="w-full"
|
||||
>
|
||||
<Menu.Item
|
||||
@ -165,9 +172,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
>
|
||||
<div className="flex items-center justify-start gap-2.5 truncate">
|
||||
<span
|
||||
className={`relative flex h-6 w-6 flex-shrink-0 items-center justify-center p-2 text-xs uppercase ${
|
||||
!workspace?.logo && "rounded bg-custom-primary-500 text-white"
|
||||
}`}
|
||||
className={`relative flex h-6 w-6 flex-shrink-0 items-center justify-center p-2 text-xs uppercase ${!workspace?.logo && "rounded bg-custom-primary-500 text-white"
|
||||
}`}
|
||||
>
|
||||
{workspace?.logo && workspace.logo !== "" ? (
|
||||
<img
|
||||
@ -181,9 +187,8 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
</span>
|
||||
|
||||
<h5
|
||||
className={`truncate text-sm font-medium ${
|
||||
workspaceSlug === workspace.slug ? "" : "text-custom-text-200"
|
||||
}`}
|
||||
className={`truncate text-sm font-medium ${workspaceSlug === workspace.slug ? "" : "text-custom-text-200"
|
||||
}`}
|
||||
>
|
||||
{workspace.name}
|
||||
</h5>
|
||||
@ -220,8 +225,10 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
Create workspace
|
||||
</Menu.Item>
|
||||
</Link>
|
||||
{userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link) => (
|
||||
<Link key={link.key} href={link.href} className="w-full">
|
||||
{userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
|
||||
<Link key={link.key} href={link.href} className="w-full" onClick={() => {
|
||||
if (index > 0) handleItemClick();
|
||||
}}>
|
||||
<Menu.Item
|
||||
as="div"
|
||||
className="flex items-center gap-2 rounded px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 font-medium"
|
||||
@ -278,7 +285,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
<div className="flex flex-col gap-2.5 pb-2">
|
||||
<span className="px-2 text-custom-sidebar-text-200">{currentUser?.email}</span>
|
||||
{profileLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
|
||||
<Link key={index} href={link.link}>
|
||||
<Link key={index} href={link.link} onClick={() => { if (index == 0) handleItemClick(); }}>
|
||||
<Menu.Item key={index} as="div">
|
||||
<span className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
|
||||
<link.icon className="h-4 w-4 stroke-[1.5]" />
|
||||
|
@ -27,12 +27,21 @@ export const WorkspaceSidebarMenu = observer(() => {
|
||||
// computed
|
||||
const workspaceMemberInfo = currentWorkspaceRole || EUserWorkspaceRoles.GUEST;
|
||||
|
||||
const handleLinkClick = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
themeStore.toggleSidebar();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full cursor-pointer space-y-2 p-4">
|
||||
{SIDEBAR_MENU_ITEMS.map(
|
||||
(link) =>
|
||||
workspaceMemberInfo >= link.access && (
|
||||
<Link key={link.key} href={`/${workspaceSlug}${link.href}`}>
|
||||
<Link key={link.key}
|
||||
href={`/${workspaceSlug}${link.href}`}
|
||||
onClick={handleLinkClick}
|
||||
>
|
||||
<span className="block w-full my-1">
|
||||
<Tooltip
|
||||
tooltipContent={link.label}
|
||||
@ -41,11 +50,10 @@ export const WorkspaceSidebarMenu = observer(() => {
|
||||
disabled={!themeStore?.sidebarCollapsed}
|
||||
>
|
||||
<div
|
||||
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${
|
||||
link.highlight(router.asPath, `/${workspaceSlug}`)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
|
||||
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${link.highlight(router.asPath, `/${workspaceSlug}`)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
|
||||
>
|
||||
{
|
||||
<link.Icon
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FC } from "react";
|
||||
import { FC, useEffect, useRef } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// components
|
||||
import {
|
||||
@ -10,20 +10,48 @@ import {
|
||||
import { ProjectSidebarList } from "components/project";
|
||||
// hooks
|
||||
import { useApplication } from "hooks/store";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
|
||||
export interface IAppSidebar {}
|
||||
export interface IAppSidebar { }
|
||||
|
||||
export const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
// store hooks
|
||||
const { theme: themStore } = useApplication();
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useOutsideClickDetector(ref, () => {
|
||||
if (themStore.sidebarCollapsed === false) {
|
||||
if (window.innerWidth < 768) {
|
||||
themStore.toggleSidebar();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
if (window.innerWidth <= 768) {
|
||||
themStore.toggleSidebar(true);
|
||||
}
|
||||
};
|
||||
handleResize();
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, [themStore]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed 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 ${
|
||||
themStore?.sidebarCollapsed ? "" : "md:w-[280px]"
|
||||
} ${themStore?.sidebarCollapsed ? "left-0" : "-left-full md:left-0"}`}
|
||||
>
|
||||
<div className="flex h-full w-full flex-1 flex-col">
|
||||
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
|
||||
fixed md:relative
|
||||
${themStore.sidebarCollapsed ? "-ml-[280px]" : ""}
|
||||
sm:${themStore.sidebarCollapsed ? "-ml-[280px]" : ""}
|
||||
md:ml-0 ${themStore.sidebarCollapsed ? 'w-[80px]' : 'w-[280px]'}
|
||||
lg:ml-0 ${themStore.sidebarCollapsed ? 'w-[80px]' : 'w-[280px]'}
|
||||
`} >
|
||||
<div
|
||||
ref={ref}
|
||||
className="flex h-full w-full flex-1 flex-col">
|
||||
<WorkspaceSidebarDropdown />
|
||||
<WorkspaceSidebarQuickAction />
|
||||
<WorkspaceSidebarMenu />
|
||||
@ -33,3 +61,6 @@ export const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user