Style/workspace project settings layout (#3520)

* style: project settings layout for mobile screens

* style: workspace settings layout for mobile screens
This commit is contained in:
Ramesh Kumar Chandra 2024-01-31 15:42:20 +05:30 committed by GitHub
parent 0d036e6bf5
commit 3a4c893368
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 126 additions and 71 deletions

View File

@ -31,7 +31,6 @@ export const GoogleSignInButton: FC<Props> = (props) => {
size: "large",
logo_alignment: "center",
text: type === "sign_in" ? "signin_with" : "signup_with",
width: 384,
} as GsiButtonConfiguration // customization attributes
);
} catch (err) {

View File

@ -77,7 +77,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
})}
>
Issues
<span className="flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-medium py-1 px-1.5 rounded-xl h-4 min-w-6 flex items-center text-center justify-center">
<span className="flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-medium rounded-xl h-4 min-w-6 flex items-center text-center justify-center">
{totalIssues}
</span>
</h6>

View File

@ -72,14 +72,14 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
startedCount > 0
? "started"
: unStartedCount > 0
? "unstarted"
: backlogCount > 0
? "backlog"
: completedCount > 0
? "completed"
: canceledCount > 0
? "cancelled"
: null;
? "unstarted"
: backlogCount > 0
? "backlog"
: completedCount > 0
? "completed"
: canceledCount > 0
? "cancelled"
: null;
setActiveStateGroup(stateGroup);
setDefaultStateGroup(stateGroup);
@ -151,13 +151,13 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
/>
</div>
{totalCount > 0 ? (
<div className="flex items-center pl-20 md:pl-11 lg:pl-14 pr-11 mt-11">
<div className="flex md:flex-col lg:flex-row items-center gap-x-10 gap-y-8 w-full">
<div className="w-full flex justify-center">
<div className="flex items-center pl-10 md:pl-11 lg:pl-14 pr-11 mt-11">
<div className="flex flex-col sm:flex-row md:flex-row lg:flex-row items-center justify-evenly gap-x-10 gap-y-8 w-full">
<div>
<PieGraph
data={chartData}
height="220px"
width="220px"
width="200px"
innerRadius={0.6}
cornerRadius={5}
colors={(datum) => datum.data.color}
@ -189,7 +189,7 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
layers={["arcs", CenteredMetric]}
/>
</div>
<div className="justify-self-end space-y-6 w-min whitespace-nowrap">
<div className="space-y-6 w-min whitespace-nowrap">
{chartData.map((item) => (
<div key={item.id} className="flex items-center justify-between gap-6">
<div className="flex items-center gap-2.5 w-24">

View File

@ -2,13 +2,13 @@ import { FC } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// ui
import { Breadcrumbs } from "@plane/ui";
import { Breadcrumbs, CustomMenu } from "@plane/ui";
// helper
import { renderEmoji } from "helpers/emoji.helper";
// hooks
import { useProject, useUser } from "hooks/store";
// constants
import { EUserProjectRoles } from "constants/project";
import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "constants/project";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
@ -20,7 +20,7 @@ export const ProjectSettingHeader: FC<IProjectSettingHeader> = observer((props)
const { title } = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
const { workspaceSlug, projectId } = router.query;
// store hooks
const {
membership: { currentProjectRole },
@ -31,29 +31,48 @@ 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">
<SidebarHamburgerToggle />
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<SidebarHamburgerToggle/>
<div>
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
label={currentProjectDetails?.name ?? "Project"}
icon={
currentProjectDetails?.emoji ? (
renderEmoji(currentProjectDetails.emoji)
) : currentProjectDetails?.icon_prop ? (
renderEmoji(currentProjectDetails.icon_prop)
) : (
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded bg-gray-700 uppercase text-white">
{currentProjectDetails?.name.charAt(0)}
</span>
)
}
link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
<Breadcrumbs.BreadcrumbItem type="text" label={title} />
</Breadcrumbs>
<div className="z-50">
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
label={currentProjectDetails?.name ?? "Project"}
icon={
currentProjectDetails?.emoji ? (
renderEmoji(currentProjectDetails.emoji)
) : currentProjectDetails?.icon_prop ? (
renderEmoji(currentProjectDetails.icon_prop)
) : (
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded bg-gray-700 uppercase text-white">
{currentProjectDetails?.name.charAt(0)}
</span>
)
}
link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
<div className="hidden sm:hidden md:block lg:block">
<Breadcrumbs.BreadcrumbItem type="text" label={title} />
</div>
</Breadcrumbs>
</div>
</div>
<CustomMenu
className="flex-shrink-0 block sm:block md:hidden lg:hidden"
maxHeight="lg"
customButton={
<span className="text-xs px-1.5 py-1 border rounded-md text-custom-text-200 border-custom-border-300">{title}</span>
}
placement="bottom-start"
closeOnSelect
>
{PROJECT_SETTINGS_LINKS.map((item) => (
<CustomMenu.MenuItem key={item.key} onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}${item.href}`)}>
{item.label}
</CustomMenu.MenuItem>
))}
</CustomMenu>
</div>
</div>
);

View File

@ -1,12 +1,13 @@
import { FC } from "react";
import { useRouter } from "next/router";
// ui
import { Breadcrumbs } from "@plane/ui";
import { Breadcrumbs, CustomMenu } 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";
import { WORKSPACE_SETTINGS_LINKS } from "constants/workspace";
export interface IWorkspaceSettingHeader {
title: string;
@ -21,7 +22,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/>
<SidebarHamburgerToggle />
<div>
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
@ -30,9 +31,26 @@ export const WorkspaceSettingHeader: FC<IWorkspaceSettingHeader> = observer((pro
icon={<Settings className="h-4 w-4 text-custom-text-300" />}
link={`/${workspaceSlug}/settings`}
/>
<Breadcrumbs.BreadcrumbItem type="text" label={title} />
<div className="hidden sm:hidden md:block lg:block">
<Breadcrumbs.BreadcrumbItem type="text" label={title} />
</div>
</Breadcrumbs>
</div>
<CustomMenu
className="flex-shrink-0 block sm:block md:hidden lg:hidden"
maxHeight="lg"
customButton={
<span className="text-xs px-1.5 py-1 border rounded-md text-custom-text-200 border-custom-border-300">{title}</span>
}
placement="bottom-start"
closeOnSelect
>
{WORKSPACE_SETTINGS_LINKS.map((item) => (
<CustomMenu.MenuItem key={item.key} onClick={() => router.push(`/${workspaceSlug}${item.href}`)}>
{item.label}
</CustomMenu.MenuItem>
))}
</CustomMenu>
</div>
</div>
);

View File

@ -147,10 +147,10 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="relative mt-6 h-44 w-full">
<div className="absolute inset-0 z-[1] bg-gradient-to-t from-black/50 to-transparent" />
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
<img src={watch("cover_image")!} alt={watch("cover_image")!} className="h-44 w-full rounded-md object-cover" />
<div className="absolute bottom-4 z-10 flex w-full items-end justify-between gap-3 px-4">
<div className="absolute bottom-4 z-5 flex w-full items-end justify-between gap-3 px-4">
<div className="flex flex-grow gap-3 truncate">
<div className="flex h-[52px] w-[52px] flex-shrink-0 items-center justify-center rounded-lg bg-custom-background-90">
<div className="grid h-7 w-7 place-items-center">

View File

@ -1,4 +1,4 @@
import { Fragment } from "react";
import { Fragment, useState } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import Link from "next/link";
@ -6,6 +6,7 @@ import { useTheme } from "next-themes";
import { Menu, Transition } from "@headlessui/react";
import { mutate } from "swr";
import { Check, ChevronDown, CircleUserRound, LogOut, Mails, PlusSquare, Settings, UserCircle2 } from "lucide-react";
import { usePopper } from "react-popper";
// hooks
import { useApplication, useUser, useWorkspace } from "hooks/store";
// hooks
@ -14,7 +15,6 @@ import useToast from "hooks/use-toast";
import { Avatar, Loader } from "@plane/ui";
// types
import { IWorkspace } from "@plane/types";
// Static Data
const userLinks = (workspaceSlug: string, userId: string) => [
{
@ -36,7 +36,6 @@ const userLinks = (workspaceSlug: string, userId: string) => [
icon: Settings,
},
];
const profileLinks = (workspaceSlug: string, userId: string) => [
{
name: "View profile",
@ -49,7 +48,6 @@ const profileLinks = (workspaceSlug: string, userId: string) => [
link: "/profile",
},
];
export const WorkspaceSidebarDropdown = observer(() => {
// router
const router = useRouter();
@ -64,12 +62,25 @@ export const WorkspaceSidebarDropdown = observer(() => {
// hooks
const { setToastAlert } = useToast();
const { setTheme } = useTheme();
// popper-js refs
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
// popper-js init
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: "right",
modifiers: [
{
name: "preventOverflow",
options: {
padding: 12,
},
},
],
});
const handleWorkspaceNavigation = (workspace: IWorkspace) =>
updateCurrentUser({
last_workspace_id: workspace?.id,
});
const handleSignOut = async () => {
await signOut()
.then(() => {
@ -85,16 +96,12 @@ export const WorkspaceSidebarDropdown = observer(() => {
})
);
};
const handleItemClick = () => {
console.log('CLICKED')
if (window.innerWidth < 768) {
toggleSidebar();
}
};
const workspacesList = Object.values(workspaces ?? {});
// TODO: fix workspaces list scroll
return (
<div className="flex items-center gap-x-3 gap-y-2 px-4 pt-4">
@ -121,14 +128,12 @@ export const WorkspaceSidebarDropdown = observer(() => {
activeWorkspace?.name?.charAt(0) ?? "..."
)}
</div>
{!sidebarCollapsed && (
<h4 className="truncate text-base font-medium text-custom-text-100">
{activeWorkspace?.name ? activeWorkspace.name : "Loading..."}
</h4>
)}
</div>
{!sidebarCollapsed && (
<ChevronDown
className={`mx-1 hidden h-4 w-4 flex-shrink-0 group-hover/menu-button:block ${open ? "rotate-180" : ""
@ -137,7 +142,6 @@ export const WorkspaceSidebarDropdown = observer(() => {
)}
</div>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
@ -185,7 +189,6 @@ export const WorkspaceSidebarDropdown = observer(() => {
workspace?.name?.charAt(0) ?? "..."
)}
</span>
<h5
className={`truncate text-sm font-medium ${workspaceSlug === workspace.slug ? "" : "text-custom-text-200"
}`}
@ -226,9 +229,14 @@ export const WorkspaceSidebarDropdown = observer(() => {
</Menu.Item>
</Link>
{userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
<Link key={link.key} href={link.href} className="w-full" onClick={() => {
if (index > 0) handleItemClick();
}}>
<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"
@ -256,10 +264,9 @@ export const WorkspaceSidebarDropdown = observer(() => {
</>
)}
</Menu>
{!sidebarCollapsed && (
<Menu as="div" className="relative flex-shrink-0">
<Menu.Button className="grid place-items-center outline-none">
<Menu.Button className="grid place-items-center outline-none" ref={setReferenceElement}>
<Avatar
name={currentUser?.display_name}
src={currentUser?.avatar}
@ -268,7 +275,6 @@ export const WorkspaceSidebarDropdown = observer(() => {
className="!text-base"
/>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
@ -281,11 +287,20 @@ export const WorkspaceSidebarDropdown = observer(() => {
<Menu.Items
className="absolute left-0 z-20 mt-1 flex w-52 origin-top-left flex-col divide-y
divide-custom-sidebar-border-200 rounded-md border border-custom-sidebar-border-200 bg-custom-sidebar-background-100 px-1 py-2 text-xs shadow-lg outline-none"
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<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} onClick={() => { if (index == 0) handleItemClick(); }}>
<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]" />
@ -323,4 +338,4 @@ export const WorkspaceSidebarDropdown = observer(() => {
)}
</div>
);
});
});

View File

@ -41,11 +41,13 @@ export const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props)
}
/>
) : (
<div className="flex h-full w-full gap-2 overflow-x-hidden overflow-y-scroll">
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8">
<div className="inset-y-0 z-20 flex flex-grow-0 h-full w-full gap-2 overflow-x-hidden overflow-y-scroll">
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
<ProjectSettingsSidebar />
</div>
{children}
<div className="w-full pl-10 sm:pl-10 md:pl-0 lg:pl-0">
{children}
</div>
</div>
);
});

View File

@ -10,11 +10,13 @@ export const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = (props) => {
const { children } = props;
return (
<div className="flex h-full w-full gap-2 overflow-x-hidden overflow-y-scroll">
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8">
<div className="inset-y-0 z-20 flex h-full w-full gap-2 overflow-x-hidden overflow-y-scroll">
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
<WorkspaceSettingsSidebar />
</div>
{children}
<div className="w-full pl-10 sm:pl-10 md:pl-0 lg:pl-0">
{children}
</div>
</div>
);
};