improved ux + coloring fix + improved dashboard ui

This commit is contained in:
Daniel
2023-08-28 14:03:06 -04:00
parent e47aef8123
commit 5015f79b81
7 changed files with 84 additions and 186 deletions
+10 -15
View File
@@ -32,16 +32,15 @@ export default async function updateLink(
const isCollectionOwner = const isCollectionOwner =
targetLink?.collection.ownerId === link.collection.ownerId && targetLink?.collection.ownerId === link.collection.ownerId &&
link.collection.ownerId === userId && link.collection.ownerId === userId;
targetLink?.collection.ownerId === userId;
const authorizedSwitchCollection = const unauthorizedSwitchCollection =
!isCollectionOwner && targetLink?.collection.id === link.collection.id; !isCollectionOwner && targetLink?.collection.id !== link.collection.id;
console.log(authorizedSwitchCollection); console.log(isCollectionOwner);
// Makes sure collection members (non-owners) cannot move a link to/from a collection. // Makes sure collection members (non-owners) cannot move a link to/from a collection.
if (!authorizedSwitchCollection) if (unauthorizedSwitchCollection)
return { return {
response: "You can't move a link to/from a collection you don't own.", response: "You can't move a link to/from a collection you don't own.",
status: 401, status: 401,
@@ -59,15 +58,11 @@ export default async function updateLink(
data: { data: {
name: link.name, name: link.name,
description: link.description, description: link.description,
collection: collection: {
targetLink?.collection.ownerId === link.collection.ownerId &&
link.collection.ownerId === userId
? {
connect: { connect: {
id: link.collection.id, id: link.collection.id,
}, },
} },
: undefined,
tags: { tags: {
set: [], set: [],
connectOrCreate: link.tags.map((tag) => ({ connectOrCreate: link.tags.map((tag) => ({
@@ -104,14 +99,14 @@ export default async function updateLink(
}, },
}); });
if (targetLink.collection.id !== link.collection.id) { if (targetLink?.collection.id !== link.collection.id) {
await moveFile( await moveFile(
`archives/${targetLink.collection.id}/${link.id}.pdf`, `archives/${targetLink?.collection.id}/${link.id}.pdf`,
`archives/${link.collection.id}/${link.id}.pdf` `archives/${link.collection.id}/${link.id}.pdf`
); );
await moveFile( await moveFile(
`archives/${targetLink.collection.id}/${link.id}.png`, `archives/${targetLink?.collection.id}/${link.id}.png`,
`archives/${link.collection.id}/${link.id}.png` `archives/${link.collection.id}/${link.id}.png`
); );
} }
+1
View File
@@ -53,6 +53,7 @@ export default function Subscribe() {
<TextInput <TextInput
placeholder="john" placeholder="john"
value={inputedUsername} value={inputedUsername}
className="bg-white"
onChange={(e) => setInputedUsername(e.target.value)} onChange={(e) => setInputedUsername(e.target.value)}
/> />
</div> </div>
+33 -154
View File
@@ -2,15 +2,13 @@ import useCollectionStore from "@/store/collections";
import { import {
faChartSimple, faChartSimple,
faChevronDown, faChevronDown,
faThumbTack,
} 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 MainLayout from "@/layouts/MainLayout"; import MainLayout from "@/layouts/MainLayout";
import useLinkStore from "@/store/links"; import useLinkStore from "@/store/links";
import useTagStore from "@/store/tags"; import useTagStore from "@/store/tags";
import LinkCard from "@/components/LinkCard"; import LinkCard from "@/components/LinkCard";
import Link from "next/link";
import CollectionCard from "@/components/CollectionCard";
import { Disclosure, Transition } from "@headlessui/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import useLinks from "@/hooks/useLinks"; import useLinks from "@/hooks/useLinks";
@@ -21,20 +19,6 @@ export default function Dashboard() {
const [numberOfLinks, setNumberOfLinks] = useState(0); const [numberOfLinks, setNumberOfLinks] = useState(0);
const [tagPinDisclosure, setTagPinDisclosure] = useState<boolean>(() => {
const storedValue =
typeof window !== "undefined" && localStorage.getItem("tagPinDisclosure");
return storedValue ? storedValue === "true" : true;
});
const [collectionPinDisclosure, setCollectionPinDisclosure] =
useState<boolean>(() => {
const storedValue =
typeof window !== "undefined" &&
localStorage.getItem("collectionPinDisclosure");
return storedValue ? storedValue === "true" : true;
});
const [linkPinDisclosure, setLinkPinDisclosure] = useState<boolean>(() => { const [linkPinDisclosure, setLinkPinDisclosure] = useState<boolean>(() => {
const storedValue = const storedValue =
typeof window !== "undefined" && typeof window !== "undefined" &&
@@ -54,20 +38,6 @@ export default function Dashboard() {
); );
}, [collections]); }, [collections]);
useEffect(() => {
localStorage.setItem(
"tagPinDisclosure",
tagPinDisclosure ? "true" : "false"
);
}, [tagPinDisclosure]);
useEffect(() => {
localStorage.setItem(
"collectionPinDisclosure",
collectionPinDisclosure ? "true" : "false"
);
}, [collectionPinDisclosure]);
useEffect(() => { useEffect(() => {
localStorage.setItem( localStorage.setItem(
"linkPinDisclosure", "linkPinDisclosure",
@@ -76,25 +46,22 @@ export default function Dashboard() {
}, [linkPinDisclosure]); }, [linkPinDisclosure]);
return ( return (
// ml-80
<MainLayout> <MainLayout>
<div className="p-5"> <div className="p-5 flex flex-col gap-5">
<div className="flex gap-3 items-center mb-5"> <div className="flex gap-3 items-center">
<div className="flex gap-2"> <div className="flex gap-2">
<FontAwesomeIcon <FontAwesomeIcon
icon={faChartSimple} icon={faChartSimple}
className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300 drop-shadow" className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300 drop-shadow"
/> />
<p className="sm:text-4xl text-3xl capitalize text-black dark:text-white"> <p className="sm:text-4xl text-3xl text-black dark:text-white">
Dashboard Dashboard
</p> </p>
</div> </div>
</div> </div>
<br /> <div className="flex flex-col md:flex-row md:items-center gap-5">
<div className="flex flex-col justify-center items-center gap-2 md:w-full rounded-2xl p-10 border border-sky-100 dark:border-neutral-700">
<div className="flex flex-col md:flex-row md:items-center justify-evenly gap-2 mb-10">
<div className="flex items-baseline gap-2">
<p className="font-bold text-6xl text-sky-500 dark:text-sky-300"> <p className="font-bold text-6xl text-sky-500 dark:text-sky-300">
{numberOfLinks} {numberOfLinks}
</p> </p>
@@ -103,7 +70,7 @@ export default function Dashboard() {
</p> </p>
</div> </div>
<div className="flex items-baseline gap-2"> <div className="flex flex-col justify-center items-center gap-2 md:w-full rounded-2xl p-10 border border-sky-100 dark:border-neutral-700">
<p className="font-bold text-6xl text-sky-500 dark:text-sky-300"> <p className="font-bold text-6xl text-sky-500 dark:text-sky-300">
{collections.length} {collections.length}
</p> </p>
@@ -112,7 +79,7 @@ export default function Dashboard() {
</p> </p>
</div> </div>
<div className="flex items-baseline gap-2"> <div className="flex flex-col justify-center items-center gap-2 md:w-full rounded-2xl p-10 border border-sky-100 dark:border-neutral-700">
<p className="font-bold text-6xl text-sky-500 dark:text-sky-300"> <p className="font-bold text-6xl text-sky-500 dark:text-sky-300">
{tags.length} {tags.length}
</p> </p>
@@ -122,143 +89,55 @@ export default function Dashboard() {
</div> </div>
</div> </div>
{/* <hr className="my-5 border-sky-100" /> */} <div className="flex justify-between items-center">
<br /> <div className="flex gap-2 items-center">
<FontAwesomeIcon
<div className="flex flex-col 2xl:flex-row items-start justify-evenly 2xl:gap-2"> icon={faThumbTack}
className="w-5 h-5 text-sky-500 dark:text-sky-300 drop-shadow"
/>
<p className="text-2xl text-black dark:text-white">Pinned Links</p>
</div>
{links.some((e) => e.pinnedBy && e.pinnedBy[0]) ? ( {links.some((e) => e.pinnedBy && e.pinnedBy[0]) ? (
<Disclosure defaultOpen={linkPinDisclosure}> <button
<div className="flex flex-col gap-5 p-2 w-full mx-auto md:w-2/3"> className="text-black dark:text-white flex items-center gap-2 cursor-pointer"
<Disclosure.Button onClick={() => setLinkPinDisclosure(!linkPinDisclosure)}
onClick={() => {
setLinkPinDisclosure(!linkPinDisclosure);
}}
className="flex justify-between gap-2 items-baseline shadow active:shadow-inner dark:bg-neutral-700 duration-100 py-2 px-4 rounded-full"
> >
<p className="text-black dark:text-white text-xl"> {linkPinDisclosure ? "Show Less" : "Show More"}
Pinned Links
</p>
<div className="text-black dark:text-white flex items-center gap-2">
{linkPinDisclosure ? "Hide" : "Show"}
<FontAwesomeIcon <FontAwesomeIcon
icon={faChevronDown} icon={faChevronDown}
className={`w-4 h-4 text-black dark:text-white ${ className={`w-4 h-4 text-black dark:text-white ${
linkPinDisclosure ? "rotate-reverse" : "rotate" linkPinDisclosure ? "rotate-reverse" : "rotate"
}`} }`}
/> />
</button>
) : undefined}
</div> </div>
</Disclosure.Button>
<Transition <div className="flex flex-col 2xl:flex-row items-start justify-evenly 2xl:gap-2">
enter="transition duration-100 ease-out" {links.some((e) => e.pinnedBy && e.pinnedBy[0]) ? (
enterFrom="transform opacity-0 -translate-y-3" <div
enterTo="transform opacity-100 translate-y-0" className={`grid overflow-hidden 2xl:grid-cols-3 xl:grid-cols-2 grid-cols-1 gap-5 w-full ${
leave="transition duration-100 ease-out" linkPinDisclosure ? "h-full" : "h-44"
leaveFrom="transform opacity-100 translate-y-0" }`}
leaveTo="transform opacity-0 -translate-y-3"
> >
<Disclosure.Panel className="grid grid-cols-1 xl:grid-cols-2 gap-5 w-full">
{links {links
.filter((e) => e.pinnedBy && e.pinnedBy[0]) .filter((e) => e.pinnedBy && e.pinnedBy[0])
.map((e, i) => ( .map((e, i) => (
<LinkCard key={i} link={e} count={i} /> <LinkCard key={i} link={e} count={i} />
))} ))}
</Disclosure.Panel>
</Transition>
</div> </div>
</Disclosure>
) : ( ) : (
<div className="border border-solid border-sky-100 dark:border-neutral-700 w-full mx-auto md:w-2/3 p-10 rounded-2xl"> <div className="border border-solid border-sky-100 dark:border-neutral-700 w-full mx-auto p-10 rounded-2xl">
<p className="text-center text-2xl text-black dark:text-white"> <p className="text-center text-2xl text-black dark:text-white">
No Pinned Links No Pinned Links
</p> </p>
<p className="text-center text-black dark:text-white text-sm"> <p className="text-center text-gray-500 dark:text-gray-300 text-sm mt-2">
You can Pin Links by clicking on the three dots on each Link and You can Pin your favorite Links by clicking on the three dots on
clicking &quot;Pin to Dashboard.&quot; each Link and clicking{" "}
<span className="font-semibold">Pin to Dashboard</span>.
</p> </p>
</div> </div>
)} )}
{/* <Disclosure defaultOpen={collectionPinDisclosure}>
<div className="flex flex-col gap-5 p-2 w-full">
<Disclosure.Button
onClick={() => {
setCollectionPinDisclosure(!collectionPinDisclosure);
}}
className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full"
>
<p className="text-black text-xl">Pinned Collections</p>
<div className="text-black flex items-center gap-2">
{collectionPinDisclosure ? "Hide" : "Show"}
<FontAwesomeIcon
icon={faChevronDown}
className={`w-4 h-4 text-black ${
collectionPinDisclosure ? "rotate-reverse" : "rotate"
}`}
/>
</div>
</Disclosure.Button>
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform opacity-0 -translate-y-3"
enterTo="transform opacity-100 translate-y-0"
leave="transition duration-100 ease-out"
leaveFrom="transform opacity-100 translate-y-0"
leaveTo="transform opacity-0 -translate-y-3"
>
<Disclosure.Panel className="flex flex-col gap-5 w-full">
{collections.slice(0, 5).map((e, i) => (
<CollectionCard key={i} collection={e} />
))}
</Disclosure.Panel>
</Transition>
</div>
</Disclosure> */}
{/* <Disclosure defaultOpen={tagPinDisclosure}>
<div className="flex flex-col gap-5 p-2 w-full">
<Disclosure.Button
onClick={() => {
setTagPinDisclosure(!tagPinDisclosure);
}}
className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full"
>
<p className="text-black text-xl">Pinned Tags</p>
<div className="text-black flex items-center gap-2">
{tagPinDisclosure ? "Hide" : "Show"}
<FontAwesomeIcon
icon={faChevronDown}
className={`w-4 h-4 text-black ${
tagPinDisclosure ? "rotate-reverse" : "rotate"
}`}
/>
</div>
</Disclosure.Button>
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform opacity-0 -translate-y-3"
enterTo="transform opacity-100 translate-y-0"
leave="transition duration-100 ease-out"
leaveFrom="transform opacity-100 translate-y-0"
leaveTo="transform opacity-0 -translate-y-3"
>
<Disclosure.Panel className="flex gap-2 flex-wrap">
{tags.slice(0, 19).map((e, i) => (
<Link
href={`/tags/${e.id}`}
key={i}
className="px-2 py-1 bg-sky-200 rounded-full hover:opacity-60 duration-100 text-black"
>
{e.name}
</Link>
))}
</Disclosure.Panel>
</Transition>
</div>
</Disclosure> */}
</div> </div>
</div> </div>
</MainLayout> </MainLayout>
+1
View File
@@ -64,6 +64,7 @@ export default function Forgot() {
type="email" type="email"
placeholder="johnny@example.com" placeholder="johnny@example.com"
value={form.email} value={form.email}
className="bg-white"
onChange={(e) => setForm({ ...form, email: e.target.value })} onChange={(e) => setForm({ ...form, email: e.target.value })}
/> />
</div> </div>
+2
View File
@@ -62,6 +62,7 @@ export default function Login() {
<TextInput <TextInput
placeholder="johnny" placeholder="johnny"
value={form.username} value={form.username}
className="bg-white"
onChange={(e) => setForm({ ...form, username: e.target.value })} onChange={(e) => setForm({ ...form, username: e.target.value })}
/> />
</div> </div>
@@ -75,6 +76,7 @@ export default function Login() {
type="password" type="password"
placeholder="••••••••••••••" placeholder="••••••••••••••"
value={form.password} value={form.password}
className="bg-white"
onChange={(e) => setForm({ ...form, password: e.target.value })} onChange={(e) => setForm({ ...form, password: e.target.value })}
/> />
{emailEnabled && ( {emailEnabled && (
+5
View File
@@ -111,6 +111,7 @@ export default function Register() {
<TextInput <TextInput
placeholder="Johnny" placeholder="Johnny"
value={form.name} value={form.name}
className="bg-white"
onChange={(e) => setForm({ ...form, name: e.target.value })} onChange={(e) => setForm({ ...form, name: e.target.value })}
/> />
</div> </div>
@@ -124,6 +125,7 @@ export default function Register() {
<TextInput <TextInput
placeholder="john" placeholder="john"
value={form.username} value={form.username}
className="bg-white"
onChange={(e) => setForm({ ...form, username: e.target.value })} onChange={(e) => setForm({ ...form, username: e.target.value })}
/> />
</div> </div>
@@ -139,6 +141,7 @@ export default function Register() {
type="email" type="email"
placeholder="johnny@example.com" placeholder="johnny@example.com"
value={form.email} value={form.email}
className="bg-white"
onChange={(e) => setForm({ ...form, email: e.target.value })} onChange={(e) => setForm({ ...form, email: e.target.value })}
/> />
</div> </div>
@@ -153,6 +156,7 @@ export default function Register() {
type="password" type="password"
placeholder="••••••••••••••" placeholder="••••••••••••••"
value={form.password} value={form.password}
className="bg-white"
onChange={(e) => setForm({ ...form, password: e.target.value })} onChange={(e) => setForm({ ...form, password: e.target.value })}
/> />
</div> </div>
@@ -166,6 +170,7 @@ export default function Register() {
type="password" type="password"
placeholder="••••••••••••••" placeholder="••••••••••••••"
value={form.passwordConfirmation} value={form.passwordConfirmation}
className="bg-white"
onChange={(e) => onChange={(e) =>
setForm({ ...form, passwordConfirmation: e.target.value }) setForm({ ...form, passwordConfirmation: e.target.value })
} }
+15
View File
@@ -47,6 +47,21 @@
animation: slide-up-animation 70ms; animation: slide-up-animation 70ms;
} }
.slide-down {
animation: slide-down-animation 70ms;
}
@keyframes slide-down-animation {
0% {
transform: translateY(-15%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slide-up-animation { @keyframes slide-up-animation {
0% { 0% {
transform: translateY(15%); transform: translateY(15%);