many visual changes and improvements

This commit is contained in:
Daniel
2023-06-05 13:24:43 +03:30
parent 6a4f21fc0a
commit a9d7303359
24 changed files with 311 additions and 194 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ export default function ({ link, count }: Props) {
<div className="flex gap-3 items-center flex-wrap my-3">
<Link href={`/collections/${link.collection.id}`}>
<div className="flex items-center gap-1 cursor-pointer hover:opacity-60 duration-100">
<FontAwesomeIcon icon={faFolder} className="w-4 text-sky-300" />
<FontAwesomeIcon icon={faFolder} className="w-4 text-sky-500" />
<p className="text-sky-900">{link.collection.name}</p>
</div>
</Link>
+1 -1
View File
@@ -24,7 +24,7 @@ export default function Dropdown({ onClickOutside, className, items }: Props) {
return (
<ClickAwayHandler
onClickOutside={onClickOutside}
className={`${className} border border-sky-100 py-1 shadow-md bg-gray-50 rounded-md flex flex-col z-10`}
className={`${className} py-1 shadow-md bg-gray-50 rounded-md flex flex-col z-10`}
>
{items.map((e, i) => {
const inner = (
+57
View File
@@ -0,0 +1,57 @@
import React, { SetStateAction } from "react";
import ClickAwayHandler from "./ClickAwayHandler";
import Checkbox from "./Checkbox";
import { SearchSettings } from "@/types/global";
type Props = {
setFilterDropdown: (value: SetStateAction<boolean>) => void;
toggleCheckbox: (
name: "name" | "title" | "url" | "collection" | "tags"
) => void;
searchSettings: SearchSettings;
};
export default function FilterSearchDropdown({
setFilterDropdown,
toggleCheckbox,
searchSettings,
}: Props) {
return (
<ClickAwayHandler
onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement;
if (target.id !== "filter-dropdown") setFilterDropdown(false);
}}
className="absolute top-8 right-0 shadow-md bg-gray-50 rounded-md p-2 z-20 w-40"
>
<p className="mb-2 text-sky-900 text-center font-semibold">Filter by</p>
<div className="flex flex-col gap-2">
<Checkbox
label="Name"
state={searchSettings.filter.name}
onClick={() => toggleCheckbox("name")}
/>
<Checkbox
label="Link"
state={searchSettings.filter.url}
onClick={() => toggleCheckbox("url")}
/>
<Checkbox
label="Title"
state={searchSettings.filter.title}
onClick={() => toggleCheckbox("title")}
/>
<Checkbox
label="Collection"
state={searchSettings.filter.collection}
onClick={() => toggleCheckbox("collection")}
/>
<Checkbox
label="Tags"
state={searchSettings.filter.tags}
onClick={() => toggleCheckbox("tags")}
/>
</div>
</ClickAwayHandler>
);
}
+8 -4
View File
@@ -78,22 +78,26 @@ export default function ({ link, count }: Props) {
<div className="flex justify-between gap-5 w-full h-full z-0">
<div className="flex flex-col justify-between">
<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-400 font-bold">{count + 1}.</p>
<p className="text-lg text-sky-600 font-bold">{link.name}</p>
</div>
<p className="text-sky-400 text-sm font-medium">{link.title}</p>
<div className="flex gap-3 items-center flex-wrap my-3">
<Link href={`/collections/${link.collection.id}`}>
<div className="flex items-center gap-1 cursor-pointer hover:opacity-60 duration-100">
<FontAwesomeIcon icon={faFolder} className="w-4 text-sky-300" />
<FontAwesomeIcon
icon={faFolder}
className="w-4 h-4 mt-1"
style={{ color: link.collection.color }}
/>
<p className="text-sky-900">{link.collection.name}</p>
</div>
</Link>
<div className="flex gap-1 items-center flex-wrap">
<div className="flex gap-1 items-center flex-wrap mt-1">
{link.tags.map((e, i) => (
<Link key={i} href={`/tags/${e.id}`}>
<p className="px-2 py-1 bg-sky-200 text-sky-700 text-xs rounded-3xl cursor-pointer hover:bg-sky-100 duration-100">
<p className="px-2 py-1 bg-sky-200 text-sky-700 text-xs rounded-3xl cursor-pointer hover:opacity-60 duration-100">
{e.name}
</p>
</Link>
+4 -4
View File
@@ -34,7 +34,7 @@ export default function ChangePassword({
<div className="max-w-sm mx-auto flex flex-col gap-3">
<p className="text-xl text-sky-500 mb-2 text-center">Change Password</p>
<p className="text-sm font-bold text-sky-300">Old Password</p>
<p className="text-sm text-sky-500">Old Password</p>
<input
value={oldPassword}
@@ -42,7 +42,7 @@ export default function ChangePassword({
type="text"
className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100"
/>
<p className="text-sm font-bold text-sky-300">New Password</p>
<p className="text-sm text-sky-500">New Password</p>
<input
value={newPassword1}
@@ -50,7 +50,7 @@ export default function ChangePassword({
type="text"
className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100"
/>
<p className="text-sm font-bold text-sky-300">Re-enter New Password</p>
<p className="text-sm text-sky-500">Re-enter New Password</p>
<input
value={newPassword2}
@@ -60,7 +60,7 @@ export default function ChangePassword({
/>
<div
className="mx-auto mt-2 text-white flex items-center gap-2 py-2 px-5 rounded-md select-none font-bold duration-100 bg-sky-500 hover:bg-sky-400 cursor-pointer"
className="mx-auto mt-2 text-white flex items-center gap-2 py-2 px-5 rounded-md select-none duration-100 bg-sky-500 hover:bg-sky-400 cursor-pointer"
onClick={submit}
>
Save
@@ -47,7 +47,7 @@ export default function CollectionInfo({
<div className="flex flex-col sm:flex-row gap-3">
<div className="w-full">
<p className="text-sm font-bold text-sky-300 mb-2">
<p className="text-sm text-sky-500 mb-2">
Name
<RequiredBadge />
</p>
@@ -63,9 +63,7 @@ export default function CollectionInfo({
/>
<div className="color-picker flex justify-between">
<div className="flex flex-col justify-between items-center w-32">
<p className="text-sm w-full font-bold text-sky-300 mb-2">
Icon Color
</p>
<p className="text-sm w-full text-sky-500 mb-2">Icon Color</p>
<div style={{ color: collection.color }}>
<FontAwesomeIcon
icon={faFolder}
@@ -73,9 +71,9 @@ export default function CollectionInfo({
/>
</div>
<div
className="py-1 px-2 rounded-md text-xs font-semibold cursor-pointer text-gray-500 hover:bg-slate-200 duration-100"
className="py-1 px-2 rounded-md text-xs font-semibold cursor-pointer text-sky-500 hover:bg-slate-200 duration-100"
onClick={() =>
setCollection({ ...collection, color: "#7dd3fc" })
setCollection({ ...collection, color: "#0ea5e9" })
}
>
Reset
@@ -90,7 +88,7 @@ export default function CollectionInfo({
</div>
<div className="w-full">
<p className="text-sm font-bold text-sky-300 mb-2">Description</p>
<p className="text-sm text-sky-500 mb-2">Description</p>
<textarea
className="w-full h-[11.4rem] resize-none border rounded-md duration-100 bg-white p-3 outline-none border-sky-100 focus:border-sky-500"
placeholder="The purpose of this Collection..."
@@ -77,7 +77,7 @@ export default function TeamManagement({
Sharing & Collaboration
</p>
<p className="text-sm font-bold text-sky-300">Make Public</p>
<p className="text-sm text-sky-500">Make Public</p>
<Checkbox
label="Make this a public collection."
@@ -93,7 +93,9 @@ export default function TeamManagement({
{collection.isPublic ? (
<div>
<p className="mb-2 text-gray-500">Public Link (Click to copy)</p>
<p className="text-sm text-sky-500 mb-2">
Public Link (Click to copy)
</p>
<div
onClick={() => {
try {
@@ -113,7 +115,7 @@ export default function TeamManagement({
<hr />
<p className="text-sm font-bold text-sky-300">Member Management</p>
<p className="text-sm text-sky-500">Member Management</p>
<div className="flex items-center gap-2">
<input
@@ -202,10 +204,10 @@ export default function TeamManagement({
</div>
<div className="flex sm:block items-center gap-5">
<div>
<p className="font-bold text-sm text-gray-500">
<p className="font-bold text-sm text-sky-500">
Permissions
</p>
<p className="text-xs text-gray-400 mb-2">
<p className="text-xs text-gray-500 mb-2">
(Click to toggle.)
</p>
</div>
+4 -4
View File
@@ -115,7 +115,7 @@ export default function EditLink({
<div className="grid sm:grid-cols-2 gap-3">
<div>
<p className="text-sm font-bold text-sky-300 mb-2">
<p className="text-sm text-sky-500 mb-2">
Name
<RequiredBadge />
</p>
@@ -130,7 +130,7 @@ export default function EditLink({
{method === "CREATE" ? (
<div>
<p className="text-sm font-bold text-sky-300 mb-2">
<p className="text-sm text-sky-500 mb-2">
URL
<RequiredBadge />
</p>
@@ -145,7 +145,7 @@ export default function EditLink({
) : null}
<div>
<p className="text-sm font-bold text-sky-300 mb-2">
<p className="text-sm text-sky-500 mb-2">
Collection
<RequiredBadge />
</p>
@@ -167,7 +167,7 @@ export default function EditLink({
</div>
<div className={method === "UPDATE" ? "sm:col-span-2" : ""}>
<p className="text-sm font-bold text-sky-300 mb-2">Tags</p>
<p className="text-sm text-sky-500 mb-2">Tags</p>
<TagSelection
onChange={setTags}
defaultValue={link.tags.map((e) => {
+8 -13
View File
@@ -95,12 +95,10 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
<div className="flex flex-col gap-3 sm:w-[35rem] w-80">
<p className="text-xl text-sky-500 mb-2 text-center">Settings</p>
<p className="text-sky-600">Profile Settings</p>
<div className="grid sm:grid-cols-2 gap-3 auto-rows-auto">
<div className="flex flex-col gap-3">
<div>
<p className="text-sm font-bold text-sky-300 mb-2">Display Name</p>
<p className="text-sm text-sky-500 mb-2">Display Name</p>
<input
type="text"
value={user.name}
@@ -110,7 +108,7 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
</div>
<div>
<p className="text-sm font-bold text-sky-300 mb-2">Email</p>
<p className="text-sm text-sky-500 mb-2">Email</p>
<input
type="text"
value={user.email}
@@ -120,7 +118,7 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
</div>
<div>
<p className="text-sm font-bold text-sky-300 mb-2">Password</p>
<p className="text-sm text-sky-500 mb-2">Password</p>
<div className="w-fit" onClick={togglePasswordFormModal}>
<div className="border border-sky-100 rounded-md bg-white px-2 py-1 text-center select-none cursor-pointer text-sky-900 duration-100 hover:border-sky-500">
@@ -139,7 +137,7 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
</div>
<div className="sm:row-span-2 sm:justify-self-center mb-3">
<p className="text-sm font-bold text-sky-300 mb-2 sm:text-center">
<p className="text-sm text-sky-500 mb-2 sm:text-center">
Profile Photo
</p>
<div className="w-28 h-28 flex items-center justify-center border border-sky-100 rounded-full relative">
@@ -202,7 +200,7 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
<hr />
<p className="text-sky-600">Privacy Settings</p>
<p className="text-sm text-sky-500 mb-2">Profile Visibility</p>
<Checkbox
label="Make profile private"
@@ -211,19 +209,16 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
onClick={() => setUser({ ...user, isPrivate: !user.isPrivate })}
/>
<p className="text-gray-500 text-sm mb-3">
<p className="text-gray-500 text-sm">
This will limit who can find and add you to other Collections.
</p>
{user.isPrivate ? (
<div>
<p className="text-sm font-bold text-sky-300 mb-2">
Whitelisted Users
</p>
<p className="text-sm text-sky-500 mb-2">Whitelisted Users</p>
<p className="text-gray-500 text-sm mb-3">
Please provide the Email addresses of the users you wish to grant
visibility to your profile. Separate by comma. Users not included
will be unable to view your profile.
visibility to your profile. Separated by comma.
</p>
<textarea
className="w-full resize-none border rounded-md duration-100 bg-white p-2 outline-none border-sky-100 focus:border-sky-500"
+1 -1
View File
@@ -51,7 +51,7 @@ export default function ({ link, count }: Props) {
<div className="flex justify-between items-center gap-5 w-full h-full z-0">
<div className="flex flex-col justify-between">
<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-400 font-bold">{count + 1}.</p>
<p className="text-lg text-sky-600 font-bold">{link.name}</p>
</div>
@@ -7,7 +7,6 @@ import {
faBookmark,
faChartSimple,
} from "@fortawesome/free-solid-svg-icons";
import SidebarItem from "./SidebarItem";
import useTagStore from "@/store/tags";
import Link from "next/link";
import { useRouter } from "next/router";
@@ -23,13 +22,13 @@ export default function ({ className }: { className?: string }) {
useEffect(() => {
setActive(router.asPath);
}, [router]);
}, [router, collections]);
return (
<div
className={`bg-gray-100 h-screen w-64 xl:w-80 overflow-y-auto border-solid border-r-sky-100 px-2 border z-20 ${className}`}
>
<p className="p-3 text-sky-500 font-bold text-2xl my-2 leading-4">
<p className="p-2 text-sky-500 font-bold text-2xl my-2 leading-4">
Linkwarden
</p>
@@ -38,45 +37,29 @@ export default function ({ className }: { className?: string }) {
<div
className={`${
active === "/dashboard"
? "bg-sky-500"
? "bg-sky-200"
: "hover:bg-slate-200 bg-gray-100"
} outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex items-center gap-2`}
>
<FontAwesomeIcon
icon={faChartSimple}
className={`w-4 h-4 ${
active === "/dashboard" ? "text-white" : "text-sky-300"
}`}
className={`w-6 h-6 drop-shadow text-sky-500`}
/>
<p
className={`${
active === "/dashboard" ? "text-white" : "text-sky-900"
}`}
>
Dashboard
</p>
<p className="text-sky-600">Dashboard</p>
</div>
</Link>
<Link href="/collections">
<div
className={`${
active === "/collections" ? "bg-sky-500" : "hover:bg-slate-200"
active === "/collections" ? "bg-sky-200" : "hover:bg-slate-200"
} outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex items-center gap-2`}
>
<FontAwesomeIcon
icon={faBox}
className={`w-4 h-4 ${
active === "/collections" ? "text-white" : "text-sky-300"
}`}
className={`w-6 h-6 drop-shadow text-sky-500`}
/>
<p
className={`${
active === "/collections" ? "text-white" : "text-sky-900"
}`}
>
All Collections
</p>
<p className="text-sky-600">All Collections</p>
</div>
</Link>
@@ -84,60 +67,71 @@ export default function ({ className }: { className?: string }) {
<div
className={`${
active === "/links"
? "bg-sky-500"
? "bg-sky-200"
: "hover:bg-slate-200 bg-gray-100"
} outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex items-center gap-2`}
>
<FontAwesomeIcon
icon={faBookmark}
className={`w-4 h-4 ${
active === "/links" ? "text-white" : "text-sky-300"
}`}
className={`w-6 h-6 drop-shadow text-sky-500`}
/>
<p
className={`${
active === "/links" ? "text-white" : "text-sky-900"
}`}
>
All Links
</p>
<p className="text-sky-600">All Links</p>
</div>
</Link>
</div>
<div className="text-gray-500 mt-5">
<p className="text-sm mb-2 pl-3 font-semibold">Collections</p>
<p className="text-sm mb-2 pl-2 font-semibold">Collections</p>
</div>
<div className="flex flex-col gap-1">
{collections
.sort((a, b) => a.name.localeCompare(b.name))
.map((e, i) => {
return (
<SidebarItem
key={i}
text={e.name}
icon={<FontAwesomeIcon icon={faFolder} />}
iconColor={e.color}
path={`/collections/${e.id}`}
className="capitalize"
/>
<Link key={i} href={`/collections/${e.id}`}>
<div
className={`${
active === `/collections/${e.id}`
? "bg-sky-200"
: "hover:bg-slate-200 bg-gray-100"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
>
<FontAwesomeIcon
icon={faFolder}
className="w-6 h-6 drop-shadow"
style={{ color: e.color }}
/>
<p className="text-sky-600 truncate w-4/6">{e.name}</p>
</div>
</Link>
);
})}
</div>
<div className="text-gray-500 mt-5">
<p className="text-sm mb-2 pl-3 font-semibold">Tags</p>
<p className="text-sm mb-2 pl-2 font-semibold">Tags</p>
</div>
<div className="flex flex-col gap-1">
{tags
.sort((a, b) => a.name.localeCompare(b.name))
.map((e, i) => {
return (
<SidebarItem
key={i}
text={e.name}
icon={<FontAwesomeIcon icon={faHashtag} />}
path={`/tags/${e.id}`}
/>
<Link key={i} href={`/tags/${e.id}`}>
<div
className={`${
active === `/tags/${e.id}`
? "bg-sky-200"
: "hover:bg-slate-200 bg-gray-100"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
>
<FontAwesomeIcon
icon={faHashtag}
className="w-4 h-4 text-sky-500 mt-1"
/>
<p className="text-sky-600 truncate w-4/6">{e.name}</p>
</div>
</Link>
);
})}
</div>
-49
View File
@@ -1,49 +0,0 @@
import Link from "next/link";
import React, { ReactElement, useEffect, useState } from "react";
import { useRouter } from "next/router";
interface SidebarItemProps {
text: string;
icon: ReactElement;
path: string;
className?: string;
iconColor?: string;
}
export default function ({
text,
icon,
path,
className,
iconColor,
}: SidebarItemProps) {
const router = useRouter();
const [active, setActive] = useState(false);
useEffect(() => {
if (router.asPath === path) setActive(true);
else setActive(false);
}, [router]);
return (
<Link href={path}>
<div
className={`${
active ? "bg-sky-500" : "hover:bg-slate-200 bg-gray-100"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md ${className}`}
>
{React.cloneElement(icon, {
className: "w-4 h-4",
style: {
color: active ? "white" : iconColor ? iconColor : "#7dd3fc",
},
})}
<p
className={`${active ? "text-white" : "text-sky-900"} truncate w-4/6`}
>
{text}
</p>
</div>
</Link>
);
}
+1 -1
View File
@@ -19,7 +19,7 @@ export default function SortLinkDropdown({
const target = e.target as HTMLInputElement;
if (target.id !== "sort-dropdown") toggleSortDropdown();
}}
className="absolute top-8 right-0 shadow-md bg-gray-50 rounded-md p-2 z-10 border border-sky-100 w-48"
className="absolute top-8 right-0 shadow-md bg-gray-50 rounded-md p-2 z-10 w-48"
>
<p className="mb-2 text-sky-900 text-center font-semibold">Sort by</p>
<div className="flex flex-col gap-2">