Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WEB-808] style: workspace settings mobile responsiveness #4047

Merged
merged 7 commits into from
Apr 29, 2024
29 changes: 4 additions & 25 deletions web/components/headers/workspace-settings.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { FC } from "react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
// ui
import { Settings } from "lucide-react";
import { Breadcrumbs, CustomMenu } from "@plane/ui";
// hooks
// ui
import { Breadcrumbs } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common";
import { WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace";

export interface IWorkspaceSettingHeader {
title: string;
Expand All @@ -20,7 +18,7 @@ export const WorkspaceSettingHeader: FC<IWorkspaceSettingHeader> = observer((pro
const { workspaceSlug } = router.query;

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="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div>
<Breadcrumbs>
Expand All @@ -34,28 +32,9 @@ export const WorkspaceSettingHeader: FC<IWorkspaceSettingHeader> = observer((pro
/>
}
/>
<div className="hidden sm:hidden md:block lg:block">
<Breadcrumbs.BreadcrumbItem type="text" link={<BreadcrumbLink label={title} />} />
</div>
<Breadcrumbs.BreadcrumbItem type="text" link={<BreadcrumbLink label={title} />} />
</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>
);
Expand Down
153 changes: 78 additions & 75 deletions web/components/workspace/settings/members-list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@
}}
onSubmit={handleRemove}
/>
<div className="group flex items-center justify-between px-3 py-4 hover:bg-custom-background-90">
<div className="flex items-center gap-x-4 gap-y-2">
<div className="group w-full flex items-center justify-between px-3 py-4 hover:bg-custom-background-90">
<div className="flex w-full items-center gap-x-4 gap-y-2">
{memberDetails.member.avatar && memberDetails.member.avatar.trim() !== "" ? (
<Link href={`/${workspaceSlug}/profile/${memberDetails.member.id}`}>
<span className="relative flex h-10 w-10 items-center justify-center rounded p-4 capitalize text-white">
Expand All @@ -123,87 +123,90 @@
</span>
</Link>
)}
<div>
<Link href={`/${workspaceSlug}/profile/${memberDetails.member.id}`}>
<span className="text-sm font-medium">
{memberDetails.member.first_name} {memberDetails.member.last_name}
</span>
</Link>
<div className="flex items-center">
<div className="w-full">
<div className="flex w-full items-start justify-between">
<Link href={`/${workspaceSlug}/profile/${memberDetails.member.id}`}>
Fixed Show fixed Hide fixed
<div className="w-full overflow-hidden">
<span className="text-sm font-medium line-clamp-1">
{memberDetails.member.first_name} {memberDetails.member.last_name}
</span>
</div>
</Link>
<div className="flex flex-shrink-0 items-center gap-2 text-xs">
<CustomSelect
customButton={
<div className="item-center flex gap-1 rounded px-2 py-0.5">
<span
className={`flex items-center rounded text-xs font-medium ${hasRoleChangeAccess ? "" : "text-custom-sidebar-text-400"
}`}
>
{ROLE[memberDetails.role]}
</span>
{hasRoleChangeAccess && (
<span className="grid place-items-center">
<ChevronDown className="h-3 w-3" />
</span>
)}
</div>
}
value={memberDetails.role}
onChange={(value: EUserWorkspaceRoles) => {
if (!workspaceSlug || !value) return;

updateMember(workspaceSlug.toString(), memberDetails.member.id, {
role: value,
}).catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "An error occurred while updating member role. Please try again.",
});
});
}}
disabled={!hasRoleChangeAccess}
placement="bottom-end"
>
{Object.keys(ROLE).map((key) => {
if (currentWorkspaceRole && currentWorkspaceRole !== 20 && currentWorkspaceRole < parseInt(key))
return null;

return (
<CustomSelect.Option key={key} value={parseInt(key, 10)}>
<>{ROLE[parseInt(key) as keyof typeof ROLE]}</>
</CustomSelect.Option>
);
})}
</CustomSelect>
<Tooltip
isMobile={isMobile}
tooltipContent={isCurrentUser ? "Leave workspace" : "Remove member"}
disabled={!isAdmin && !isCurrentUser}
>
<button
type="button"
onClick={() => setRemoveMemberModal(true)}
className={
isAdmin || isCurrentUser
? "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100"
: "pointer-events-none opacity-0"
}
>
<XCircle className="h-3.5 w-3.5 text-red-500" strokeWidth={2} />
</button>
</Tooltip>
</div>
</div>
<div className="flex flex-col sm:flex-row items-start sm:items-center truncate">
<p className="text-xs text-custom-text-300">{memberDetails.member.display_name}</p>
{isAdmin && (
<>
<Dot height={16} width={16} className="text-custom-text-300" />
<p className="text-xs text-custom-text-300">{memberDetails.member.email}</p>
<Dot height={16} width={16} className="text-custom-text-300 hidden sm:block" />
<p className="text-xs text-custom-text-300 line-clamp-1 truncate">{memberDetails.member.email}</p>
</>
)}
</div>
</div>
</div>
<div className="flex items-center gap-2 text-xs">
<CustomSelect
customButton={
<div className="item-center flex gap-1 rounded px-2 py-0.5">
<span
className={`flex items-center rounded text-xs font-medium ${
hasRoleChangeAccess ? "" : "text-custom-sidebar-text-400"
}`}
>
{ROLE[memberDetails.role]}
</span>
{hasRoleChangeAccess && (
<span className="grid place-items-center">
<ChevronDown className="h-3 w-3" />
</span>
)}
</div>
}
value={memberDetails.role}
onChange={(value: EUserWorkspaceRoles) => {
if (!workspaceSlug || !value) return;

updateMember(workspaceSlug.toString(), memberDetails.member.id, {
role: value,
}).catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "An error occurred while updating member role. Please try again.",
});
});
}}
disabled={!hasRoleChangeAccess}
placement="bottom-end"
>
{Object.keys(ROLE).map((key) => {
if (currentWorkspaceRole && currentWorkspaceRole !== 20 && currentWorkspaceRole < parseInt(key))
return null;

return (
<CustomSelect.Option key={key} value={parseInt(key, 10)}>
<>{ROLE[parseInt(key) as keyof typeof ROLE]}</>
</CustomSelect.Option>
);
})}
</CustomSelect>
<Tooltip
isMobile={isMobile}
tooltipContent={isCurrentUser ? "Leave workspace" : "Remove member"}
disabled={!isAdmin && !isCurrentUser}
>
<button
type="button"
onClick={() => setRemoveMemberModal(true)}
className={
isAdmin || isCurrentUser
? "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100"
: "pointer-events-none opacity-0"
}
>
<XCircle className="h-3.5 w-3.5 text-red-500" strokeWidth={2} />
</button>
</Tooltip>
</div>
</div>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import router from "next/router";
import { WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace";

const MobileWorkspaceSettingsTabs = () => {
const { workspaceSlug } = router.query;
return (
<div className="md:hidden sticky flex overflow-x-auto">
{WORKSPACE_SETTINGS_LINKS.map((item, index) => (
<div
className={`${
item.highlight(router.asPath, `/${workspaceSlug}`)
? "text-custom-primary-100 text-sm py-2 px-3 whitespace-nowrap flex flex-grow cursor-pointer justify-around border-b border-custom-primary-200"
: "text-custom-text-200 flex flex-grow cursor-pointer justify-around border-b border-custom-border-200 text-sm py-2 px-3 whitespace-nowrap"
}`}
key={index}
onClick={() => router.push(`/${workspaceSlug}${item.href}`)}
>
{item.label}
</div>
))}
</div>
);
};

export default MobileWorkspaceSettingsTabs;
8 changes: 6 additions & 2 deletions web/layouts/settings-layout/workspace/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FC, ReactNode } from "react";
// components
import MobileWorkspaceSettingsTabs from "@/components/workspace/settings/mobile-workspace-settings-tabs";
import { WorkspaceSettingsSidebar } from "./sidebar";

export interface IWorkspaceSettingLayout {
Expand All @@ -14,8 +15,11 @@ export const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = (props) => {
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
<WorkspaceSettingsSidebar />
</div>
<div className="w-full pl-10 sm:pl-10 md:pl-0 lg:pl-0 overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md">
{children}
<div className="relative w-full overflow-hidden">
<MobileWorkspaceSettingsTabs />
<div className="w-full pl-10 md:pl-0 overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md">
{children}
</div>
</div>
</div>
);
Expand Down
Loading