diff --git a/components/Navbar.tsx b/components/Navbar.tsx index 110c218..f51d9ea 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -13,11 +13,14 @@ import { faSliders, faArrowRightFromBracket, faChevronDown, + faBars, } from "@fortawesome/free-solid-svg-icons"; import { useState } from "react"; import Dropdown from "@/components/Dropdown"; import Modal from "./Modal"; import AddLink from "./Modal/AddLink"; +import ClickAwayHandler from "./ClickAwayHandler"; +import Sidebar from "./Sidebar"; export default function () { const { data: session } = useSession(); @@ -27,6 +30,13 @@ export default function () { const user = session?.user; const [linkModal, setLinkModal] = useState(false); + const [sidebar, setSidebar] = useState(false); + + window.addEventListener("resize", () => setSidebar(false)); + + const toggleSidebar = () => { + setSidebar(!sidebar); + }; const toggleLinkModal = () => { setLinkModal(!linkModal); @@ -34,6 +44,12 @@ export default function () { return (
+
+ +
@@ -101,6 +119,16 @@ export default function () { className="absolute top-8 right-0 z-20 w-36" /> ) : null} + + {sidebar ? ( +
+ +
+ +
+
+
+ ) : null}
diff --git a/components/Sidebar/index.tsx b/components/Sidebar/index.tsx index 63e97ff..81489d5 100644 --- a/components/Sidebar/index.tsx +++ b/components/Sidebar/index.tsx @@ -21,7 +21,7 @@ export default function () { const { tags } = useTagStore(); return ( -
+

Linkwarden

diff --git a/hooks/useRedirection.tsx b/hooks/useRedirect.tsx similarity index 96% rename from hooks/useRedirection.tsx rename to hooks/useRedirect.tsx index 70611d3..64219ee 100644 --- a/hooks/useRedirection.tsx +++ b/hooks/useRedirect.tsx @@ -3,7 +3,7 @@ // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see . -import { ReactNode, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useSession } from "next-auth/react"; import { useRouter } from "next/router"; diff --git a/layouts/AuthRedirect.tsx b/layouts/AuthRedirect.tsx new file mode 100644 index 0000000..8e9bfcd --- /dev/null +++ b/layouts/AuthRedirect.tsx @@ -0,0 +1,45 @@ +// Copyright (C) 2022-present Daniel31x13 +// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3. +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// You should have received a copy of the GNU General Public License along with this program. If not, see . + +import { ReactNode } from "react"; +import { useSession } from "next-auth/react"; +import Loader from "../components/Loader"; +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; +import getInitialData from "@/lib/client/getInitialData"; + +interface Props { + children: ReactNode; +} + +export default function ({ children }: Props) { + const router = useRouter(); + const { status } = useSession(); + const [redirect, setRedirect] = useState(true); + + getInitialData(); + + useEffect(() => { + if ( + status === "authenticated" && + (router.pathname === "/login" || router.pathname === "/register") + ) { + router.push("/").then(() => { + setRedirect(false); + }); + } else if ( + status === "unauthenticated" && + !(router.pathname === "/login" || router.pathname === "/register") + ) { + router.push("/login").then(() => { + setRedirect(false); + }); + } else if (status === "loading") setRedirect(true); + else setRedirect(false); + }, [status]); + + if (status !== "loading" && !redirect) return <>{children}; + else return ; +} diff --git a/layouts/MainLayout.tsx b/layouts/Dashboard.tsx similarity index 76% rename from layouts/MainLayout.tsx rename to layouts/Dashboard.tsx index 5447931..a1588e2 100644 --- a/layouts/MainLayout.tsx +++ b/layouts/Dashboard.tsx @@ -8,9 +8,8 @@ import Sidebar from "@/components/Sidebar"; import { ReactNode } from "react"; import { useSession } from "next-auth/react"; import Loader from "../components/Loader"; -import useRedirection from "@/hooks/useRedirection"; +import useRedirect from "@/hooks/useRedirect"; import { useRouter } from "next/router"; -import getInitialData from "@/lib/client/getInitialData"; interface Props { children: ReactNode; @@ -19,22 +18,23 @@ interface Props { export default function ({ children }: Props) { const { status } = useSession(); const router = useRouter(); - const redirection = useRedirection(); + const redirect = useRedirect(); const routeExists = router.route === "/_error" ? false : true; - getInitialData(); - - if (status === "authenticated" && !redirection && routeExists) + if (status === "authenticated" && !redirect && routeExists) return ( - <> - -
+
+
+ +
+ +
{children}
- +
); - else if ((status === "unauthenticated" && !redirection) || !routeExists) + else if ((status === "unauthenticated" && !redirect) || !routeExists) return <>{children}; else return ; } diff --git a/pages/_app.tsx b/pages/_app.tsx index 9716086..9b28aac 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -4,11 +4,11 @@ // You should have received a copy of the GNU General Public License along with this program. If not, see . import React from "react"; -import MainLayout from "@/layouts/MainLayout"; import "@/styles/globals.css"; import { SessionProvider } from "next-auth/react"; import type { AppProps } from "next/app"; import Head from "next/head"; +import AuthRedirect from "@/layouts/AuthRedirect"; export default function App({ Component, pageProps }: AppProps) { return ( @@ -35,9 +35,9 @@ export default function App({ Component, pageProps }: AppProps) { /> - + - + ); } diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 7ba7493..1b475f5 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -32,16 +32,12 @@ export const authOptions: AuthOptions = { }, }); - console.log(findUser); - let passwordMatches: boolean = false; if (findUser?.password) { passwordMatches = bcrypt.compareSync(password, findUser.password); } - console.log(passwordMatches); - if (passwordMatches) { return { id: findUser?.id, diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx index 1376e70..234d18b 100644 --- a/pages/collections/[id].tsx +++ b/pages/collections/[id].tsx @@ -22,6 +22,7 @@ import { import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; +import Dashboard from "@/layouts/Dashboard"; export default function () { const router = useRouter(); @@ -61,89 +62,90 @@ export default function () { }, [links, router, collections]); return ( - // ml-80 -
-
-
- -

{activeCollection?.name}

-
-
-
setExpandDropdown(!expandDropdown)} - id="edit-dropdown" - className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" - > - + +
+
+
+ +

{activeCollection?.name}

- {expandDropdown ? ( - , - onClick: () => { - toggleLinkModal(); - setExpandDropdown(false); - }, - }, - { - name: "Edit Collection", - icon: , - onClick: () => { - toggleEditCollectionModal(); - setExpandDropdown(false); - }, - }, - { - name: "Delete Collection", - icon: , - onClick: () => { - toggleDeleteCollectionModal(); - setExpandDropdown(false); - }, - }, - ]} - onClickOutside={(e: Event) => { - const target = e.target as HTMLInputElement; - if (target.id !== "edit-dropdown") setExpandDropdown(false); - }} - className="absolute top-7 left-0 z-10 w-44" - /> - ) : null} - - {linkModal ? ( - - - - ) : null} - - {editCollectionModal && activeCollection ? ( - - +
setExpandDropdown(!expandDropdown)} + id="edit-dropdown" + className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" + > + - - ) : null} - - {deleteCollectionModal && activeCollection ? ( - - + {expandDropdown ? ( + , + onClick: () => { + toggleLinkModal(); + setExpandDropdown(false); + }, + }, + { + name: "Edit Collection", + icon: , + onClick: () => { + toggleEditCollectionModal(); + setExpandDropdown(false); + }, + }, + { + name: "Delete Collection", + icon: , + onClick: () => { + toggleDeleteCollectionModal(); + setExpandDropdown(false); + }, + }, + ]} + onClickOutside={(e: Event) => { + const target = e.target as HTMLInputElement; + if (target.id !== "edit-dropdown") setExpandDropdown(false); + }} + className="absolute top-7 left-0 z-10 w-44" /> - - ) : null} + ) : null} + + {linkModal ? ( + + + + ) : null} + + {editCollectionModal && activeCollection ? ( + + + + ) : null} + + {deleteCollectionModal && activeCollection ? ( + + + + ) : null} +
+ {linksByCollection.map((e, i) => { + return ; + })}
- {linksByCollection.map((e, i) => { - return ; - })} -
+ ); } diff --git a/pages/collections/index.tsx b/pages/collections/index.tsx index 15b9f2b..755b9a8 100644 --- a/pages/collections/index.tsx +++ b/pages/collections/index.tsx @@ -16,6 +16,7 @@ import Dropdown from "@/components/Dropdown"; import { useState } from "react"; import Modal from "@/components/Modal"; import AddCollection from "@/components/Modal/AddCollection"; +import Dashboard from "@/layouts/Dashboard"; export default function () { const { collections } = useCollectionStore(); @@ -29,64 +30,66 @@ export default function () { return ( // ml-80 -
-
-
- -

All Collections

-
-
-
setExpandDropdown(!expandDropdown)} - id="edit-dropdown" - className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" - > - + +
+
+
+ +

All Collections

- {expandDropdown ? ( - , - onClick: () => { - toggleCollectionModal(); - setExpandDropdown(false); +
+
setExpandDropdown(!expandDropdown)} + id="edit-dropdown" + className="inline-flex rounded-md cursor-pointer hover:bg-white hover:border-sky-500 border-sky-100 border duration-100 p-1" + > + +
+ {expandDropdown ? ( + , + onClick: () => { + toggleCollectionModal(); + setExpandDropdown(false); + }, }, - }, - ]} - onClickOutside={(e: Event) => { - const target = e.target as HTMLInputElement; - if (target.id !== "edit-dropdown") setExpandDropdown(false); - }} - className="absolute top-7 left-0 w-36" - /> + ]} + onClickOutside={(e: Event) => { + const target = e.target as HTMLInputElement; + if (target.id !== "edit-dropdown") setExpandDropdown(false); + }} + className="absolute top-7 left-0 w-36" + /> + ) : null} +
+ + {linkModal ? ( + + + ) : null}
+
+ {collections.map((e, i) => { + return ; + })} - {linkModal ? ( - - - - ) : null} -
-
- {collections.map((e, i) => { - return ; - })} - -
-

New Collection

- +
+

New Collection

+ +
-
+
); } diff --git a/pages/links.tsx b/pages/links.tsx index e372f43..8923dc6 100644 --- a/pages/links.tsx +++ b/pages/links.tsx @@ -4,6 +4,7 @@ // You should have received a copy of the GNU General Public License along with this program. If not, see . import LinkList from "@/components/LinkList"; +import Dashboard from "@/layouts/Dashboard"; import useLinkStore from "@/store/links"; import { faBookmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -12,16 +13,21 @@ export default function Links() { const { links } = useLinkStore(); return ( -
-
-
- -

All Links

+ +
+
+
+ +

All Links

+
+ {links.map((e, i) => { + return ; + })}
- {links.map((e, i) => { - return ; - })} -
+ ); } diff --git a/pages/login.tsx b/pages/login.tsx index eb79d92..cc23739 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -5,6 +5,7 @@ import { signIn } from "next-auth/react"; import Link from "next/link"; +import { useRouter } from "next/router"; import { useState } from "react"; interface FormData { @@ -13,6 +14,8 @@ interface FormData { } export default function () { + const router = useRouter(); + const [form, setForm] = useState({ email: "", password: "", @@ -24,16 +27,12 @@ export default function () { const res = await signIn("credentials", { email: form.email, password: form.password, + redirect: false, }); - console.log(res?.status); + console.log(res); - if (res?.ok) { - setForm({ - email: "", - password: "", - }); - } else { + if (!res?.ok) { console.log("User not found or password does not match.", res); } } else { diff --git a/pages/tags/[id].tsx b/pages/tags/[id].tsx index 31a0c95..4a06f14 100644 --- a/pages/tags/[id].tsx +++ b/pages/tags/[id].tsx @@ -3,6 +3,7 @@ // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with this program. If not, see . +import Dashboard from "@/layouts/Dashboard"; import { useRouter } from "next/router"; export default function () { @@ -10,5 +11,9 @@ export default function () { const tagId = Number(router.query.id); - return
{"HI"}
; + return ( + +
{"HI"}
+
+ ); } diff --git a/styles/globals.css b/styles/globals.css index 0cd5402..971a0b9 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -27,14 +27,17 @@ hyphens: auto; } -.slide-up { - animation: slide-up-animation 70ms; -} - .fade-in { animation: fade-in-animation 100ms; } +/* Bug: "lg:block" just didn't work... */ +@media (min-width: 1024px) { + .lgblock { + display: block; + } +} + @keyframes fade-in-animation { 0% { opacity: 0; @@ -44,6 +47,10 @@ } } +.slide-up { + animation: slide-up-animation 70ms; +} + @keyframes slide-up-animation { 0% { transform: translateY(15%); @@ -54,3 +61,18 @@ opacity: 1; } } + +.slide-right { + animation: slide-right-animation 100ms; +} + +@keyframes slide-right-animation { + 0% { + transform: translateX(-25%); + opacity: 0; + } + 100% { + transform: translateX(0); + opacity: 1; + } +}