[WEB-2182] chore: user favorites improvement (#5318)
* chore: favorite collapsible spacing * chore: favorite collapsible tooltip added * chore: user favorites icon improvement and code refactor * chore: favorites empty state added * chore: project identifier message updated * chore: favorties collapsible improvement * chore: code refactor * fix: build error * fix: app sidebar draft issue z-index
This commit is contained in:
parent
91142659ca
commit
598846adc4
6 changed files with 99 additions and 63 deletions
13
packages/types/src/favorite/favorite.d.ts
vendored
13
packages/types/src/favorite/favorite.d.ts
vendored
|
|
@ -1,9 +1,22 @@
|
|||
type TLogoProps = {
|
||||
in_use: "emoji" | "icon";
|
||||
emoji?: {
|
||||
value?: string;
|
||||
url?: string;
|
||||
};
|
||||
icon?: {
|
||||
name?: string;
|
||||
color?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type IFavorite = {
|
||||
id: string;
|
||||
name: string;
|
||||
entity_type: string;
|
||||
entity_data: {
|
||||
name: string;
|
||||
logo_props?: TLogoProps | undefined;
|
||||
};
|
||||
is_folder: boolean;
|
||||
sort_order: number;
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ export const CreateProjectForm: FC<Props> = observer((props) => {
|
|||
/>
|
||||
<Tooltip
|
||||
isMobile={isMobile}
|
||||
tooltipContent="Helps you identify issues in the project uniquely, (e.g. APP-123). Max 5 characters."
|
||||
tooltipContent="Helps you identify issues in the project uniquely. Max 5 characters."
|
||||
className="text-sm"
|
||||
position="right-top"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
|||
/>
|
||||
<Tooltip
|
||||
isMobile={isMobile}
|
||||
tooltipContent="Helps you identify issues in the project uniquely, (e.g. APP-123). Max 5 characters."
|
||||
tooltipContent="Helps you identify issues in the project uniquely. Max 5 characters."
|
||||
className="text-sm"
|
||||
position="right-top"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,16 @@ import { useParams } from "next/navigation";
|
|||
import { Briefcase, FileText, Layers, MoreHorizontal, Star } from "lucide-react";
|
||||
// ui
|
||||
import { IFavorite } from "@plane/types";
|
||||
import { ContrastIcon, CustomMenu, DiceIcon, DragHandle, FavoriteFolderIcon, LayersIcon, Tooltip } from "@plane/ui";
|
||||
import {
|
||||
ContrastIcon,
|
||||
CustomMenu,
|
||||
DiceIcon,
|
||||
DragHandle,
|
||||
FavoriteFolderIcon,
|
||||
LayersIcon,
|
||||
Logo,
|
||||
Tooltip,
|
||||
} from "@plane/ui";
|
||||
// components
|
||||
import { SidebarNavItem } from "@/components/sidebar";
|
||||
|
||||
|
|
@ -20,6 +29,17 @@ import { useAppTheme } from "@/hooks/store";
|
|||
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
const iconClassName = `flex-shrink-0 size-4 stroke-[1.5] m-auto`;
|
||||
const ICONS: Record<string, JSX.Element> = {
|
||||
page: <FileText className={iconClassName} />,
|
||||
project: <Briefcase className={iconClassName} />,
|
||||
view: <Layers className={iconClassName} />,
|
||||
module: <DiceIcon className={iconClassName} />,
|
||||
cycle: <ContrastIcon className={iconClassName} />,
|
||||
issue: <LayersIcon className={iconClassName} />,
|
||||
folder: <FavoriteFolderIcon className={iconClassName} />,
|
||||
};
|
||||
|
||||
export const FavoriteItem = observer(
|
||||
({
|
||||
favoriteMap,
|
||||
|
|
@ -48,28 +68,18 @@ export const FavoriteItem = observer(
|
|||
const dragHandleRef = useRef<HTMLButtonElement | null>(null);
|
||||
const actionSectionRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const getIcon = () => {
|
||||
const className = `flex-shrink-0 size-4 stroke-[1.5] m-auto`;
|
||||
|
||||
switch (favorite.entity_type) {
|
||||
case "page":
|
||||
return <FileText className={className} />;
|
||||
case "project":
|
||||
return <Briefcase className={className} />;
|
||||
case "view":
|
||||
return <Layers className={className} />;
|
||||
case "module":
|
||||
return <DiceIcon className={className} />;
|
||||
case "cycle":
|
||||
return <ContrastIcon className={className} />;
|
||||
case "issue":
|
||||
return <LayersIcon className={className} />;
|
||||
case "folder":
|
||||
return <FavoriteFolderIcon className={className} />;
|
||||
default:
|
||||
return <FileText />;
|
||||
}
|
||||
};
|
||||
const getIcon = () => (
|
||||
<>
|
||||
<div className="hidden group-hover:block">{ICONS[favorite.entity_type] || <FileText />}</div>
|
||||
<div className="block group-hover:hidden">
|
||||
{favorite.entity_data?.logo_props?.in_use ? (
|
||||
<Logo logo={favorite.entity_data?.logo_props} size={16} type="lucide" />
|
||||
) : (
|
||||
ICONS[favorite.entity_type] || <FileText />
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
const getLink = () => {
|
||||
switch (favorite.entity_type) {
|
||||
|
|
@ -133,7 +143,10 @@ export const FavoriteItem = observer(
|
|||
<div ref={elementRef} className="group/project-item">
|
||||
<SidebarNavItem
|
||||
key={favorite.id}
|
||||
className={`${sidebarCollapsed ? "p-0 size-8 aspect-square justify-center mx-auto" : ""}`}
|
||||
className={cn({
|
||||
"bg-custom-sidebar-background-90": isMenuActive,
|
||||
"p-0 size-8 aspect-square justify-center mx-auto": sidebarCollapsed,
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={cn("flex justify-between items-center gap-1.5 py-[1px]", {
|
||||
|
|
|
|||
|
|
@ -133,14 +133,16 @@ export const SidebarFavoritesMenu = observer(() => {
|
|||
<span onClick={() => toggleFavoriteMenu(!isFavoriteMenuOpen)} className="flex-1 text-start">
|
||||
YOUR FAVORITES
|
||||
</span>
|
||||
<span className="flex gap-2 flex-shrink-0 opacity-0 pointer-events-none group-hover/workspace-button:opacity-100 group-hover/workspace-button:pointer-events-auto rounded p-0.5 ">
|
||||
<FolderPlus
|
||||
onClick={() => {
|
||||
setCreateNewFolder(true);
|
||||
!isFavoriteMenuOpen && toggleFavoriteMenu(!isFavoriteMenuOpen);
|
||||
}}
|
||||
className={cn("size-4 flex-shrink-0 text-custom-sidebar-text-400 transition-transform")}
|
||||
/>
|
||||
<span className="flex flex-shrink-0 opacity-0 pointer-events-none group-hover/workspace-button:opacity-100 group-hover/workspace-button:pointer-events-auto rounded p-0.5 ">
|
||||
<Tooltip tooltipHeading="Create folder" tooltipContent="">
|
||||
<FolderPlus
|
||||
onClick={() => {
|
||||
setCreateNewFolder(true);
|
||||
!isFavoriteMenuOpen && toggleFavoriteMenu(!isFavoriteMenuOpen);
|
||||
}}
|
||||
className={cn("size-4 flex-shrink-0 text-custom-sidebar-text-400 transition-transform")}
|
||||
/>
|
||||
</Tooltip>
|
||||
<ChevronRight
|
||||
onClick={() => toggleFavoriteMenu(!isFavoriteMenuOpen)}
|
||||
className={cn("size-4 flex-shrink-0 text-custom-sidebar-text-400 transition-transform", {
|
||||
|
|
@ -168,34 +170,42 @@ export const SidebarFavoritesMenu = observer(() => {
|
|||
static
|
||||
>
|
||||
{createNewFolder && <NewFavoriteFolder setCreateNewFolder={setCreateNewFolder} actionType="create" />}
|
||||
{uniqBy(orderBy(Object.values(favoriteMap), "sequence", "desc"), "id")
|
||||
.filter((fav) => !fav.parent)
|
||||
.map((fav, index) => (
|
||||
<Tooltip
|
||||
key={fav.id}
|
||||
tooltipContent={fav.entity_data ? fav.entity_data.name : fav.name}
|
||||
position="right"
|
||||
className="ml-2"
|
||||
disabled={!sidebarCollapsed}
|
||||
isMobile={isMobile}
|
||||
>
|
||||
{fav.is_folder ? (
|
||||
<FavoriteFolder
|
||||
favorite={fav}
|
||||
isLastChild={index === favoriteIds.length - 1}
|
||||
handleRemoveFromFavorites={handleRemoveFromFavorites}
|
||||
handleRemoveFromFavoritesFolder={handleRemoveFromFavoritesFolder}
|
||||
/>
|
||||
) : (
|
||||
<FavoriteItem
|
||||
favorite={fav}
|
||||
handleRemoveFromFavorites={handleRemoveFromFavorites}
|
||||
handleRemoveFromFavoritesFolder={handleRemoveFromFavoritesFolder}
|
||||
favoriteMap={favoriteMap}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
))}
|
||||
{Object.keys(favoriteMap).length === 0 ? (
|
||||
<>
|
||||
{!sidebarCollapsed && (
|
||||
<span className="text-custom-text-400 text-xs text-center font-medium py-1">No favorites yet</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
uniqBy(orderBy(Object.values(favoriteMap), "sequence", "desc"), "id")
|
||||
.filter((fav) => !fav.parent)
|
||||
.map((fav, index) => (
|
||||
<Tooltip
|
||||
key={fav.id}
|
||||
tooltipContent={fav.entity_data ? fav.entity_data.name : fav.name}
|
||||
position="right"
|
||||
className="ml-2"
|
||||
disabled={!sidebarCollapsed}
|
||||
isMobile={isMobile}
|
||||
>
|
||||
{fav.is_folder ? (
|
||||
<FavoriteFolder
|
||||
favorite={fav}
|
||||
isLastChild={index === favoriteIds.length - 1}
|
||||
handleRemoveFromFavorites={handleRemoveFromFavorites}
|
||||
handleRemoveFromFavoritesFolder={handleRemoveFromFavoritesFolder}
|
||||
/>
|
||||
) : (
|
||||
<FavoriteItem
|
||||
favorite={fav}
|
||||
handleRemoveFromFavorites={handleRemoveFromFavorites}
|
||||
handleRemoveFromFavoritesFolder={handleRemoveFromFavoritesFolder}
|
||||
favoriteMap={favoriteMap}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
))
|
||||
)}
|
||||
</Disclosure.Panel>
|
||||
)}
|
||||
</Transition>
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ export const SidebarQuickActions = observer(() => {
|
|||
</button>
|
||||
)}
|
||||
{isDraftButtonOpen && (
|
||||
<div className="absolute mt-0 h-10 w-[220px] pt-2 z-10 top-8 left-0">
|
||||
<div className="absolute mt-0 h-10 w-[220px] pt-2 z-[16] top-8 left-0">
|
||||
<div className="h-full w-full">
|
||||
<button
|
||||
onClick={() => setIsDraftIssueModalOpen(true)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue