style: app sidebar revamp (#1120)

* style: app sidebar, sidebar workspace dropdown and help section styling

* style: consistent  padding and spacing

* feat: material icon global component

* style: icons updated and tooltip added

* style: project list spacing and project name truncate

* style: sidebar padding and theming

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
This commit is contained in:
Anmol Singh Bhatia 2023-07-13 18:35:43 +05:30 committed by GitHub
parent 3f3fb373cc
commit 60e96bcb72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 305 additions and 329 deletions

View File

@ -70,8 +70,7 @@ const TOUR_STEPS: {
{
key: "pages",
title: "Document with pages",
description:
"Modules break your big think into Projects or Features, to help you organize better.",
description: "Use Pages to quickly jot down issues when you're in a meeting or starting a day.",
image: PagesTour,
prevStep: "views",
},

View File

@ -151,11 +151,11 @@ export const ProjectSidebarList: FC = () => {
data={projectToDelete}
user={user}
/>
<div className="mt-2.5 h-full overflow-y-auto border-t border-custom-sidebar-border-100 bg-custom-sidebar-background-100 pt-2.5">
<div className="h-full overflow-y-auto mt-5 px-4">
{favoriteProjects && favoriteProjects.length > 0 && (
<div className="mt-3 flex flex-col space-y-2 px-3">
<div className="flex flex-col space-y-2">
{!sidebarCollapse && (
<h5 className="text-sm font-semibold text-custom-sidebar-text-200">Favorites</h5>
<h5 className="text-sm font-medium text-custom-sidebar-text-200">Favorites</h5>
)}
{favoriteProjects.map((favoriteProject) => {
const project = favoriteProject.project_detail;
@ -173,9 +173,9 @@ export const ProjectSidebarList: FC = () => {
})}
</div>
)}
<div className="flex flex-col space-y-2 p-3">
<div className="flex flex-col space-y-2 mt-5">
{!sidebarCollapse && (
<h5 className="text-sm font-semibold text-custom-sidebar-text-200">Projects</h5>
<h5 className="text-sm font-medium text-custom-sidebar-text-200">Projects</h5>
)}
{projects ? (
<>

View File

@ -4,22 +4,9 @@ import { useRouter } from "next/router";
// headless ui
import { Disclosure, Transition } from "@headlessui/react";
// ui
import { CustomMenu, Icon } from "components/ui";
import { CustomMenu, Icon, Tooltip } from "components/ui";
// icons
import {
ChevronDownIcon,
DocumentTextIcon,
LinkIcon,
StarIcon,
TrashIcon,
} from "@heroicons/react/24/outline";
import {
ContrastIcon,
LayerDiagonalIcon,
PeopleGroupIcon,
SettingIcon,
ViewListIcon,
} from "components/icons";
import { LinkIcon, StarIcon, TrashIcon } from "@heroicons/react/24/outline";
// helpers
import { truncateText } from "helpers/string.helper";
import { renderEmoji } from "helpers/emoji.helper";
@ -39,32 +26,32 @@ const navigation = (workspaceSlug: string, projectId: string) => [
{
name: "Issues",
href: `/${workspaceSlug}/projects/${projectId}/issues`,
icon: LayerDiagonalIcon,
icon: "stack",
},
{
name: "Cycles",
href: `/${workspaceSlug}/projects/${projectId}/cycles`,
icon: ContrastIcon,
icon: "contrast",
},
{
name: "Modules",
href: `/${workspaceSlug}/projects/${projectId}/modules`,
icon: PeopleGroupIcon,
icon: "dataset",
},
{
name: "Views",
href: `/${workspaceSlug}/projects/${projectId}/views`,
icon: ViewListIcon,
icon: "photo_filter",
},
{
name: "Pages",
href: `/${workspaceSlug}/projects/${projectId}/pages`,
icon: DocumentTextIcon,
icon: "article",
},
{
name: "Settings",
href: `/${workspaceSlug}/projects/${projectId}/settings`,
icon: SettingIcon,
icon: "settings",
},
];
@ -84,44 +71,56 @@ export const SingleSidebarProject: React.FC<Props> = ({
{({ open }) => (
<>
<div className="flex items-center gap-x-1 text-custom-sidebar-text-100">
<Disclosure.Button
as="div"
className={`flex w-full cursor-pointer select-none items-center rounded-md py-2 text-left text-sm font-medium ${
sidebarCollapse ? "justify-center" : "justify-between"
}`}
<Tooltip
tooltipContent={`${project?.name}`}
position="right"
className="ml-2"
disabled={!sidebarCollapse}
>
<div className="flex items-center gap-x-2">
{project.emoji ? (
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded uppercase">
{renderEmoji(project.emoji)}
</span>
) : project.icon_prop ? (
<div className="h-7 w-7 grid place-items-center">
<span
style={{ color: project.icon_prop.color }}
className="material-symbols-rounded text-lg"
>
{project.icon_prop.name}
<Disclosure.Button
as="div"
className={`flex w-full cursor-pointer select-none items-center rounded-sm py-1 text-left text-sm font-medium ${
sidebarCollapse ? "justify-center" : "justify-between"
}`}
>
<div className="flex items-center gap-x-2">
{project.emoji ? (
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded uppercase">
{renderEmoji(project.emoji)}
</span>
</div>
) : (
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded bg-gray-700 uppercase text-white">
{project?.name.charAt(0)}
</span>
)}
) : project.icon_prop ? (
<div className="h-7 w-7 grid place-items-center">
<span
style={{ color: project.icon_prop.color }}
className="material-symbols-rounded text-lg"
>
{project.icon_prop.name}
</span>
</div>
) : (
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded bg-gray-700 uppercase text-white">
{project?.name.charAt(0)}
</span>
)}
{!sidebarCollapse && (
<p
className={`overflow-hidden text-ellipsis ${
open ? "" : "text-custom-sidebar-text-200"
}`}
>
{truncateText(project?.name, 14)}
</p>
)}
</div>
{!sidebarCollapse && (
<h5 className={`overflow-hidden text-sm ${open ? "" : "text-custom-text-200"}`}>
{truncateText(project?.name, 20)}
</h5>
<Icon
iconName="expand_more"
className={`${open ? "rotate-180" : ""} text-custom-text-200 duration-300`}
/>
)}
</div>
{!sidebarCollapse && (
<span>
<ChevronDownIcon className={`h-4 w-4 duration-300 ${open ? "rotate-180" : ""}`} />
</span>
)}
</Disclosure.Button>
</Disclosure.Button>
</Tooltip>
{!sidebarCollapse && (
<CustomMenu ellipsis>
@ -177,9 +176,7 @@ export const SingleSidebarProject: React.FC<Props> = ({
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Disclosure.Panel
className={`${sidebarCollapse ? "" : "ml-[2.25rem]"} flex flex-col gap-y-1`}
>
<Disclosure.Panel className={`space-y-2 ${sidebarCollapse ? "" : "ml-[2.25rem]"}`}>
{navigation(workspaceSlug as string, project?.id).map((item) => {
if (
(item.name === "Cycles" && !project.cycle_view) ||
@ -191,25 +188,24 @@ export const SingleSidebarProject: React.FC<Props> = ({
return (
<Link key={item.name} href={item.href}>
<a
className={`group flex items-center rounded-md p-2 text-xs font-medium outline-none ${
router.asPath.includes(item.href)
? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 focus:bg-custom-sidebar-background-90"
} ${sidebarCollapse ? "justify-center" : ""}`}
>
<div className="grid place-items-center">
<item.icon
className={`h-5 w-5 flex-shrink-0 ${!sidebarCollapse ? "mr-3" : ""}`}
color={
<a className="block w-full">
<Tooltip
tooltipContent={`${project?.name}: ${item.name}`}
position="right"
className="ml-2"
disabled={!sidebarCollapse}
>
<div
className={`group flex items-center rounded-md px-2 py-1.5 gap-2 text-xs font-medium outline-none ${
router.asPath.includes(item.href)
? "rgb(var(--color-sidebar-text-100))"
: "rgb(var(--color-sidebar-text-200))"
}
aria-hidden="true"
/>
</div>
{!sidebarCollapse && item.name}
? "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"
} ${sidebarCollapse ? "justify-center" : ""}`}
>
<Icon iconName={item.icon} />
{!sidebarCollapse && item.name}
</div>
</Tooltip>
</a>
</Link>
);

View File

@ -5,6 +5,7 @@ import Link from "next/link";
import { Menu, Transition } from "@headlessui/react";
// icons
import { ChevronDownIcon, EllipsisHorizontalIcon } from "@heroicons/react/24/outline";
import { Icon } from "./icon";
type Props = {
children: React.ReactNode;
@ -61,8 +62,9 @@ const CustomMenu = ({
type="button"
className="relative grid place-items-center rounded p-1 text-custom-text-200 hover:bg-custom-background-80 outline-none"
>
<EllipsisHorizontalIcon
className={`h-4 w-4 ${verticalEllipsis ? "rotate-90" : ""}`}
<Icon
iconName="more_horiz"
className={`${verticalEllipsis ? "rotate-90" : ""} text-brand-secondary`}
/>
</Menu.Button>
) : (

View File

@ -1,4 +1,4 @@
import { useState, useRef, FC } from "react";
import React, { useRef, useState } from "react";
import { useRouter } from "next/router";
@ -8,9 +8,16 @@ import useSWR from "swr";
// headless ui
import { Transition } from "@headlessui/react";
// services
import workspaceService from "services/workspace.service";
// hooks
import useTheme from "hooks/use-theme";
import useUser from "hooks/use-user";
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// components
import UpgradeToProModal from "./upgrade-to-pro-modal";
// ui
import { CircularProgress } from "components/ui";
// icons
import {
ArrowLongLeftIcon,
@ -20,15 +27,8 @@ import {
XMarkIcon,
} from "@heroicons/react/24/outline";
import { QuestionMarkCircleIcon, DocumentIcon, DiscordIcon, GithubIcon } from "components/icons";
// services
import workspaceService from "services/workspace.service";
// fetch-keys
import { WORKSPACE_DETAILS } from "constants/fetch-keys";
// ui
import { CircularProgress } from "components/ui";
// components
import UpgradeToProModal from "./upgrade-to-pro-modal";
import useUser from "hooks/use-user";
const helpOptions = [
{
@ -58,36 +58,28 @@ export interface WorkspaceHelpSectionProps {
setSidebarActive: React.Dispatch<React.SetStateAction<boolean>>;
}
type progress = {
progress: number;
};
export const WorkspaceHelpSection: FC<WorkspaceHelpSectionProps> = (props) => {
// router
export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setSidebarActive }) => {
const [alert, setAlert] = useState(false);
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
const router = useRouter();
const { workspaceSlug } = router.query;
const { setSidebarActive } = props;
// theme
const { collapsed: sidebarCollapse, toggleCollapsed } = useTheme();
// states
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
// refs
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
// hooks
useOutsideClickDetector(helpOptionsRef, () => setIsNeedHelpOpen(false));
const { user } = useUser();
const helpOptionMode = sidebarCollapse ? "left-full" : "left-[-75px]";
const [alert, setAlert] = useState(false);
const [upgradeModal, setUpgradeModal] = useState(false);
const { data: workspaceDetails } = useSWR(
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
workspaceSlug ? () => workspaceService.getWorkspace(workspaceSlug as string) : null
);
const issueNumber = workspaceDetails?.total_issues || 0;
return (
@ -98,61 +90,58 @@ export const WorkspaceHelpSection: FC<WorkspaceHelpSectionProps> = (props) => {
user={user}
issueNumber={issueNumber}
/>
{!sidebarCollapse && (alert || (issueNumber && issueNumber >= 750)) ? (
<>
<div
className={`border-t p-4 ${
issueNumber >= 750
? "bg-red-50 text-red-600 border-red-200"
: issueNumber >= 500
? "bg-yellow-50 text-yellow-600 border-yellow-200"
: "text-green-600"
}`}
>
<div className="flex items-center gap-2 w-full">
<CircularProgress progress={(issueNumber / 1024) * 100} />
<div className="">Free Plan</div>
{issueNumber < 750 && (
<div className="ml-auto text-custom-text-200" onClick={() => setAlert(false)}>
<XMarkIcon className="h-4 w-4" />
</div>
)}
</div>
<div className="text-custom-text-200 text-xs mt-2">
This workspace has used {issueNumber} of its 1024 issues creation limit (
{((issueNumber / 1024) * 100).toFixed(0)}
%).
</div>
{!sidebarCollapse && (alert || issueNumber >= 750) && (
<div
className={`border-t border-custom-sidebar-border-100 p-4 ${
issueNumber >= 750
? "bg-red-500/10 text-red-600"
: issueNumber >= 500
? "bg-yellow-500/10 text-yellow-600"
: "text-green-600"
}`}
>
<div className="flex items-center gap-2">
<CircularProgress progress={(issueNumber / 1024) * 100} />
<div>Free Plan</div>
{issueNumber < 750 && (
<div
className="ml-auto text-custom-text-200 cursor-pointer"
onClick={() => setAlert(false)}
>
<XMarkIcon className="h-4 w-4" />
</div>
)}
</div>
</>
) : (
""
<div className="text-custom-text-200 text-xs mt-2">
This workspace has used {issueNumber} of its 1024 issues creation limit (
{((issueNumber / 1024) * 100).toFixed(0)}
%).
</div>
</div>
)}
<div
className={`flex w-full items-center justify-between self-baseline border-t border-custom-border-100 bg-custom-sidebar-background-100 px-6 py-2 ${
className={`flex w-full items-center justify-between gap-1 self-baseline border-t border-custom-border-100 bg-custom-sidebar-background-100 px-4 py-2 ${
sidebarCollapse ? "flex-col" : ""
}`}
>
{alert || (issueNumber && issueNumber >= 750) ? (
{alert || issueNumber >= 750 ? (
<button
type="button"
className={`flex items-center gap-x-1 rounded-md px-2 py-2 font-medium outline-none text-sm
${
className={`flex items-center gap-2 rounded-md px-2.5 py-1.5 font-medium outline-none text-sm ${
issueNumber >= 750
? "bg-custom-primary-100 text-white"
? "bg-red-500/10 text-red-500"
: "bg-blue-500/10 text-custom-primary-100"
}
${sidebarCollapse ? "w-full justify-center" : ""}`}
} ${sidebarCollapse ? "w-full justify-center" : ""}`}
title="Shortcuts"
onClick={() => setUpgradeModal(true)}
>
<ArrowUpCircleIcon className="h-4 w-4 " />
{!sidebarCollapse && <span> Learn more</span>}
<ArrowUpCircleIcon className="h-4 w-4" />
{!sidebarCollapse && <span>Learn more</span>}
</button>
) : (
<button
type="button"
className={`flex items-center gap-x-1 rounded-md px-2 py-2 font-medium outline-none text-sm ${
className={`flex items-center gap-2 rounded-md px-2.5 py-1.5 font-medium outline-none text-sm ${
issueNumber >= 750
? "bg-red-500/10 text-red-600"
: issueNumber >= 500
@ -169,7 +158,6 @@ export const WorkspaceHelpSection: FC<WorkspaceHelpSectionProps> = (props) => {
{!sidebarCollapse && <span>Free Plan</span>}
</button>
)}
<button
type="button"
className={`flex items-center gap-x-1 rounded-md px-2 py-2 text-xs font-medium text-custom-text-200 outline-none hover:bg-custom-background-90 hover:text-custom-text-100 ${
@ -184,7 +172,6 @@ export const WorkspaceHelpSection: FC<WorkspaceHelpSectionProps> = (props) => {
title="Shortcuts"
>
<RocketLaunchIcon className="h-4 w-4 text-custom-text-200" />
{/* {!sidebarCollapse && <span>Shortcuts</span>} */}
</button>
<button
type="button"
@ -195,7 +182,6 @@ export const WorkspaceHelpSection: FC<WorkspaceHelpSectionProps> = (props) => {
title="Help"
>
<QuestionMarkCircleIcon className="h-4 w-4 text-custom-text-200" />
{/* {!sidebarCollapse && <span>Help</span>} */}
</button>
<button
type="button"
@ -229,7 +215,9 @@ export const WorkspaceHelpSection: FC<WorkspaceHelpSectionProps> = (props) => {
leaveTo="transform opacity-0 scale-95"
>
<div
className={`absolute bottom-2 ${helpOptionMode} space-y-2 rounded-sm bg-custom-background-80 p-1 shadow-md`}
className={`absolute bottom-2 ${
sidebarCollapse ? "left-full" : "left-[-75px]"
} space-y-2 rounded-sm bg-custom-background-80 p-1 shadow-md`}
ref={helpOptionsRef}
>
{helpOptions.map(({ name, Icon, href, onClick }) => {

View File

@ -86,157 +86,155 @@ export const WorkspaceSidebarDropdown = () => {
};
return (
<div className="relative">
<Menu as="div" className="col-span-4 inline-block w-full p-3 text-left">
<div className="flex items-center justify-between gap-2.5">
<Menu.Button className="text-custom-sidebar-text-200 flex w-full items-center rounded-md py-2 text-sm font-semibold focus:outline-none">
<div
className={`flex w-full items-center gap-x-2 rounded-md bg-custom-sidebar-background-80 px-2 py-1.5 ${
sidebarCollapse ? "justify-center" : ""
}`}
>
<div className="relative grid h-6 w-6 place-items-center rounded bg-gray-700 uppercase text-white">
{activeWorkspace?.logo && activeWorkspace.logo !== "" ? (
<img
src={activeWorkspace.logo}
className="absolute top-0 left-0 h-full w-full object-cover rounded"
alt="Workspace Logo"
/>
) : (
activeWorkspace?.name?.charAt(0) ?? "..."
)}
</div>
{!sidebarCollapse && (
<h4 className="text-custom-text-100">
{activeWorkspace?.name ? truncateText(activeWorkspace.name, 14) : "Loading..."}
</h4>
)}
</div>
</Menu.Button>
{!sidebarCollapse && (
<Link href={`/${workspaceSlug}/me/profile`}>
<a>
<div className="flex flex-grow justify-end">
<Avatar user={user} height="32px" width="32px" fontSize="14px" />
</div>
</a>
</Link>
)}
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="fixed left-2 z-20 mt-1 flex w-full max-w-[17rem] origin-top-left flex-col rounded-md
border border-custom-sidebar-border-100 bg-custom-sidebar-background-90 shadow-lg focus:outline-none"
<Menu as="div" className="relative col-span-4 inline-block w-full px-4 pt-4 text-left">
<div className="flex items-center justify-between gap-2">
<Menu.Button className="text-custom-sidebar-text-200 flex w-full items-center rounded-sm text-sm font-medium focus:outline-none">
<div
className={`flex w-full items-center gap-x-2 rounded-sm bg-custom-sidebar-background-80 p-1 ${
sidebarCollapse ? "justify-center" : ""
}`}
>
<div className="flex flex-col items-start justify-start gap-3 p-3">
<div className="text-sm text-custom-sidebar-text-200">{user?.email}</div>
<span className="text-sm font-semibold text-custom-sidebar-text-200">Workspace</span>
{workspaces ? (
<div className="flex h-full w-full flex-col items-start justify-start gap-3.5">
{workspaces.length > 0 ? (
workspaces.map((workspace) => (
<Menu.Item key={workspace.id}>
{({ active }) => (
<button
type="button"
onClick={() => handleWorkspaceNavigation(workspace)}
className="flex w-full items-center justify-between gap-1 rounded-md text-sm text-custom-sidebar-text-100"
>
<div className="flex items-center justify-start gap-2.5">
<span className="relative flex h-6 w-6 items-center justify-center rounded bg-gray-700 p-2 text-xs uppercase text-white">
{workspace?.logo && workspace.logo !== "" ? (
<img
src={workspace.logo}
className="absolute top-0 left-0 h-full w-full object-cover rounded"
alt="Workspace Logo"
/>
) : (
workspace?.name?.charAt(0) ?? "..."
)}
</span>
<h5
className={`text-sm ${
workspaceSlug === workspace.slug ? "" : "text-custom-text-200"
}`}
>
{truncateText(workspace.name, 18)}
</h5>
</div>
<span className="p-1">
<CheckIcon
className={`h-3 w-3.5 text-custom-sidebar-text-100 ${
active || workspace.id === activeWorkspace?.id
? "opacity-100"
: "opacity-0"
}`}
/>
</span>
</button>
)}
</Menu.Item>
))
) : (
<p>No workspace found!</p>
)}
<Menu.Item
as="button"
type="button"
onClick={() => {
router.push("/create-workspace");
}}
className="flex w-full items-center gap-1 text-sm text-custom-sidebar-text-200"
>
<PlusIcon className="h-3 w-3" />
Create Workspace
</Menu.Item>
</div>
<div className="relative grid h-6 w-6 place-items-center rounded bg-gray-700 uppercase text-white">
{activeWorkspace?.logo && activeWorkspace.logo !== "" ? (
<img
src={activeWorkspace.logo}
className="absolute top-0 left-0 h-full w-full object-cover rounded"
alt="Workspace Logo"
/>
) : (
<div className="w-full">
<Loader className="space-y-2">
<Loader.Item height="30px" />
<Loader.Item height="30px" />
</Loader>
</div>
activeWorkspace?.name?.charAt(0) ?? "..."
)}
</div>
<div className="flex w-full flex-col items-start justify-start gap-2 border-t border-custom-sidebar-border-100 px-3 py-2 text-sm">
{userLinks(workspaceSlug as string).map((link, index) => (
{!sidebarCollapse && (
<h4 className="text-custom-text-100">
{activeWorkspace?.name ? truncateText(activeWorkspace.name, 14) : "Loading..."}
</h4>
)}
</div>
</Menu.Button>
{!sidebarCollapse && (
<Link href={`/${workspaceSlug}/me/profile`}>
<a>
<div className="flex flex-grow justify-end">
<Avatar user={user} height="28px" width="28px" fontSize="14px" />
</div>
</a>
</Link>
)}
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="fixed left-2 z-20 mt-1 flex w-full max-w-[17rem] origin-top-left flex-col rounded-md
border border-custom-sidebar-border-100 bg-custom-sidebar-background-90 shadow-lg focus:outline-none"
>
<div className="flex flex-col items-start justify-start gap-3 p-3">
<div className="text-sm text-custom-sidebar-text-200">{user?.email}</div>
<span className="text-sm font-semibold text-custom-sidebar-text-200">Workspace</span>
{workspaces ? (
<div className="flex h-full w-full flex-col items-start justify-start gap-3.5">
{workspaces.length > 0 ? (
workspaces.map((workspace) => (
<Menu.Item key={workspace.id}>
{({ active }) => (
<button
type="button"
onClick={() => handleWorkspaceNavigation(workspace)}
className="flex w-full items-center justify-between gap-1 rounded-md text-sm text-custom-sidebar-text-100"
>
<div className="flex items-center justify-start gap-2.5">
<span className="relative flex h-6 w-6 items-center justify-center rounded bg-gray-700 p-2 text-xs uppercase text-white">
{workspace?.logo && workspace.logo !== "" ? (
<img
src={workspace.logo}
className="absolute top-0 left-0 h-full w-full object-cover rounded"
alt="Workspace Logo"
/>
) : (
workspace?.name?.charAt(0) ?? "..."
)}
</span>
<h5
className={`text-sm ${
workspaceSlug === workspace.slug ? "" : "text-custom-text-200"
}`}
>
{truncateText(workspace.name, 18)}
</h5>
</div>
<span className="p-1">
<CheckIcon
className={`h-3 w-3.5 text-custom-sidebar-text-100 ${
active || workspace.id === activeWorkspace?.id
? "opacity-100"
: "opacity-0"
}`}
/>
</span>
</button>
)}
</Menu.Item>
))
) : (
<p>No workspace found!</p>
)}
<Menu.Item
key={index}
as="div"
className="flex w-full items-center justify-start rounded px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
as="button"
type="button"
onClick={() => {
router.push("/create-workspace");
}}
className="flex w-full items-center gap-1 text-sm text-custom-sidebar-text-200"
>
<Link href={link.href}>
<a className="w-full">{link.name}</a>
</Link>
<PlusIcon className="h-3 w-3" />
Create Workspace
</Menu.Item>
))}
</div>
<div className="w-full border-t border-t-custom-sidebar-border-100 px-3 py-2">
</div>
) : (
<div className="w-full">
<Loader className="space-y-2">
<Loader.Item height="30px" />
<Loader.Item height="30px" />
</Loader>
</div>
)}
</div>
<div className="flex w-full flex-col items-start justify-start gap-2 border-t border-custom-sidebar-border-100 px-3 py-2 text-sm">
{userLinks(workspaceSlug as string).map((link, index) => (
<Menu.Item
as="button"
type="button"
className="flex w-full items-center justify-start rounded px-2 py-1 text-sm text-red-600 hover:bg-custom-sidebar-background-80"
onClick={handleSignOut}
key={index}
as="div"
className="flex w-full items-center justify-start rounded px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
>
Sign out
<Link href={link.href}>
<a className="w-full">{link.name}</a>
</Link>
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
))}
</div>
<div className="w-full border-t border-t-custom-sidebar-border-100 px-3 py-2">
<Menu.Item
as="button"
type="button"
className="flex w-full items-center justify-start rounded px-2 py-1 text-sm text-red-600 hover:bg-custom-sidebar-background-80"
onClick={handleSignOut}
>
Sign out
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</Menu>
);
};

View File

@ -5,9 +5,8 @@ import Link from "next/link";
// hooks
import useTheme from "hooks/use-theme";
// icons
import { ChartBarIcon } from "@heroicons/react/24/outline";
import { GridViewIcon, AssignmentClipboardIcon, TickMarkIcon, SettingIcon } from "components/icons";
// components
import { Icon, Tooltip } from "components/ui";
export const WorkspaceSidebarMenu = () => {
const router = useRouter();
@ -18,34 +17,34 @@ export const WorkspaceSidebarMenu = () => {
const workspaceLinks = (workspaceSlug: string) => [
{
icon: GridViewIcon,
icon: "grid_view",
name: "Dashboard",
href: `/${workspaceSlug}`,
},
{
icon: ChartBarIcon,
icon: "bar_chart",
name: "Analytics",
href: `/${workspaceSlug}/analytics`,
},
{
icon: AssignmentClipboardIcon,
icon: "work",
name: "Projects",
href: `/${workspaceSlug}/projects`,
},
{
icon: TickMarkIcon,
icon: "task_alt",
name: "My Issues",
href: `/${workspaceSlug}/me/my-issues`,
},
{
icon: SettingIcon,
icon: "settings",
name: "Settings",
href: `/${workspaceSlug}/settings`,
},
];
return (
<div className="flex w-full flex-col items-start justify-start gap-2 px-3 py-1">
<div className="w-full cursor-pointer space-y-2 px-4 mt-5">
{workspaceLinks(workspaceSlug as string).map((link, index) => {
const isActive =
link.name === "Settings"
@ -54,28 +53,24 @@ export const WorkspaceSidebarMenu = () => {
return (
<Link key={index} href={link.href}>
<a
className={`${
isActive
? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100"
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 focus:bg-custom-sidebar-background-90"
} group flex w-full items-center gap-3 rounded-md p-2 text-sm font-medium outline-none ${
sidebarCollapse ? "justify-center" : ""
}`}
>
<span className="grid h-5 w-5 flex-shrink-0 place-items-center">
<link.icon
color={
<a className="block w-full">
<Tooltip
tooltipContent={link.name}
position="right"
className="ml-2"
disabled={!sidebarCollapse}
>
<div
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${
isActive
? "rgb(var(--color-sidebar-text-100))"
: "rgb(var(--color-sidebar-text-200))"
}
aria-hidden="true"
height="20"
width="20"
/>
</span>
{!sidebarCollapse && link.name}
? "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"
} ${sidebarCollapse ? "justify-center" : ""}`}
>
<Icon iconName={`${link.icon}`} />
{!sidebarCollapse && link.name}
</div>
</Tooltip>
</a>
</Link>
);

View File

@ -19,13 +19,11 @@ const Sidebar: React.FC<SidebarProps> = ({ toggleSidebar, setToggleSidebar }) =>
return (
<div
className={`z-20 h-full flex-shrink-0 border-r border-custom-sidebar-border-100 ${
sidebarCollapse ? "" : "w-auto md:w-[17rem]"
} fixed inset-y-0 top-0 ${
toggleSidebar ? "left-0" : "-left-full md:left-0"
} flex h-full flex-col bg-custom-sidebar-background-100 duration-300 md:relative`}
className={`fixed md:relative inset-y-0 flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-100 z-20 duration-300 ${
sidebarCollapse ? "" : "md:w-72"
} ${toggleSidebar ? "left-0" : "-left-full md:left-0"}`}
>
<div className="flex h-full flex-1 flex-col">
<div className="flex h-full w-full flex-1 flex-col">
<WorkspaceSidebarDropdown />
<WorkspaceSidebarMenu />
<ProjectSidebarList />

View File

@ -14,7 +14,7 @@ export interface IWorkspace {
readonly created_by: string;
readonly updated_by: string;
organization_size: string;
total_issues: number | null;
total_issues: number;
}
export interface IWorkspaceLite {