feat: page improvement (#797)

* feat: remove label icon added

* feat: block menu dropdown state added

* feat: page info icon added and  style: overflow title and label fix
This commit is contained in:
Anmol Singh Bhatia 2023-04-12 18:07:50 +05:30 committed by GitHub
parent f2e8add29d
commit d6dbfdc731
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 16 deletions

View file

@ -1,9 +1,11 @@
import { useState } from "react"; import { useState } from "react";
import useSWR, { mutate } from "swr";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// services // services
import pagesService from "services/pages.service"; import pagesService from "services/pages.service";
import projectService from "services/project.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// components // components
@ -23,9 +25,9 @@ import {
ALL_PAGES_LIST, ALL_PAGES_LIST,
FAVORITE_PAGES_LIST, FAVORITE_PAGES_LIST,
MY_PAGES_LIST, MY_PAGES_LIST,
PROJECT_MEMBERS,
RECENT_PAGES_LIST, RECENT_PAGES_LIST,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
import { mutate } from "swr";
type Props = { type Props = {
pages: IPage[] | undefined; pages: IPage[] | undefined;
@ -44,6 +46,13 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { data: people } = useSWR(
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
workspaceSlug && projectId
? () => projectService.projectMembers(workspaceSlug as string, projectId as string)
: null
);
const handleEditPage = (page: IPage) => { const handleEditPage = (page: IPage) => {
setSelectedPageToUpdate(page); setSelectedPageToUpdate(page);
setCreateUpdatePageModal(true); setCreateUpdatePageModal(true);
@ -198,6 +207,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
<SinglePageListItem <SinglePageListItem
key={page.id} key={page.id}
page={page} page={page}
people={people}
handleEditPage={() => handleEditPage(page)} handleEditPage={() => handleEditPage(page)}
handleDeletePage={() => handleDeletePage(page)} handleDeletePage={() => handleDeletePage(page)}
handleAddToFavorites={() => handleAddToFavorites(page)} handleAddToFavorites={() => handleAddToFavorites(page)}
@ -212,6 +222,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
<SinglePageDetailedItem <SinglePageDetailedItem
key={page.id} key={page.id}
page={page} page={page}
people={people}
handleEditPage={() => handleEditPage(page)} handleEditPage={() => handleEditPage(page)}
handleDeletePage={() => handleDeletePage(page)} handleDeletePage={() => handleDeletePage(page)}
handleAddToFavorites={() => handleAddToFavorites(page)} handleAddToFavorites={() => handleAddToFavorites(page)}
@ -226,6 +237,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
<SinglePageDetailedItem <SinglePageDetailedItem
key={page.id} key={page.id}
page={page} page={page}
people={people}
handleEditPage={() => handleEditPage(page)} handleEditPage={() => handleEditPage(page)}
handleDeletePage={() => handleDeletePage(page)} handleDeletePage={() => handleDeletePage(page)}
handleAddToFavorites={() => handleAddToFavorites(page)} handleAddToFavorites={() => handleAddToFavorites(page)}

View file

@ -1,4 +1,4 @@
import { useEffect, useState } from "react"; import { useEffect, useState, useRef } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Link from "next/link"; import Link from "next/link";
@ -16,6 +16,7 @@ import issuesService from "services/issues.service";
import aiService from "services/ai.service"; import aiService from "services/ai.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// components // components
import { GptAssistantModal } from "components/core"; import { GptAssistantModal } from "components/core";
import { CreateUpdateBlockInline } from "components/pages"; import { CreateUpdateBlockInline } from "components/pages";
@ -61,6 +62,9 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
const [gptAssistantModal, setGptAssistantModal] = useState(false); const [gptAssistantModal, setGptAssistantModal] = useState(false);
const [isMenuActive, setIsMenuActive] = useState(false);
const actionSectionRef = useRef<HTMLDivElement | null>(null);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, pageId } = router.query; const { workspaceSlug, projectId, pageId } = router.query;
@ -274,6 +278,7 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
reset({ ...block }); reset({ ...block });
}, [reset, block]); }, [reset, block]);
useOutsideClickDetector(actionSectionRef, () => setIsMenuActive(false));
return ( return (
<Draggable draggableId={block.id} index={index} isDragDisabled={createBlockForm}> <Draggable draggableId={block.id} index={index} isDragDisabled={createBlockForm}>
{(provided, snapshot) => ( {(provided, snapshot) => (
@ -308,7 +313,12 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
<EllipsisVerticalIcon className="h-[18px]" /> <EllipsisVerticalIcon className="h-[18px]" />
<EllipsisVerticalIcon className="h-[18px] -ml-3" /> <EllipsisVerticalIcon className="h-[18px] -ml-3" />
</button> </button>
<div className="absolute top-4 right-0 items-center gap-2 hidden group-hover:!flex bg-white pl-4"> <div
ref={actionSectionRef}
className={`absolute top-4 right-0 items-center gap-2 hidden group-hover:!flex bg-white pl-4 ${
isMenuActive ? "!flex" : ""
}`}
>
{block.issue && block.sync && ( {block.issue && block.sync && (
<div className="flex flex-shrink-0 cursor-default items-center gap-1 rounded bg-gray-100 py-1 px-1.5 text-xs"> <div className="flex flex-shrink-0 cursor-default items-center gap-1 rounded bg-gray-100 py-1 px-1.5 text-xs">
{isSyncing ? ( {isSyncing ? (
@ -350,7 +360,16 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
> >
<PencilIcon className="h-3.5 w-3.5" /> <PencilIcon className="h-3.5 w-3.5" />
</button> </button>
<CustomMenu label={<BoltIcon className="h-4.5 w-3.5" />} noBorder noChevron> <CustomMenu
customButton={
<button
className="flex cursor-pointer items-center justify-between gap-1 px-2.5 py-1 text-xs duration-300 hover:bg-gray-100 text-left rounded w-full"
onClick={() => setIsMenuActive(!isMenuActive)}
>
<BoltIcon className="h-4.5 w-3.5" />
</button>
}
>
{block.issue ? ( {block.issue ? (
<> <>
<CustomMenu.MenuItem onClick={handleBlockSync}> <CustomMenu.MenuItem onClick={handleBlockSync}>

View file

@ -15,14 +15,16 @@ import {
StarIcon, StarIcon,
TrashIcon, TrashIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { ExclamationIcon } from "components/icons";
// helpers // helpers
import { truncateText } from "helpers/string.helper"; import { truncateText } from "helpers/string.helper";
import { renderShortTime, renderShortDate } from "helpers/date-time.helper"; import { renderShortTime, renderShortDate, renderLongDateFormat } from "helpers/date-time.helper";
// types // types
import { IPage } from "types"; import { IPage, IProjectMember } from "types";
type TSingleStatProps = { type TSingleStatProps = {
page: IPage; page: IPage;
people: IProjectMember[] | undefined;
handleEditPage: () => void; handleEditPage: () => void;
handleDeletePage: () => void; handleDeletePage: () => void;
handleAddToFavorites: () => void; handleAddToFavorites: () => void;
@ -32,6 +34,7 @@ type TSingleStatProps = {
export const SinglePageDetailedItem: React.FC<TSingleStatProps> = ({ export const SinglePageDetailedItem: React.FC<TSingleStatProps> = ({
page, page,
people,
handleEditPage, handleEditPage,
handleDeletePage, handleDeletePage,
handleAddToFavorites, handleAddToFavorites,
@ -132,6 +135,18 @@ export const SinglePageDetailedItem: React.FC<TSingleStatProps> = ({
</button> </button>
</Tooltip> </Tooltip>
)} )}
<Tooltip
theme="dark"
position="top-right"
tooltipContent={`Created by ${
people?.find((person) => person.member.id === page.created_by)?.member
.first_name ?? ""
} on ${renderLongDateFormat(`${page.created_at}`)}`}
>
<span>
<ExclamationIcon className="h-4 w-4 text-gray-400" />
</span>
</Tooltip>
<CustomMenu verticalEllipsis> <CustomMenu verticalEllipsis>
<CustomMenu.MenuItem <CustomMenu.MenuItem
onClick={(e: any) => { onClick={(e: any) => {

View file

@ -1,5 +1,7 @@
import React from "react"; import React from "react";
import useSWR from "swr";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -9,22 +11,22 @@ import useUser from "hooks/use-user";
import { CustomMenu, Tooltip } from "components/ui"; import { CustomMenu, Tooltip } from "components/ui";
// icons // icons
import { import {
DocumentTextIcon,
LockClosedIcon, LockClosedIcon,
LockOpenIcon, LockOpenIcon,
PencilIcon, PencilIcon,
StarIcon, StarIcon,
TrashIcon, TrashIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { PencilScribbleIcon } from "components/icons"; import { ExclamationIcon, PencilScribbleIcon } from "components/icons";
// helpers // helpers
import { truncateText } from "helpers/string.helper"; import { truncateText } from "helpers/string.helper";
import { renderShortDate, renderShortTime } from "helpers/date-time.helper"; import { renderLongDateFormat, renderShortDate, renderShortTime } from "helpers/date-time.helper";
// types // types
import { IPage } from "types"; import { IPage, IProjectMember } from "types";
type TSingleStatProps = { type TSingleStatProps = {
page: IPage; page: IPage;
people: IProjectMember[] | undefined;
handleEditPage: () => void; handleEditPage: () => void;
handleDeletePage: () => void; handleDeletePage: () => void;
handleAddToFavorites: () => void; handleAddToFavorites: () => void;
@ -34,6 +36,7 @@ type TSingleStatProps = {
export const SinglePageListItem: React.FC<TSingleStatProps> = ({ export const SinglePageListItem: React.FC<TSingleStatProps> = ({
page, page,
people,
handleEditPage, handleEditPage,
handleDeletePage, handleDeletePage,
handleAddToFavorites, handleAddToFavorites,
@ -49,11 +52,11 @@ export const SinglePageListItem: React.FC<TSingleStatProps> = ({
<li> <li>
<Link href={`/${workspaceSlug}/projects/${projectId}/pages/${page.id}`}> <Link href={`/${workspaceSlug}/projects/${projectId}/pages/${page.id}`}>
<a> <a>
<div className="relative rounded p-4 hover:bg-[#E9ECEF]"> <div className="relative rounded p-4 hover:bg-gray-200">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2 flex-wrap">
<PencilScribbleIcon className="h-4 w-4" /> <PencilScribbleIcon className="h-4 w-4" />
<p className="mr-2 truncate text-base text-[#212529] font-medium"> <p className="mr-2 truncate text-base text-gray-800 font-medium">
{truncateText(page.name, 75)} {truncateText(page.name, 75)}
</p> </p>
{page.label_details.length > 0 && {page.label_details.length > 0 &&
@ -81,8 +84,9 @@ export const SinglePageListItem: React.FC<TSingleStatProps> = ({
<div className="ml-2 flex flex-shrink-0"> <div className="ml-2 flex flex-shrink-0">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Tooltip <Tooltip
tooltipContent={`Last updated at ${ tooltipContent={`Last updated at ${renderShortTime(
renderShortTime(page.updated_at)} on ${renderShortDate(page.updated_at)}`} page.updated_at
)} on ${renderShortDate(page.updated_at)}`}
> >
<p className="text-sm text-gray-400">{renderShortTime(page.updated_at)}</p> <p className="text-sm text-gray-400">{renderShortTime(page.updated_at)}</p>
</Tooltip> </Tooltip>
@ -134,6 +138,18 @@ export const SinglePageListItem: React.FC<TSingleStatProps> = ({
</button> </button>
</Tooltip> </Tooltip>
)} )}
<Tooltip
theme="dark"
position="top-right"
tooltipContent={`Created by ${
people?.find((person) => person.member.id === page.created_by)?.member
.first_name ?? ""
} on ${renderLongDateFormat(`${page.created_at}`)}`}
>
<span>
<ExclamationIcon className="h-4 w-4 text-gray-400" />
</span>
</Tooltip>
<CustomMenu width="auto" verticalEllipsis> <CustomMenu width="auto" verticalEllipsis>
<CustomMenu.MenuItem <CustomMenu.MenuItem

View file

@ -35,6 +35,7 @@ import {
PlusIcon, PlusIcon,
StarIcon, StarIcon,
LinkIcon, LinkIcon,
XMarkIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { ColorPalletteIcon, ClipboardIcon } from "components/icons"; import { ColorPalletteIcon, ClipboardIcon } from "components/icons";
// helpers // helpers
@ -330,7 +331,11 @@ const SinglePage: NextPage = () => {
return ( return (
<div <div
key={label.id} key={label.id}
className="group flex items-center gap-1 rounded-2xl border px-2 py-0.5 text-xs" className="group flex items-center gap-1 cursor-pointer rounded-2xl border px-2 py-0.5 text-xs hover:border-red-500 hover:bg-red-50"
onClick={() => {
const updatedLabels = pageDetails.labels.filter((l) => l !== labelId);
partialUpdatePage({ labels_list: updatedLabels });
}}
style={{ style={{
backgroundColor: `${ backgroundColor: `${
label?.color && label.color !== "" ? label.color : "#000000" label?.color && label.color !== "" ? label.color : "#000000"
@ -345,6 +350,7 @@ const SinglePage: NextPage = () => {
}} }}
/> />
{label.name} {label.name}
<XMarkIcon className="h-2.5 w-2.5 group-hover:text-red-500" />
</div> </div>
); );
})} })}