feat: added dropdown component
This commit is contained in:
@@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useRouter } from "next/router";
|
||||
import { NewLink } from "@/types/global";
|
||||
import useLinkSlice from "@/store/links";
|
||||
import useLinkStore from "@/store/links";
|
||||
|
||||
export default function ({ toggleLinkModal }: { toggleLinkModal: Function }) {
|
||||
const router = useRouter();
|
||||
@@ -17,7 +17,7 @@ export default function ({ toggleLinkModal }: { toggleLinkModal: Function }) {
|
||||
collection: { id: Number(router.query.id) },
|
||||
});
|
||||
|
||||
const { addLink } = useLinkSlice();
|
||||
const { addLink } = useLinkStore();
|
||||
|
||||
const setTags = (e: any) => {
|
||||
const tagNames = e.map((e: any) => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useRef, useEffect, ReactNode, RefObject } from "react";
|
||||
|
||||
interface Props {
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
onClickOutside: Function;
|
||||
className?: string;
|
||||
}
|
||||
};
|
||||
|
||||
function useOutsideAlerter(
|
||||
ref: RefObject<HTMLElement>,
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import Link from "next/link";
|
||||
import React, { MouseEventHandler, ReactElement } from "react";
|
||||
import ClickAwayHandler from "./ClickAwayHandler";
|
||||
|
||||
type MenuItem = {
|
||||
name: string;
|
||||
icon: ReactElement;
|
||||
onClick?: MouseEventHandler;
|
||||
href?: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
onClickOutside: Function;
|
||||
className?: string;
|
||||
items: MenuItem[];
|
||||
};
|
||||
|
||||
export default function ({ onClickOutside, className, items }: Props) {
|
||||
return (
|
||||
<ClickAwayHandler
|
||||
onClickOutside={onClickOutside}
|
||||
className={`${className} border border-sky-100 shadow mb-5 bg-gray-50 p-4 rounded flex flex-col gap-4`}
|
||||
>
|
||||
{items.map((e, i) => {
|
||||
return e.href ? (
|
||||
<Link key={i} href={e.href}>
|
||||
<div className="flex items-center gap-2 px-2 cursor-pointer">
|
||||
{React.cloneElement(e.icon, {
|
||||
className: "text-sky-500 w-5 h-5",
|
||||
})}
|
||||
<p className="text-sky-900">{e.name}</p>
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<div key={i} onClick={e.onClick}>
|
||||
<div className="flex items-center gap-2 px-2 cursor-pointer">
|
||||
{React.cloneElement(e.icon, {
|
||||
className: "text-sky-500 w-5 h-5",
|
||||
})}
|
||||
<p className="text-sky-900">{e.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</ClickAwayHandler>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import useCollectionSlice from "@/store/collections";
|
||||
import useCollectionStore from "@/store/collections";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
@@ -6,7 +6,7 @@ import { styles } from "./styles";
|
||||
import { Options } from "./types";
|
||||
|
||||
export default function ({ onChange }: any) {
|
||||
const { collections } = useCollectionSlice();
|
||||
const { collections } = useCollectionStore();
|
||||
const router = useRouter();
|
||||
|
||||
const [options, setOptions] = useState<Options[]>([]);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import useTagSlice from "@/store/tags";
|
||||
import useTagStore from "@/store/tags";
|
||||
import { useEffect, useState } from "react";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
import { styles } from "./styles";
|
||||
import { Options } from "./types";
|
||||
|
||||
export default function ({ onChange }: any) {
|
||||
const { tags } = useTagSlice();
|
||||
const { tags } = useTagStore();
|
||||
|
||||
const [options, setOptions] = useState<Options[]>([]);
|
||||
|
||||
|
||||
+32
-5
@@ -3,13 +3,16 @@ import {
|
||||
faFolder,
|
||||
faArrowUpRightFromSquare,
|
||||
faEllipsis,
|
||||
faHeart,
|
||||
faStar,
|
||||
faPenToSquare,
|
||||
faTrashCan,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faFileImage, faFilePdf } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Dropdown from "./Dropdown";
|
||||
|
||||
export default function ({
|
||||
link,
|
||||
@@ -18,6 +21,7 @@ export default function ({
|
||||
link: ExtendedLink;
|
||||
count: number;
|
||||
}) {
|
||||
const [editDropdown, setEditDropdown] = useState(false);
|
||||
const [archiveLabel, setArchiveLabel] = useState("Archived Formats");
|
||||
|
||||
const shortendURL = new URL(link.url).host.toLowerCase();
|
||||
@@ -42,8 +46,8 @@ export default function ({
|
||||
<div className="flex items-baseline gap-1">
|
||||
<p className="text-sm text-sky-300 font-bold">{count + 1}.</p>
|
||||
<p className="text-lg text-sky-600">{link.name}</p>
|
||||
{link.isFavorites ? (
|
||||
<FontAwesomeIcon icon={faHeart} className="w-3 text-red-600" />
|
||||
{link.starred ? (
|
||||
<FontAwesomeIcon icon={faStar} className="w-3 text-amber-400" />
|
||||
) : null}
|
||||
</div>
|
||||
<p className="text-sky-400 text-sm font-medium">{link.title}</p>
|
||||
@@ -76,10 +80,12 @@ export default function ({
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-between items-end">
|
||||
|
||||
<div className="flex flex-col justify-between items-end relative">
|
||||
<FontAwesomeIcon
|
||||
icon={faEllipsis}
|
||||
className="w-6 h-6 text-gray-500 cursor-pointer"
|
||||
className="w-6 h-6 text-gray-500 hover:text-gray-400 duration-100 cursor-pointer"
|
||||
onClick={() => setEditDropdown(!editDropdown)}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-center text-sky-500 text-sm font-bold">
|
||||
@@ -121,6 +127,27 @@ export default function ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{editDropdown ? (
|
||||
<Dropdown
|
||||
items={[
|
||||
{
|
||||
name: "Star",
|
||||
icon: <FontAwesomeIcon icon={faStar} />,
|
||||
},
|
||||
{
|
||||
name: "Edit",
|
||||
icon: <FontAwesomeIcon icon={faPenToSquare} />,
|
||||
},
|
||||
{
|
||||
name: "Delete",
|
||||
icon: <FontAwesomeIcon icon={faTrashCan} />,
|
||||
},
|
||||
]}
|
||||
onClickOutside={() => setEditDropdown(!editDropdown)}
|
||||
className="absolute top-8 right-0"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-11
@@ -1,6 +1,5 @@
|
||||
import { signOut } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import useCollectionSlice from "@/store/collections";
|
||||
import useCollectionStore from "@/store/collections";
|
||||
import { Collection, Tag } from "@prisma/client";
|
||||
import ClickAwayHandler from "./ClickAwayHandler";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
@@ -15,15 +14,15 @@ import {
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { useEffect, useState } from "react";
|
||||
import AddLinkModal from "./AddLinkModal";
|
||||
import useTagSlice from "@/store/tags";
|
||||
import useTagStore from "@/store/tags";
|
||||
|
||||
export default function () {
|
||||
const router = useRouter();
|
||||
const [pageName, setPageName] = useState<string | null>("");
|
||||
const [pageIcon, setPageIcon] = useState<IconDefinition | null>(null);
|
||||
|
||||
const { collections } = useCollectionSlice();
|
||||
const { tags } = useTagSlice();
|
||||
const { collections } = useCollectionStore();
|
||||
const { tags } = useTagStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (router.route === "/collections/[id]") {
|
||||
@@ -83,12 +82,6 @@ export default function () {
|
||||
icon={faMagnifyingGlass}
|
||||
className="select-none cursor-pointer w-5 h-5 text-white bg-sky-500 p-2 rounded hover:bg-sky-400 duration-100"
|
||||
/>
|
||||
<div
|
||||
onClick={() => signOut()}
|
||||
className="cursor-pointer w-max text-sky-900"
|
||||
>
|
||||
Sign Out
|
||||
</div>
|
||||
|
||||
{linkModal ? (
|
||||
<div className="fixed top-0 bottom-0 right-0 left-0 bg-gray-500 bg-opacity-10 flex items-center fade-in z-10">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useSession } from "next-auth/react";
|
||||
import ClickAwayHandler from "@/components/ClickAwayHandler";
|
||||
import { useState } from "react";
|
||||
import useCollectionSlice from "@/store/collections";
|
||||
import useCollectionStore from "@/store/collections";
|
||||
import { signOut } from "next-auth/react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faUserCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import {
|
||||
faPlus,
|
||||
faChevronDown,
|
||||
@@ -11,19 +11,24 @@ import {
|
||||
faBox,
|
||||
faHashtag,
|
||||
faBookmark,
|
||||
faCircleUser,
|
||||
faSliders,
|
||||
faArrowRightFromBracket,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import useTagSlice from "@/store/tags";
|
||||
import useTagStore from "@/store/tags";
|
||||
import Link from "next/link";
|
||||
import Dropdown from "@/components/Dropdown";
|
||||
|
||||
export default function () {
|
||||
const { data: session } = useSession();
|
||||
|
||||
const [collectionInput, setCollectionInput] = useState(false);
|
||||
const [profileDropdown, setProfileDropdown] = useState(false);
|
||||
|
||||
const { collections, addCollection } = useCollectionSlice();
|
||||
const { collections, addCollection } = useCollectionStore();
|
||||
|
||||
const { tags } = useTagSlice();
|
||||
const { tags } = useTagStore();
|
||||
|
||||
const user = session?.user;
|
||||
|
||||
@@ -44,12 +49,35 @@ export default function () {
|
||||
|
||||
return (
|
||||
<div className="fixed bg-gray-100 top-0 bottom-0 left-0 w-80 p-5 overflow-y-auto hide-scrollbar border-solid border-r-sky-100 border z-10">
|
||||
<div className="flex gap-3 items-center mb-5 p-3 cursor-pointer w-fit text-gray-600">
|
||||
<FontAwesomeIcon icon={faUserCircle} className="h-8" />
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex gap-3 items-center mb-5 p-3 w-fit text-gray-600 relative">
|
||||
<FontAwesomeIcon icon={faCircleUser} className="h-8" />
|
||||
<div
|
||||
className="flex items-center gap-1 cursor-pointer"
|
||||
onClick={() => setProfileDropdown(!profileDropdown)}
|
||||
>
|
||||
<p>{user?.name}</p>
|
||||
<FontAwesomeIcon icon={faChevronDown} className="h-3" />
|
||||
</div>
|
||||
{profileDropdown ? (
|
||||
<Dropdown
|
||||
items={[
|
||||
{
|
||||
name: "Settings",
|
||||
icon: <FontAwesomeIcon icon={faSliders} />,
|
||||
},
|
||||
{
|
||||
name: "Logout",
|
||||
icon: <FontAwesomeIcon icon={faArrowRightFromBracket} />,
|
||||
onClick: () => {
|
||||
signOut();
|
||||
setProfileDropdown(!profileDropdown);
|
||||
},
|
||||
},
|
||||
]}
|
||||
onClickOutside={() => setProfileDropdown(!profileDropdown)}
|
||||
className="absolute top-14 left-0"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<Link href="links">
|
||||
|
||||
Reference in New Issue
Block a user