better looking dropdown component

This commit is contained in:
Daniel 2023-05-28 06:51:35 +03:30
parent d2051a67ab
commit 577b279108
7 changed files with 51 additions and 61 deletions

View File

@ -4,11 +4,7 @@
// You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. // You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { faEllipsis } from "@fortawesome/free-solid-svg-icons";
faPenToSquare,
faTrashCan,
faEllipsis,
} from "@fortawesome/free-solid-svg-icons";
import Link from "next/link"; import Link from "next/link";
import { CollectionIncludingMembers } from "@/types/global"; import { CollectionIncludingMembers } from "@/types/global";
import useLinkStore from "@/store/links"; import useLinkStore from "@/store/links";
@ -50,12 +46,12 @@ export default function ({
<div className="bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% self-stretch min-h-[12rem] rounded-md shadow duration-100 hover:shadow-none group relative"> <div className="bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% self-stretch min-h-[12rem] rounded-md shadow duration-100 hover:shadow-none group relative">
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="edit-dropdown" id={"expand-dropdown" + collection.id}
className="inline-flex absolute top-5 right-5 rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" className="inline-flex absolute top-5 right-5 rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
id="edit-dropdown" id={"expand-dropdown" + collection.id}
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500"
/> />
</div> </div>
@ -100,7 +96,6 @@ export default function ({
items={[ items={[
{ {
name: "Edit Collection", name: "Edit Collection",
icon: <FontAwesomeIcon icon={faPenToSquare} />,
onClick: () => { onClick: () => {
toggleEditCollectionModal(); toggleEditCollectionModal();
setExpandDropdown(false); setExpandDropdown(false);
@ -108,7 +103,6 @@ export default function ({
}, },
{ {
name: "Delete Collection", name: "Delete Collection",
icon: <FontAwesomeIcon icon={faTrashCan} />,
onClick: () => { onClick: () => {
toggleDeleteCollectionModal(); toggleDeleteCollectionModal();
setExpandDropdown(false); setExpandDropdown(false);
@ -117,9 +111,10 @@ export default function ({
]} ]}
onClickOutside={(e: Event) => { onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "edit-dropdown") setExpandDropdown(false); if (target.id !== "expand-dropdown" + collection.id)
setExpandDropdown(false);
}} }}
className="absolute top-[3.2rem] right-5 z-10 w-44" className="absolute top-[3.2rem] right-5 z-10 w-36"
/> />
) : null} ) : null}

View File

@ -8,8 +8,6 @@ import {
faFolder, faFolder,
faArrowUpRightFromSquare, faArrowUpRightFromSquare,
faEllipsis, faEllipsis,
faPenToSquare,
faTrashCan,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { faFileImage, faFilePdf } from "@fortawesome/free-regular-svg-icons"; import { faFileImage, faFilePdf } from "@fortawesome/free-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -124,14 +122,14 @@ export default function ({ link, count }: Props) {
<div className="flex flex-col justify-between items-end relative"> <div className="flex flex-col justify-between items-end relative">
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="edit-dropdown" id="expand-dropdown"
className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-white hover:outline outline-sky-100 outline-1 duration-100 p-1" className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-white hover:outline outline-sky-100 outline-1 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
title="More" title="More"
className="w-6 h-6" className="w-6 h-6"
id="edit-dropdown" id="expand-dropdown"
/> />
</div> </div>
<div className="relative"> <div className="relative">
@ -168,7 +166,6 @@ export default function ({ link, count }: Props) {
items={[ items={[
{ {
name: "Edit", name: "Edit",
icon: <FontAwesomeIcon icon={faPenToSquare} />,
onClick: () => { onClick: () => {
setEditModal(true); setEditModal(true);
setExpandDropdown(false); setExpandDropdown(false);
@ -176,7 +173,6 @@ export default function ({ link, count }: Props) {
}, },
{ {
name: "Delete", name: "Delete",
icon: <FontAwesomeIcon icon={faTrashCan} />,
onClick: () => { onClick: () => {
removeLink(link); removeLink(link);
setExpandDropdown(false); setExpandDropdown(false);
@ -185,7 +181,7 @@ export default function ({ link, count }: Props) {
]} ]}
onClickOutside={(e: Event) => { onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "edit-dropdown") setExpandDropdown(false); if (target.id !== "expand-dropdown") setExpandDropdown(false);
}} }}
className="absolute top-8 right-0 w-36" className="absolute top-8 right-0 w-36"
/> />

View File

@ -4,15 +4,20 @@
// You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. // You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
import Link from "next/link"; import Link from "next/link";
import React, { MouseEventHandler, ReactElement } from "react"; import React, { MouseEventHandler } from "react";
import ClickAwayHandler from "./ClickAwayHandler"; import ClickAwayHandler from "./ClickAwayHandler";
type MenuItem = { type MenuItem =
name: string; | {
icon: ReactElement; name: string;
onClick?: MouseEventHandler; onClick: MouseEventHandler;
href?: string; href?: string;
}; }
| {
name: string;
onClick?: MouseEventHandler;
href: string;
};
type Props = { type Props = {
onClickOutside: Function; onClickOutside: Function;
@ -20,20 +25,17 @@ type Props = {
items: MenuItem[]; items: MenuItem[];
}; };
export default function ({ onClickOutside, className, items }: Props) { export default function Dropdown({ onClickOutside, className, items }: Props) {
return ( return (
<ClickAwayHandler <ClickAwayHandler
onClickOutside={onClickOutside} onClickOutside={onClickOutside}
className={`${className} border border-sky-100 shadow-md mb-5 bg-gray-50 rounded-md flex flex-col z-10`} className={`${className} border border-sky-100 py-1 shadow-md bg-gray-50 rounded-md flex flex-col z-10`}
> >
{items.map((e, i) => { {items.map((e, i) => {
const inner = ( const inner = (
<div className="cursor-pointer rounded-md hover:bg-white hover:outline outline-sky-100 outline-1 duration-100"> <div className="cursor-pointer rounded-md">
<div className="flex items-center gap-2 p-2 rounded-md hover:opacity-60 duration-100"> <div className="flex items-center gap-2 py-1 px-2 hover:bg-sky-200 duration-100">
{React.cloneElement(e.icon, { <p className="text-sky-900 select-none">{e.name}</p>
className: "text-sky-500 w-5 h-5",
})}
<p className="text-sky-900">{e.name}</p>
</div> </div>
</div> </div>
); );

View File

@ -8,8 +8,6 @@ import {
faFolder, faFolder,
faArrowUpRightFromSquare, faArrowUpRightFromSquare,
faEllipsis, faEllipsis,
faPenToSquare,
faTrashCan,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { faFileImage, faFilePdf } from "@fortawesome/free-regular-svg-icons"; import { faFileImage, faFilePdf } from "@fortawesome/free-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -124,14 +122,14 @@ export default function ({ link, count }: Props) {
<div className="flex flex-col justify-between items-end relative"> <div className="flex flex-col justify-between items-end relative">
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="edit-dropdown" id={"expand-dropdown" + link.id}
className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-white hover:outline outline-sky-100 outline-1 duration-100 p-1" className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-white hover:outline outline-sky-100 outline-1 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
title="More" title="More"
className="w-5 h-5" className="w-5 h-5"
id="edit-dropdown" id={"expand-dropdown" + link.id}
/> />
</div> </div>
<div className="relative"> <div className="relative">
@ -168,7 +166,6 @@ export default function ({ link, count }: Props) {
items={[ items={[
{ {
name: "Edit", name: "Edit",
icon: <FontAwesomeIcon icon={faPenToSquare} />,
onClick: () => { onClick: () => {
setEditModal(true); setEditModal(true);
setExpandDropdown(false); setExpandDropdown(false);
@ -176,7 +173,6 @@ export default function ({ link, count }: Props) {
}, },
{ {
name: "Delete", name: "Delete",
icon: <FontAwesomeIcon icon={faTrashCan} />,
onClick: () => { onClick: () => {
removeLink(link); removeLink(link);
setExpandDropdown(false); setExpandDropdown(false);
@ -185,9 +181,10 @@ export default function ({ link, count }: Props) {
]} ]}
onClickOutside={(e: Event) => { onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "edit-dropdown") setExpandDropdown(false); if (target.id !== "expand-dropdown" + link.id)
setExpandDropdown(false);
}} }}
className="absolute top-8 right-0 w-36" className="absolute top-7 right-0 w-36"
/> />
) : null} ) : null}
</div> </div>

View File

@ -8,8 +8,6 @@ import { signOut } from "next-auth/react";
import { import {
faPlus, faPlus,
faCircleUser, faCircleUser,
faSliders,
faArrowRightFromBracket,
faChevronDown, faChevronDown,
faBars, faBars,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
@ -104,7 +102,6 @@ export default function () {
items={[ items={[
{ {
name: "Settings", name: "Settings",
icon: <FontAwesomeIcon icon={faSliders} />,
onClick: () => { onClick: () => {
toggleSettingsModal(); toggleSettingsModal();
setProfileDropdown(!profileDropdown); setProfileDropdown(!profileDropdown);
@ -112,7 +109,6 @@ export default function () {
}, },
{ {
name: "Logout", name: "Logout",
icon: <FontAwesomeIcon icon={faArrowRightFromBracket} />,
onClick: () => { onClick: () => {
signOut(); signOut();
setProfileDropdown(!profileDropdown); setProfileDropdown(!profileDropdown);

View File

@ -13,12 +13,9 @@ import useCollectionStore from "@/store/collections";
import useLinkStore from "@/store/links"; import useLinkStore from "@/store/links";
import { CollectionIncludingMembers } from "@/types/global"; import { CollectionIncludingMembers } from "@/types/global";
import { import {
faAdd,
faEllipsis, faEllipsis,
faFolder, faFolder,
faPenToSquare,
faSort, faSort,
faTrashCan,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -231,12 +228,12 @@ export default function () {
<div className="relative"> <div className="relative">
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="edit-dropdown" id="expand-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
id="edit-dropdown" id="expand-dropdown"
title="More" title="More"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500"
/> />
@ -246,7 +243,6 @@ export default function () {
items={[ items={[
{ {
name: "Add Link Here", name: "Add Link Here",
icon: <FontAwesomeIcon icon={faAdd} />,
onClick: () => { onClick: () => {
toggleLinkModal(); toggleLinkModal();
setExpandDropdown(false); setExpandDropdown(false);
@ -254,7 +250,17 @@ export default function () {
}, },
{ {
name: "Edit Collection", name: "Edit Collection",
icon: <FontAwesomeIcon icon={faPenToSquare} />, onClick: () => {
toggleEditCollectionModal();
setExpandDropdown(false);
},
},
{
name: `${
activeCollection?.ownerId === data?.user.id
? "Manage"
: "View"
} Team`,
onClick: () => { onClick: () => {
toggleEditCollectionModal(); toggleEditCollectionModal();
setExpandDropdown(false); setExpandDropdown(false);
@ -262,7 +268,6 @@ export default function () {
}, },
{ {
name: "Delete Collection", name: "Delete Collection",
icon: <FontAwesomeIcon icon={faTrashCan} />,
onClick: () => { onClick: () => {
toggleDeleteCollectionModal(); toggleDeleteCollectionModal();
setExpandDropdown(false); setExpandDropdown(false);
@ -271,10 +276,10 @@ export default function () {
]} ]}
onClickOutside={(e: Event) => { onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "edit-dropdown") if (target.id !== "expand-dropdown")
setExpandDropdown(false); setExpandDropdown(false);
}} }}
className="absolute top-8 right-0 z-10 w-44" className="absolute top-8 right-0 z-10 w-36"
/> />
) : null} ) : null}

View File

@ -5,7 +5,6 @@
import useCollectionStore from "@/store/collections"; import useCollectionStore from "@/store/collections";
import { import {
faAdd,
faBox, faBox,
faEllipsis, faEllipsis,
faPlus, faPlus,
@ -95,12 +94,12 @@ export default function () {
<div className="relative"> <div className="relative">
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="edit-dropdown" id="expand-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
id="edit-dropdown" id="expand-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500"
/> />
</div> </div>
@ -109,8 +108,7 @@ export default function () {
<Dropdown <Dropdown
items={[ items={[
{ {
name: "New", name: "New Collection",
icon: <FontAwesomeIcon icon={faAdd} />,
onClick: () => { onClick: () => {
toggleCollectionModal(); toggleCollectionModal();
setExpandDropdown(false); setExpandDropdown(false);
@ -119,7 +117,8 @@ export default function () {
]} ]}
onClickOutside={(e: Event) => { onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "edit-dropdown") setExpandDropdown(false); if (target.id !== "expand-dropdown")
setExpandDropdown(false);
}} }}
className="absolute top-8 left-0 w-36" className="absolute top-8 left-0 w-36"
/> />