feat: added dropdown component
This commit is contained in:
parent
e5e2a615fc
commit
f80113c487
|
@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { NewLink } from "@/types/global";
|
import { NewLink } from "@/types/global";
|
||||||
import useLinkSlice from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
|
|
||||||
export default function ({ toggleLinkModal }: { toggleLinkModal: Function }) {
|
export default function ({ toggleLinkModal }: { toggleLinkModal: Function }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -17,7 +17,7 @@ export default function ({ toggleLinkModal }: { toggleLinkModal: Function }) {
|
||||||
collection: { id: Number(router.query.id) },
|
collection: { id: Number(router.query.id) },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { addLink } = useLinkSlice();
|
const { addLink } = useLinkStore();
|
||||||
|
|
||||||
const setTags = (e: any) => {
|
const setTags = (e: any) => {
|
||||||
const tagNames = e.map((e: any) => {
|
const tagNames = e.map((e: any) => {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import React, { useRef, useEffect, ReactNode, RefObject } from "react";
|
import React, { useRef, useEffect, ReactNode, RefObject } from "react";
|
||||||
|
|
||||||
interface Props {
|
type Props = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
onClickOutside: Function;
|
onClickOutside: Function;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
function useOutsideAlerter(
|
function useOutsideAlerter(
|
||||||
ref: RefObject<HTMLElement>,
|
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 { useRouter } from "next/router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import CreatableSelect from "react-select/creatable";
|
import CreatableSelect from "react-select/creatable";
|
||||||
|
@ -6,7 +6,7 @@ import { styles } from "./styles";
|
||||||
import { Options } from "./types";
|
import { Options } from "./types";
|
||||||
|
|
||||||
export default function ({ onChange }: any) {
|
export default function ({ onChange }: any) {
|
||||||
const { collections } = useCollectionSlice();
|
const { collections } = useCollectionStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [options, setOptions] = useState<Options[]>([]);
|
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 { useEffect, useState } from "react";
|
||||||
import CreatableSelect from "react-select/creatable";
|
import CreatableSelect from "react-select/creatable";
|
||||||
import { styles } from "./styles";
|
import { styles } from "./styles";
|
||||||
import { Options } from "./types";
|
import { Options } from "./types";
|
||||||
|
|
||||||
export default function ({ onChange }: any) {
|
export default function ({ onChange }: any) {
|
||||||
const { tags } = useTagSlice();
|
const { tags } = useTagStore();
|
||||||
|
|
||||||
const [options, setOptions] = useState<Options[]>([]);
|
const [options, setOptions] = useState<Options[]>([]);
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,16 @@ import {
|
||||||
faFolder,
|
faFolder,
|
||||||
faArrowUpRightFromSquare,
|
faArrowUpRightFromSquare,
|
||||||
faEllipsis,
|
faEllipsis,
|
||||||
faHeart,
|
faStar,
|
||||||
|
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";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import Dropdown from "./Dropdown";
|
||||||
|
|
||||||
export default function ({
|
export default function ({
|
||||||
link,
|
link,
|
||||||
|
@ -18,6 +21,7 @@ export default function ({
|
||||||
link: ExtendedLink;
|
link: ExtendedLink;
|
||||||
count: number;
|
count: number;
|
||||||
}) {
|
}) {
|
||||||
|
const [editDropdown, setEditDropdown] = useState(false);
|
||||||
const [archiveLabel, setArchiveLabel] = useState("Archived Formats");
|
const [archiveLabel, setArchiveLabel] = useState("Archived Formats");
|
||||||
|
|
||||||
const shortendURL = new URL(link.url).host.toLowerCase();
|
const shortendURL = new URL(link.url).host.toLowerCase();
|
||||||
|
@ -42,8 +46,8 @@ export default function ({
|
||||||
<div className="flex items-baseline gap-1">
|
<div className="flex items-baseline gap-1">
|
||||||
<p className="text-sm text-sky-300 font-bold">{count + 1}.</p>
|
<p className="text-sm text-sky-300 font-bold">{count + 1}.</p>
|
||||||
<p className="text-lg text-sky-600">{link.name}</p>
|
<p className="text-lg text-sky-600">{link.name}</p>
|
||||||
{link.isFavorites ? (
|
{link.starred ? (
|
||||||
<FontAwesomeIcon icon={faHeart} className="w-3 text-red-600" />
|
<FontAwesomeIcon icon={faStar} className="w-3 text-amber-400" />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sky-400 text-sm font-medium">{link.title}</p>
|
<p className="text-sky-400 text-sm font-medium">{link.title}</p>
|
||||||
|
@ -76,10 +80,12 @@ export default function ({
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-between items-end">
|
|
||||||
|
<div className="flex flex-col justify-between items-end relative">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faEllipsis}
|
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>
|
<div>
|
||||||
<p className="text-center text-sky-500 text-sm font-bold">
|
<p className="text-center text-sky-500 text-sm font-bold">
|
||||||
|
@ -121,6 +127,27 @@ export default function ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { signOut } from "next-auth/react";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import useCollectionSlice from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
import { Collection, Tag } from "@prisma/client";
|
import { Collection, Tag } from "@prisma/client";
|
||||||
import ClickAwayHandler from "./ClickAwayHandler";
|
import ClickAwayHandler from "./ClickAwayHandler";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
@ -15,15 +14,15 @@ import {
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import AddLinkModal from "./AddLinkModal";
|
import AddLinkModal from "./AddLinkModal";
|
||||||
import useTagSlice from "@/store/tags";
|
import useTagStore from "@/store/tags";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [pageName, setPageName] = useState<string | null>("");
|
const [pageName, setPageName] = useState<string | null>("");
|
||||||
const [pageIcon, setPageIcon] = useState<IconDefinition | null>(null);
|
const [pageIcon, setPageIcon] = useState<IconDefinition | null>(null);
|
||||||
|
|
||||||
const { collections } = useCollectionSlice();
|
const { collections } = useCollectionStore();
|
||||||
const { tags } = useTagSlice();
|
const { tags } = useTagStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.route === "/collections/[id]") {
|
if (router.route === "/collections/[id]") {
|
||||||
|
@ -83,12 +82,6 @@ export default function () {
|
||||||
icon={faMagnifyingGlass}
|
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"
|
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 ? (
|
{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">
|
<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 { useSession } from "next-auth/react";
|
||||||
import ClickAwayHandler from "@/components/ClickAwayHandler";
|
import ClickAwayHandler from "@/components/ClickAwayHandler";
|
||||||
import { useState } from "react";
|
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 { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faUserCircle } from "@fortawesome/free-regular-svg-icons";
|
|
||||||
import {
|
import {
|
||||||
faPlus,
|
faPlus,
|
||||||
faChevronDown,
|
faChevronDown,
|
||||||
|
@ -11,19 +11,24 @@ import {
|
||||||
faBox,
|
faBox,
|
||||||
faHashtag,
|
faHashtag,
|
||||||
faBookmark,
|
faBookmark,
|
||||||
|
faCircleUser,
|
||||||
|
faSliders,
|
||||||
|
faArrowRightFromBracket,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import SidebarItem from "./SidebarItem";
|
import SidebarItem from "./SidebarItem";
|
||||||
import useTagSlice from "@/store/tags";
|
import useTagStore from "@/store/tags";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Dropdown from "@/components/Dropdown";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
|
|
||||||
const [collectionInput, setCollectionInput] = useState(false);
|
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;
|
const user = session?.user;
|
||||||
|
|
||||||
|
@ -44,12 +49,35 @@ export default function () {
|
||||||
|
|
||||||
return (
|
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="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">
|
<div className="flex gap-3 items-center mb-5 p-3 w-fit text-gray-600 relative">
|
||||||
<FontAwesomeIcon icon={faUserCircle} className="h-8" />
|
<FontAwesomeIcon icon={faCircleUser} className="h-8" />
|
||||||
<div className="flex items-center gap-1">
|
<div
|
||||||
|
className="flex items-center gap-1 cursor-pointer"
|
||||||
|
onClick={() => setProfileDropdown(!profileDropdown)}
|
||||||
|
>
|
||||||
<p>{user?.name}</p>
|
<p>{user?.name}</p>
|
||||||
<FontAwesomeIcon icon={faChevronDown} className="h-3" />
|
<FontAwesomeIcon icon={faChevronDown} className="h-3" />
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<Link href="links">
|
<Link href="links">
|
||||||
|
|
|
@ -110,7 +110,7 @@ export default async function (
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
title,
|
title,
|
||||||
isFavorites: false,
|
starred: false,
|
||||||
screenshotPath: "",
|
screenshotPath: "",
|
||||||
pdfPath: "",
|
pdfPath: "",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import useCollectionSlice from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import useTagSlice from "@/store/tags";
|
import useTagStore from "@/store/tags";
|
||||||
import useLinkSlice from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const { status } = useSession();
|
const { status } = useSession();
|
||||||
const { setCollections } = useCollectionSlice();
|
const { setCollections } = useCollectionStore();
|
||||||
const { setTags } = useTagSlice();
|
const { setTags } = useTagStore();
|
||||||
const { setLinks } = useLinkSlice();
|
const { setLinks } = useLinkStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === "authenticated") {
|
if (status === "authenticated") {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": "https://github.com/Daniel31x13/link-warden.git",
|
"repository": "https://github.com/Daniel31x13/link-warden.git",
|
||||||
"author": "Daniel31X13 <daniel31x13@gmail.com>",
|
"author": "Daniel31X13 <daniel31x13@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import LinkList from "@/components/LinkList";
|
import LinkList from "@/components/LinkList";
|
||||||
import useLinkSlice from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { links } = useLinkSlice();
|
const { links } = useLinkStore();
|
||||||
|
|
||||||
const linksByCollection = links.filter(
|
const linksByCollection = links.filter(
|
||||||
(e) => e.collectionId === Number(router.query.id)
|
(e) => e.collectionId === Number(router.query.id)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import useCollectionSlice from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
|
|
||||||
import CollectionCard from "@/components/CollectionCard";
|
import CollectionCard from "@/components/CollectionCard";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const { collections } = useCollectionSlice();
|
const { collections } = useCollectionStore();
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
|
|
||||||
const user = session?.user;
|
const user = session?.user;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Link" RENAME COLUMN "isFavorites" TO "starred";
|
|
@ -50,7 +50,7 @@ model Link {
|
||||||
collection Collection @relation(fields: [collectionId], references: [id])
|
collection Collection @relation(fields: [collectionId], references: [id])
|
||||||
collectionId Int
|
collectionId Int
|
||||||
tags Tag[]
|
tags Tag[]
|
||||||
isFavorites Boolean
|
starred Boolean
|
||||||
screenshotPath String
|
screenshotPath String
|
||||||
pdfPath String
|
pdfPath String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { Collection } from "@prisma/client";
|
import { Collection } from "@prisma/client";
|
||||||
|
|
||||||
type CollectionSlice = {
|
type CollectionStore = {
|
||||||
collections: Collection[];
|
collections: Collection[];
|
||||||
setCollections: () => void;
|
setCollections: () => void;
|
||||||
addCollection: (collectionName: string) => void;
|
addCollection: (collectionName: string) => void;
|
||||||
|
@ -9,7 +9,7 @@ type CollectionSlice = {
|
||||||
removeCollection: (collectionId: number) => void;
|
removeCollection: (collectionId: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useCollectionSlice = create<CollectionSlice>()((set) => ({
|
const useCollectionStore = create<CollectionStore>()((set) => ({
|
||||||
collections: [],
|
collections: [],
|
||||||
setCollections: async () => {
|
setCollections: async () => {
|
||||||
const response = await fetch("/api/routes/collections");
|
const response = await fetch("/api/routes/collections");
|
||||||
|
@ -47,4 +47,4 @@ const useCollectionSlice = create<CollectionSlice>()((set) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useCollectionSlice;
|
export default useCollectionStore;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { ExtendedLink, NewLink } from "@/types/global";
|
import { ExtendedLink, NewLink } from "@/types/global";
|
||||||
|
|
||||||
type LinkSlice = {
|
type LinkStore = {
|
||||||
links: ExtendedLink[];
|
links: ExtendedLink[];
|
||||||
setLinks: () => void;
|
setLinks: () => void;
|
||||||
addLink: (linkName: NewLink) => Promise<boolean>;
|
addLink: (linkName: NewLink) => Promise<boolean>;
|
||||||
|
@ -9,7 +9,7 @@ type LinkSlice = {
|
||||||
removeLink: (linkId: number) => void;
|
removeLink: (linkId: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useLinkSlice = create<LinkSlice>()((set) => ({
|
const useLinkStore = create<LinkStore>()((set) => ({
|
||||||
links: [],
|
links: [],
|
||||||
setLinks: async () => {
|
setLinks: async () => {
|
||||||
const response = await fetch("/api/routes/links");
|
const response = await fetch("/api/routes/links");
|
||||||
|
@ -47,4 +47,4 @@ const useLinkSlice = create<LinkSlice>()((set) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useLinkSlice;
|
export default useLinkStore;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { Tag } from "@prisma/client";
|
import { Tag } from "@prisma/client";
|
||||||
|
|
||||||
type TagSlice = {
|
type TagStore = {
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
setTags: () => void;
|
setTags: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useTagSlice = create<TagSlice>()((set) => ({
|
const useTagStore = create<TagStore>()((set) => ({
|
||||||
tags: [],
|
tags: [],
|
||||||
setTags: async () => {
|
setTags: async () => {
|
||||||
const response = await fetch("/api/routes/tags");
|
const response = await fetch("/api/routes/tags");
|
||||||
|
@ -17,4 +17,4 @@ const useTagSlice = create<TagSlice>()((set) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useTagSlice;
|
export default useTagStore;
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
@keyframes slide-up-animation {
|
@keyframes slide-up-animation {
|
||||||
0% {
|
0% {
|
||||||
transform: translateY(10%);
|
transform: translateY(15%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
|
|
Ŝarĝante…
Reference in New Issue