recreated many components
This commit is contained in:
parent
b51b08b0f4
commit
916c69602d
|
@ -2,29 +2,24 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faEllipsis, faGlobe, faLink } from "@fortawesome/free-solid-svg-icons";
|
import { faEllipsis, faGlobe, faLink } from "@fortawesome/free-solid-svg-icons";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
import Dropdown from "./Dropdown";
|
import { useEffect, useState } from "react";
|
||||||
import { useState } from "react";
|
|
||||||
import ProfilePhoto from "./ProfilePhoto";
|
import ProfilePhoto from "./ProfilePhoto";
|
||||||
import { faCalendarDays } from "@fortawesome/free-regular-svg-icons";
|
import { faCalendarDays } from "@fortawesome/free-regular-svg-icons";
|
||||||
import useModalStore from "@/store/modals";
|
import useModalStore from "@/store/modals";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
import useLocalSettingsStore from "@/store/localSettings";
|
import useLocalSettingsStore from "@/store/localSettings";
|
||||||
|
import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
|
import useAccountStore from "@/store/account";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
collection: CollectionIncludingMembersAndLinkCount;
|
collection: CollectionIncludingMembersAndLinkCount;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DropdownTrigger =
|
|
||||||
| {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
| false;
|
|
||||||
|
|
||||||
export default function CollectionCard({ collection, className }: Props) {
|
export default function CollectionCard({ collection, className }: Props) {
|
||||||
const { setModal } = useModalStore();
|
const { setModal } = useModalStore();
|
||||||
const { settings } = useLocalSettingsStore();
|
const { settings } = useLocalSettingsStore();
|
||||||
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
const formattedDate = new Date(collection.createdAt as string).toLocaleString(
|
const formattedDate = new Date(collection.createdAt as string).toLocaleString(
|
||||||
"en-US",
|
"en-US",
|
||||||
|
@ -35,28 +30,40 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const [expandDropdown, setExpandDropdown] = useState<DropdownTrigger>(false);
|
|
||||||
|
|
||||||
const permissions = usePermissions(collection.id as number);
|
const permissions = usePermissions(collection.id as number);
|
||||||
|
|
||||||
|
const [collectionOwner, setCollectionOwner] = useState({
|
||||||
|
id: null as unknown as number,
|
||||||
|
name: "",
|
||||||
|
username: "",
|
||||||
|
image: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchOwner = async () => {
|
||||||
|
if (collection && collection.ownerId !== account.id) {
|
||||||
|
const owner = await getPublicUserData(collection.ownerId as number);
|
||||||
|
setCollectionOwner(owner);
|
||||||
|
} else if (collection && collection.ownerId === account.id) {
|
||||||
|
setCollectionOwner({
|
||||||
|
id: account.id as number,
|
||||||
|
name: account.name,
|
||||||
|
username: account.username as string,
|
||||||
|
image: account.image as string,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchOwner();
|
||||||
|
}, [collection]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="relative">
|
||||||
|
<div className="dropdown dropdown-bottom dropdown-end absolute top-3 right-3 z-10">
|
||||||
<div
|
<div
|
||||||
style={{
|
tabIndex={0}
|
||||||
backgroundImage: `linear-gradient(45deg, ${collection.color}30 10%, ${
|
role="button"
|
||||||
settings.theme === "dark" ? "#262626" : "#f3f4f6"
|
className="btn btn-ghost btn-sm btn-square text-neutral"
|
||||||
} 50%, ${settings.theme === "dark" ? "#262626" : "#f9fafb"} 100%)`,
|
|
||||||
}}
|
|
||||||
className={`border border-solid border-neutral-content self-stretch min-h-[12rem] rounded-2xl shadow duration-100 hover:shadow-none hover:opacity-80 group relative ${
|
|
||||||
className || ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
onClick={(e) => {
|
|
||||||
setExpandDropdown({ x: e.clientX, y: e.clientY });
|
|
||||||
}}
|
|
||||||
id={"expand-dropdown" + collection.id}
|
|
||||||
className="btn btn-ghost btn-sm btn-square absolute right-4 top-4 z-10"
|
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faEllipsis}
|
icon={faEllipsis}
|
||||||
|
@ -65,15 +72,94 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
id={"expand-dropdown" + collection.id}
|
id={"expand-dropdown" + collection.id}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<ul className="dropdown-content z-[1] menu p-2 shadow bg-base-200 border border-neutral-content rounded-box w-52">
|
||||||
|
{permissions === true ? (
|
||||||
|
<li>
|
||||||
|
<div
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={() =>
|
||||||
|
collection &&
|
||||||
|
setModal({
|
||||||
|
modal: "COLLECTION",
|
||||||
|
state: true,
|
||||||
|
method: "UPDATE",
|
||||||
|
isOwner: permissions === true,
|
||||||
|
active: collection,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Edit Collection Info
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
) : undefined}
|
||||||
|
<li>
|
||||||
|
<div
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={() =>
|
||||||
|
collection &&
|
||||||
|
setModal({
|
||||||
|
modal: "COLLECTION",
|
||||||
|
state: true,
|
||||||
|
method: "UPDATE",
|
||||||
|
isOwner: permissions === true,
|
||||||
|
active: collection,
|
||||||
|
defaultIndex: permissions === true ? 1 : 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{permissions === true ? "Share and Collaborate" : "View Team"}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={() =>
|
||||||
|
collection &&
|
||||||
|
setModal({
|
||||||
|
modal: "COLLECTION",
|
||||||
|
state: true,
|
||||||
|
method: "UPDATE",
|
||||||
|
isOwner: permissions === true,
|
||||||
|
active: collection,
|
||||||
|
defaultIndex: permissions === true ? 2 : 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{permissions === true ? "Delete Collection" : "Leave Collection"}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
<Link
|
<Link
|
||||||
href={`/collections/${collection.id}`}
|
href={`/collections/${collection.id}`}
|
||||||
className="flex flex-col gap-2 justify-between min-h-[12rem] h-full select-none p-5"
|
style={{
|
||||||
|
backgroundImage: `linear-gradient(45deg, ${collection.color}30 10%, ${
|
||||||
|
settings.theme === "dark" ? "oklch(var(--b2))" : "oklch(var(--b2))"
|
||||||
|
} 50%, ${
|
||||||
|
settings.theme === "dark" ? "oklch(var(--b2))" : "oklch(var(--b2))"
|
||||||
|
} 100%)`,
|
||||||
|
}}
|
||||||
|
className="card card-compact shadow-xl hover:shadow-none duration-200 border border-neutral-content relative"
|
||||||
>
|
>
|
||||||
<p className="text-2xl capitalize break-words line-clamp-3 w-4/5">
|
<div className="card-body flex flex-col justify-between min-h-[12rem]">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<p className="card-title break-words line-clamp-2 w-full">
|
||||||
{collection.name}
|
{collection.name}
|
||||||
</p>
|
</p>
|
||||||
|
<div className="w-8 h-8 ml-10"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center w-full">
|
<div className="flex items-center w-full">
|
||||||
|
{collectionOwner.id ? (
|
||||||
|
<ProfilePhoto
|
||||||
|
src={collectionOwner.image || undefined}
|
||||||
|
className="w-7 h-7 -mr-3"
|
||||||
|
/>
|
||||||
|
) : undefined}
|
||||||
{collection.members
|
{collection.members
|
||||||
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
||||||
.map((e, i) => {
|
.map((e, i) => {
|
||||||
|
@ -81,14 +167,16 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
key={i}
|
key={i}
|
||||||
src={e.user.image ? e.user.image : undefined}
|
src={e.user.image ? e.user.image : undefined}
|
||||||
className="-mr-3 border-[3px]"
|
className="-mr-3"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.slice(0, 4)}
|
.slice(0, 3)}
|
||||||
{collection.members.length - 4 > 0 ? (
|
{collection.members.length - 3 > 0 ? (
|
||||||
<div className="h-10 w-10 text-white flex items-center justify-center rounded-full border-[3px] bg-sky-600 dark:bg-sky-600 border-slate-200 -mr-3">
|
<div className={`avatar placeholder -mr-3`}>
|
||||||
+{collection.members.length - 4}
|
<div className="bg-base-100 text-base-content rounded-full w-8 h-8 ring-2 ring-base-content">
|
||||||
|
<span>+{collection.members.length - 3}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -107,75 +195,14 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
/>
|
/>
|
||||||
{collection._count && collection._count.links}
|
{collection._count && collection._count.links}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end gap-1 text-neutral">
|
<div className="flex items-center justify-end gap-1 text-neutral w-full">
|
||||||
<FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" />
|
<FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" />
|
||||||
<p className="font-bold text-xs">{formattedDate}</p>
|
<p className="font-bold text-xs w-full">{formattedDate}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{expandDropdown ? (
|
|
||||||
<Dropdown
|
|
||||||
points={{ x: expandDropdown.x, y: expandDropdown.y }}
|
|
||||||
items={[
|
|
||||||
permissions === true
|
|
||||||
? {
|
|
||||||
name: "Edit Collection Info",
|
|
||||||
onClick: () => {
|
|
||||||
collection &&
|
|
||||||
setModal({
|
|
||||||
modal: "COLLECTION",
|
|
||||||
state: true,
|
|
||||||
method: "UPDATE",
|
|
||||||
isOwner: permissions === true,
|
|
||||||
active: collection,
|
|
||||||
});
|
|
||||||
setExpandDropdown(false);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
{
|
|
||||||
name: permissions === true ? "Share/Collaborate" : "View Team",
|
|
||||||
onClick: () => {
|
|
||||||
collection &&
|
|
||||||
setModal({
|
|
||||||
modal: "COLLECTION",
|
|
||||||
state: true,
|
|
||||||
method: "UPDATE",
|
|
||||||
isOwner: permissions === true,
|
|
||||||
active: collection,
|
|
||||||
defaultIndex: permissions === true ? 1 : 0,
|
|
||||||
});
|
|
||||||
setExpandDropdown(false);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name:
|
|
||||||
permissions === true ? "Delete Collection" : "Leave Collection",
|
|
||||||
onClick: () => {
|
|
||||||
collection &&
|
|
||||||
setModal({
|
|
||||||
modal: "COLLECTION",
|
|
||||||
state: true,
|
|
||||||
method: "UPDATE",
|
|
||||||
isOwner: permissions === true,
|
|
||||||
active: collection,
|
|
||||||
defaultIndex: permissions === true ? 2 : 1,
|
|
||||||
});
|
|
||||||
setExpandDropdown(false);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onClickOutside={(e: Event) => {
|
|
||||||
const target = e.target as HTMLInputElement;
|
|
||||||
if (target.id !== "expand-dropdown" + collection.id)
|
|
||||||
setExpandDropdown(false);
|
|
||||||
}}
|
|
||||||
className="w-fit"
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ type Props = {
|
||||||
export default function dashboardItem({ name, value, icon }: Props) {
|
export default function dashboardItem({ name, value, icon }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-4 items-end">
|
<div className="flex gap-4 items-end">
|
||||||
<div className="p-4 bg-primary bg-opacity-20 dark:bg-opacity-10 rounded-xl select-none">
|
<div className="p-4 bg-secondary/30 rounded-xl select-none">
|
||||||
<FontAwesomeIcon icon={icon} className="w-8 h-8 text-primary" />
|
<FontAwesomeIcon icon={icon} className="w-8 h-8 text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-center">
|
<div className="flex flex-col justify-center">
|
||||||
|
|
|
@ -82,7 +82,7 @@ export default function LinkPreview({ link, className, settings }: Props) {
|
||||||
<div className="flex items-center gap-1 max-w-full w-fit my-1 hover:opacity-70 duration-100">
|
<div className="flex items-center gap-1 max-w-full w-fit my-1 hover:opacity-70 duration-100">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faFolder}
|
icon={faFolder}
|
||||||
className="w-4 h-4 mt-1 drop-shadow text-sky-400"
|
className="w-4 h-4 mt-1 drop-shadow text-primary"
|
||||||
/>
|
/>
|
||||||
<p className="truncate capitalize w-full">Landing Pages ⚡️</p>
|
<p className="truncate capitalize w-full">Landing Pages ⚡️</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -93,7 +93,7 @@ export default function PreservedFormats() {
|
||||||
{link?.screenshotPath && link?.screenshotPath !== "pending" ? (
|
{link?.screenshotPath && link?.screenshotPath !== "pending" ? (
|
||||||
<div className="flex justify-between items-center pr-1 border border-neutral-content rounded-md">
|
<div className="flex justify-between items-center pr-1 border border-neutral-content rounded-md">
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-l-md">
|
<div className="text-white bg-secondary p-2 rounded-l-md">
|
||||||
<FontAwesomeIcon icon={faFileImage} className="w-6 h-6" />
|
<FontAwesomeIcon icon={faFileImage} className="w-6 h-6" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ export default function PreservedFormats() {
|
||||||
{link?.pdfPath && link.pdfPath !== "pending" ? (
|
{link?.pdfPath && link.pdfPath !== "pending" ? (
|
||||||
<div className="flex justify-between items-center pr-1 border border-neutral-content rounded-md">
|
<div className="flex justify-between items-center pr-1 border border-neutral-content rounded-md">
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-l-md">
|
<div className="text-white bg-secondary p-2 rounded-l-md">
|
||||||
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" />
|
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -50,16 +50,18 @@ export default function Navbar() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between gap-2 items-center px-5 py-2 border-solid border-b-neutral-content border-b h-16">
|
<div className="flex justify-between gap-2 items-center px-5 py-2 border-solid border-b-neutral-content border-b">
|
||||||
<div
|
<div
|
||||||
onClick={toggleSidebar}
|
onClick={toggleSidebar}
|
||||||
className="inline-flex lg:hidden gap-1 items-center select-none cursor-pointer p-[0.687rem] text-neutral rounded-md duration-100 hover:bg-neutral-content"
|
className="text-neutral btn btn-square btn-sm btn-ghost lg:hidden"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faBars} className="w-5 h-5" />
|
<FontAwesomeIcon icon={faBars} className="w-5 h-5" />
|
||||||
</div>
|
</div>
|
||||||
<SearchBar />
|
<SearchBar />
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div
|
<ToggleDarkMode className="sm:inline-grid hidden" />
|
||||||
|
|
||||||
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setModal({
|
setModal({
|
||||||
modal: "LINK",
|
modal: "LINK",
|
||||||
|
@ -67,36 +69,28 @@ export default function Navbar() {
|
||||||
method: "CREATE",
|
method: "CREATE",
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className="inline-flex gap-1 relative sm:w-[7.2rem] items-center font-semibold select-none cursor-pointer p-[0.687rem] sm:p-2 sm:px-3 rounded-md sm:rounded-full hover:bg-neutral-content dark:hover:bg-sky-800 sm:dark:hover:bg-sky-600 text-primary sm:text-white sm:bg-sky-700 sm:hover:bg-sky-600 duration-100 group"
|
className="inline-flex sm:gap-1 relative sm:w-[5rem] items-center duration-100 group btn btn-accent text-white btn-sm"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faPlus}
|
icon={faPlus}
|
||||||
className="w-5 h-5 sm:group-hover:ml-9 sm:absolute duration-100"
|
className="w-5 h-5 sm:group-hover:ml-5 sm:absolute duration-100 left-2"
|
||||||
/>
|
/>
|
||||||
<span className="hidden sm:block group-hover:opacity-0 text-right w-full duration-100">
|
<span className="hidden sm:block group-hover:opacity-0 text-right w-full duration-100">
|
||||||
New Link
|
New
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<ToggleDarkMode className="sm:flex hidden" />
|
|
||||||
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div
|
<div
|
||||||
className="flex gap-1 group sm:hover:bg-neutral-content sm:hover:p-1 sm:hover:pr-2 duration-100 h-10 rounded-full items-center w-fit cursor-pointer"
|
className="btn btn-circle btn-ghost"
|
||||||
onClick={() => setProfileDropdown(!profileDropdown)}
|
onClick={() => setProfileDropdown(!profileDropdown)}
|
||||||
id="profile-dropdown"
|
id="profile-dropdown"
|
||||||
>
|
>
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
src={account.image ? account.image : undefined}
|
src={account.image ? account.image : undefined}
|
||||||
priority={true}
|
priority={true}
|
||||||
className="sm:group-hover:h-8 sm:group-hover:w-8 duration-100 border-[3px]"
|
className=""
|
||||||
/>
|
/>
|
||||||
<p
|
|
||||||
id="profile-dropdown"
|
|
||||||
className="leading-3 hidden sm:block select-none truncate max-w-[8rem] py-1"
|
|
||||||
>
|
|
||||||
{account.name}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{profileDropdown ? (
|
{profileDropdown ? (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
|
|
@ -6,11 +6,16 @@ import Image from "next/image";
|
||||||
type Props = {
|
type Props = {
|
||||||
src?: string;
|
src?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
emptyImage?: boolean;
|
|
||||||
priority?: boolean;
|
priority?: boolean;
|
||||||
|
name?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ProfilePhoto({ src, className, priority }: Props) {
|
export default function ProfilePhoto({
|
||||||
|
src,
|
||||||
|
className,
|
||||||
|
priority,
|
||||||
|
name,
|
||||||
|
}: Props) {
|
||||||
const [image, setImage] = useState("");
|
const [image, setImage] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -23,14 +28,21 @@ export default function ProfilePhoto({ src, className, priority }: Props) {
|
||||||
}, [src]);
|
}, [src]);
|
||||||
|
|
||||||
return !image ? (
|
return !image ? (
|
||||||
<div
|
<div className={`avatar w-8 h-8 placeholder ${className || ""}`}>
|
||||||
className={`bg-sky-600 dark:bg-sky-600 text-white h-10 w-10 aspect-square shadow rounded-full border border-neutral-content flex items-center justify-center ${
|
<div className="bg-base-100 text-base-content rounded-full w-full h-full ring-2 ring-base-content">
|
||||||
className || ""
|
{name ? (
|
||||||
}`}
|
<span className="text-2xl capitalize">{name.slice(0, 1)}</span>
|
||||||
>
|
) : (
|
||||||
<FontAwesomeIcon icon={faUser} className="w-1/2 h-1/2 aspect-square" />
|
<FontAwesomeIcon
|
||||||
|
icon={faUser}
|
||||||
|
className="w-1/2 h-1/2 aspect-square"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
<div className={`avatar w-8 h-8 drop-shadow-md ${className || ""}`}>
|
||||||
|
<div className="rounded-full w-full h-full ring-2 ring-base-content">
|
||||||
<Image
|
<Image
|
||||||
alt=""
|
alt=""
|
||||||
src={image}
|
src={image}
|
||||||
|
@ -39,9 +51,9 @@ export default function ProfilePhoto({ src, className, priority }: Props) {
|
||||||
priority={priority}
|
priority={priority}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
onError={() => setImage("")}
|
onError={() => setImage("")}
|
||||||
className={`h-10 w-10 bg-sky-600 dark:bg-sky-600 shadow rounded-full aspect-square border border-neutral-content ${
|
className="aspect-square rounded-full"
|
||||||
className || ""
|
|
||||||
}`}
|
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export default function LinkCard({ link, count }: Props) {
|
||||||
<Link
|
<Link
|
||||||
href={"/public/collections/20?q=" + e.name}
|
href={"/public/collections/20?q=" + e.name}
|
||||||
key={i}
|
key={i}
|
||||||
className="px-2 bg-sky-200 dark:bg-sky-900 text-xs rounded-3xl cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]"
|
className="px-2 bg-secondary text-white text-xs rounded-md cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]"
|
||||||
>
|
>
|
||||||
{e.name}
|
{e.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default function PublicSearchBar({ placeHolder }: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="border text-sm border-neutral-content bg-base-200 focus:border-sky-300 dark:focus:border-sky-600 rounded-md pl-8 py-2 pr-2 w-44 sm:w-60 md:focus:w-80 duration-100 outline-none"
|
className="border text-sm border-neutral-content bg-base-200 focus:border-primary rounded-md pl-8 py-2 pr-2 w-44 sm:w-60 md:focus:w-80 duration-100 outline-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default function SearchBar() {
|
||||||
e.key === "Enter" &&
|
e.key === "Enter" &&
|
||||||
router.push("/search?q=" + encodeURIComponent(searchQuery))
|
router.push("/search?q=" + encodeURIComponent(searchQuery))
|
||||||
}
|
}
|
||||||
className="border border-neutral-content bg-base-200 focus:border-primary rounded-md pl-10 py-2 pr-2 w-44 sm:w-60 md:focus:w-80 duration-100 outline-none"
|
className="border border-neutral-content bg-base-200 focus:border-primary py-2 rounded-md pl-10 pr-2 w-44 sm:w-60 md:focus:w-80 duration-100 outline-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -44,9 +44,9 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/account`
|
active === `/settings/account`
|
||||||
? "bg-primary"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faUser} className="w-6 h-6 text-primary" />
|
<FontAwesomeIcon icon={faUser} className="w-6 h-6 text-primary" />
|
||||||
|
|
||||||
|
@ -58,9 +58,9 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/appearance`
|
active === `/settings/appearance`
|
||||||
? "bg-primary"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faPalette}
|
icon={faPalette}
|
||||||
|
@ -75,9 +75,9 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/archive`
|
active === `/settings/archive`
|
||||||
? "bg-primary"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faBoxArchive}
|
icon={faBoxArchive}
|
||||||
|
@ -91,8 +91,10 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<Link href="/settings/api">
|
<Link href="/settings/api">
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/api` ? "bg-primary" : "hover:bg-slate-500"
|
active === `/settings/api`
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
? "bg-secondary/30"
|
||||||
|
: "hover:bg-neutral/20"
|
||||||
|
} duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faKey} className="w-6 h-6 text-primary" />
|
<FontAwesomeIcon icon={faKey} className="w-6 h-6 text-primary" />
|
||||||
|
|
||||||
|
@ -104,9 +106,9 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/password`
|
active === `/settings/password`
|
||||||
? "bg-primary"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faLock} className="w-6 h-6 text-primary" />
|
<FontAwesomeIcon icon={faLock} className="w-6 h-6 text-primary" />
|
||||||
|
|
||||||
|
@ -119,9 +121,9 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/billing`
|
active === `/settings/billing`
|
||||||
? "bg-primary"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faCreditCard}
|
icon={faCreditCard}
|
||||||
|
@ -144,7 +146,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="https://docs.linkwarden.app" target="_blank">
|
<Link href="https://docs.linkwarden.app" target="_blank">
|
||||||
<div
|
<div
|
||||||
className={`hover:bg-slate-500 duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
className={`hover:bg-neutral/20 duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faCircleQuestion as any}
|
icon={faCircleQuestion as any}
|
||||||
|
@ -157,7 +159,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
|
|
||||||
<Link href="https://github.com/linkwarden/linkwarden" target="_blank">
|
<Link href="https://github.com/linkwarden/linkwarden" target="_blank">
|
||||||
<div
|
<div
|
||||||
className={`hover:bg-slate-500 duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
className={`hover:bg-neutral/20 duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faGithub as any}
|
icon={faGithub as any}
|
||||||
|
@ -170,7 +172,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
|
|
||||||
<Link href="https://twitter.com/LinkwardenHQ" target="_blank">
|
<Link href="https://twitter.com/LinkwardenHQ" target="_blank">
|
||||||
<div
|
<div
|
||||||
className={`hover:bg-slate-500 duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
className={`hover:bg-neutral/20 duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faXTwitter as any}
|
icon={faXTwitter as any}
|
||||||
|
@ -183,7 +185,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
|
|
||||||
<Link href="https://fosstodon.org/@linkwarden" target="_blank">
|
<Link href="https://fosstodon.org/@linkwarden" target="_blank">
|
||||||
<div
|
<div
|
||||||
className={`hover:bg-slate-500 duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
className={`hover:bg-neutral/20 duration-100 py-2 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faMastodon as any}
|
icon={faMastodon as any}
|
||||||
|
|
|
@ -61,8 +61,8 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/dashboard`
|
active === `/dashboard`
|
||||||
? "bg-primary/20"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
@ -76,7 +76,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<Link href={`/links`}>
|
<Link href={`/links`}>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/links` ? "bg-primary/20" : "hover:bg-slate-500/20"
|
active === `/links` ? "bg-secondary/30" : "hover:bg-neutral/20"
|
||||||
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
@ -91,8 +91,8 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/collections`
|
active === `/collections`
|
||||||
? "bg-primary/20"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
@ -107,8 +107,8 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/links/pinned`
|
active === `/links/pinned`
|
||||||
? "bg-primary/20"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
} duration-100 py-5 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
@ -154,8 +154,8 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/collections/${e.id}`
|
active === `/collections/${e.id}`
|
||||||
? "bg-primary/20"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
@ -222,8 +222,8 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/tags/${e.id}`
|
active === `/tags/${e.id}`
|
||||||
? "bg-primary/20"
|
? "bg-secondary/30"
|
||||||
: "hover:bg-slate-500/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
|
@ -23,7 +23,9 @@ export default function ToggleDarkMode({ className }: Props) {
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label className="swap swap-rotate className">
|
<label
|
||||||
|
className={`swap swap-rotate btn-square text-neutral btn btn-ghost btn-sm ${className}`}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={handleToggle}
|
onChange={handleToggle}
|
||||||
|
@ -32,21 +34,24 @@ export default function ToggleDarkMode({ className }: Props) {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* sun icon */}
|
{/* sun icon */}
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
className="swap-on fill-current w-10 h-10"
|
className="swap-on fill-current w-5 h-5"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 24 24"
|
fill="currentColor"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
>
|
>
|
||||||
<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
|
<path d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0m0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13m8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5M3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8m10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0m-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707M4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
{/* moon icon */}
|
{/* moon icon */}
|
||||||
<svg
|
<svg
|
||||||
className="swap-off fill-current w-10 h-10"
|
className="swap-off fill-current w-5 h-5"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 24 24"
|
fill="currentColor"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
>
|
>
|
||||||
<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
|
<path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278" />
|
||||||
</svg>
|
</svg>
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
|
|
|
@ -53,14 +53,14 @@ export default function SettingsLayout({ children }: Props) {
|
||||||
<div className="gap-2 inline-flex mr-3">
|
<div className="gap-2 inline-flex mr-3">
|
||||||
<div
|
<div
|
||||||
onClick={toggleSidebar}
|
onClick={toggleSidebar}
|
||||||
className="text-neutral btn btn-square btn-ghost"
|
className="text-neutral btn btn-square btn-sm btn-ghost lg:hidden"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faBars} className="w-5 h-5" />
|
<FontAwesomeIcon icon={faBars} className="w-5 h-5" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard"
|
href="/dashboard"
|
||||||
className="text-neutral btn btn-square btn-ghost"
|
className="text-neutral btn btn-square btn-sm btn-ghost"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faChevronLeft} className="w-5 h-5" />
|
<FontAwesomeIcon icon={faChevronLeft} className="w-5 h-5" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -23,7 +23,6 @@ import React from "react";
|
||||||
import useModalStore from "@/store/modals";
|
import useModalStore from "@/store/modals";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { MigrationFormat, MigrationRequest } from "@/types/global";
|
import { MigrationFormat, MigrationRequest } from "@/types/global";
|
||||||
import ClickAwayHandler from "@/components/ClickAwayHandler";
|
|
||||||
import DashboardItem from "@/components/DashboardItem";
|
import DashboardItem from "@/components/DashboardItem";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
|
@ -63,8 +62,6 @@ export default function Dashboard() {
|
||||||
handleNumberOfLinksToShow();
|
handleNumberOfLinksToShow();
|
||||||
}, [width]);
|
}, [width]);
|
||||||
|
|
||||||
const [importDropdown, setImportDropdown] = useState(false);
|
|
||||||
|
|
||||||
const importBookmarks = async (e: any, format: MigrationFormat) => {
|
const importBookmarks = async (e: any, format: MigrationFormat) => {
|
||||||
const file: File = e.target.files[0];
|
const file: File = e.target.files[0];
|
||||||
|
|
||||||
|
@ -92,8 +89,6 @@ export default function Dashboard() {
|
||||||
|
|
||||||
toast.success("Imported the Bookmarks! Reloading the page...");
|
toast.success("Imported the Bookmarks! Reloading the page...");
|
||||||
|
|
||||||
setImportDropdown(false);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
@ -200,51 +195,32 @@ export default function Dashboard() {
|
||||||
method: "CREATE",
|
method: "CREATE",
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className="inline-flex gap-1 relative w-[11.4rem] items-center font-semibold select-none cursor-pointer p-2 px-3 rounded-md dark:hover:bg-sky-600 text-white bg-sky-700 hover:bg-sky-600 duration-100 group"
|
className="inline-flex gap-1 relative w-[11rem] items-center btn btn-accent text-white group"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faPlus}
|
icon={faPlus}
|
||||||
className="w-5 h-5 group-hover:ml-[4.325rem] absolute duration-100"
|
className="w-5 h-5 left-4 group-hover:ml-[4rem] absolute duration-100"
|
||||||
/>
|
/>
|
||||||
<span className="group-hover:opacity-0 text-right w-full duration-100">
|
<span className="group-hover:opacity-0 text-right w-full duration-100">
|
||||||
Create New Link
|
Create New Item
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative">
|
<details className="dropdown">
|
||||||
<div
|
<summary className="flex gap-2 text-sm btn btn-outline group">
|
||||||
onClick={() => setImportDropdown(!importDropdown)}
|
|
||||||
id="import-dropdown"
|
|
||||||
className="flex gap-2 select-none text-sm cursor-pointer p-2 px-3 rounded-md border dark:hover:border-sky-600 text-black border-black dark:text-white dark:border-white hover:border-primary hover:dark:border-primary hover:text-primary duration-100 group"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faFileImport}
|
icon={faFileImport}
|
||||||
className="w-5 h-5 duration-100"
|
className="w-5 h-5 duration-100"
|
||||||
id="import-dropdown"
|
id="import-dropdown"
|
||||||
/>
|
/>
|
||||||
<span
|
<span className="duration-100" id="import-dropdown">
|
||||||
className="text-right w-full duration-100"
|
|
||||||
id="import-dropdown"
|
|
||||||
>
|
|
||||||
Import Your Bookmarks
|
Import Your Bookmarks
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</summary>
|
||||||
{importDropdown ? (
|
<ul className="shadow menu dropdown-content z-[1] bg-base-200 border border-neutral-content rounded-box w-60">
|
||||||
<ClickAwayHandler
|
<li>
|
||||||
onClickOutside={(e: Event) => {
|
<label htmlFor="import-linkwarden-file" title="JSON File">
|
||||||
const target = e.target as HTMLInputElement;
|
From Linkwarden
|
||||||
if (target.id !== "import-dropdown")
|
|
||||||
setImportDropdown(false);
|
|
||||||
}}
|
|
||||||
className={`absolute top-10 left-0 w-52 py-1 shadow-md border border-neutral-content bg-base-200 rounded-md flex flex-col z-20`}
|
|
||||||
>
|
|
||||||
<div className="cursor-pointer rounded-md">
|
|
||||||
<label
|
|
||||||
htmlFor="import-linkwarden-file"
|
|
||||||
title="JSON File"
|
|
||||||
className="flex items-center gap-2 py-1 px-2 hover:bg-base-100 duration-100 cursor-pointer"
|
|
||||||
>
|
|
||||||
Linkwarden File...
|
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
name="photo"
|
name="photo"
|
||||||
|
@ -256,12 +232,14 @@ export default function Dashboard() {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
<label
|
<label
|
||||||
htmlFor="import-html-file"
|
htmlFor="import-html-file"
|
||||||
title="HTML File"
|
title="HTML File"
|
||||||
className="flex items-center gap-2 py-1 px-2 hover:bg-base-100 duration-100 cursor-pointer"
|
className="w-full"
|
||||||
>
|
>
|
||||||
Bookmarks HTML file...
|
From Bookmarks HTML file
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
name="photo"
|
name="photo"
|
||||||
|
@ -273,10 +251,9 @@ export default function Dashboard() {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</li>
|
||||||
</ClickAwayHandler>
|
</ul>
|
||||||
) : null}
|
</details>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -128,7 +128,7 @@ export default function PublicCollections() {
|
||||||
{collection.name}
|
{collection.name}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex gap-2 items-center mt-8 min-w-fit">
|
<div className="flex gap-2 items-center mt-8 min-w-fit">
|
||||||
<ToggleDarkMode className="w-8 h-8 flex" />
|
<ToggleDarkMode />
|
||||||
<Link href="https://linkwarden.app/" target="_blank">
|
<Link href="https://linkwarden.app/" target="_blank">
|
||||||
<Image
|
<Image
|
||||||
src={`/icon.png`}
|
src={`/icon.png`}
|
||||||
|
@ -136,15 +136,46 @@ export default function PublicCollections() {
|
||||||
height={551}
|
height={551}
|
||||||
alt="Linkwarden"
|
alt="Linkwarden"
|
||||||
title="Linkwarden"
|
title="Linkwarden"
|
||||||
className="h-8 w-fit mx-auto"
|
className="h-8 w-fit mx-auto rounded"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div className="mt-3">
|
||||||
<div className={`min-w-[15rem]`}>
|
<div className={`min-w-[15rem]`}>
|
||||||
<div
|
<div className="flex justify-center sm:justify-end items-start w-fit">
|
||||||
|
{collectionOwner.id ? (
|
||||||
|
<ProfilePhoto
|
||||||
|
src={collectionOwner.image || undefined}
|
||||||
|
className="w-7 h-7"
|
||||||
|
/>
|
||||||
|
) : undefined}
|
||||||
|
{collection.members
|
||||||
|
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
||||||
|
.map((e, i) => {
|
||||||
|
return (
|
||||||
|
<ProfilePhoto
|
||||||
|
key={i}
|
||||||
|
src={e.user.image ? e.user.image : undefined}
|
||||||
|
className="w-7 h-7"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.slice(0, 4)}
|
||||||
|
{collection?.members.length &&
|
||||||
|
collection.members.length - 3 > 0 ? (
|
||||||
|
<div className={`avatar placeholder`}>
|
||||||
|
<div className="bg-base-100 text-base-content rounded-full w-8 h-8 ring-2 ring-base-content">
|
||||||
|
<span>+{collection.members.length - 3}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<p className="ml-3 mt-1 text-neutral text-xs">
|
||||||
|
By
|
||||||
|
<span
|
||||||
|
className="btn btn-ghost btn-xs p-1"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setModal({
|
setModal({
|
||||||
modal: "COLLECTION",
|
modal: "COLLECTION",
|
||||||
|
@ -155,41 +186,12 @@ export default function PublicCollections() {
|
||||||
defaultIndex: 0,
|
defaultIndex: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="hover:opacity-80 duration-100 flex justify-center sm:justify-end items-start w-fit cursor-pointer"
|
|
||||||
>
|
>
|
||||||
{collectionOwner.id ? (
|
{collectionOwner.name}
|
||||||
<ProfilePhoto
|
|
||||||
src={
|
|
||||||
collectionOwner.image ? collectionOwner.image : undefined
|
|
||||||
}
|
|
||||||
className={`w-8 h-8 border-2`}
|
|
||||||
/>
|
|
||||||
) : undefined}
|
|
||||||
{collection.members
|
|
||||||
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
|
||||||
.map((e, i) => {
|
|
||||||
return (
|
|
||||||
<ProfilePhoto
|
|
||||||
key={i}
|
|
||||||
src={e.user.image ? e.user.image : undefined}
|
|
||||||
className={`w-8 h-8 border-2`}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.slice(0, 3)}
|
|
||||||
{collection?.members.length &&
|
|
||||||
collection.members.length - 3 > 0 ? (
|
|
||||||
<div className="w-8 h-8 min-w-[2rem] text-white text-sm flex items-center justify-center rounded-full border-2 bg-sky-600 dark:bg-sky-600 border-slate-200">
|
|
||||||
+{collection?.members?.length - 3}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<p className="ml-2 mt-1 text-neutral">
|
|
||||||
By {collectionOwner.name}
|
|
||||||
{collection.members.length > 0
|
{collection.members.length > 0
|
||||||
? ` and ${collection.members.length} others`
|
? ` and ${collection.members.length} others`
|
||||||
: undefined}
|
: undefined}
|
||||||
.
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -155,7 +155,6 @@ body {
|
||||||
|
|
||||||
/* Theme */
|
/* Theme */
|
||||||
|
|
||||||
/* react-select */
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.react-select-container .react-select__control {
|
.react-select-container .react-select__control {
|
||||||
@apply bg-base-200 dark:hover:border-neutral-500 border-red-500 border;
|
@apply bg-base-200 dark:hover:border-neutral-500 border-red-500 border;
|
||||||
|
|
|
@ -7,8 +7,8 @@ module.exports = {
|
||||||
{
|
{
|
||||||
light: {
|
light: {
|
||||||
primary: "#0ea5e9",
|
primary: "#0ea5e9",
|
||||||
secondary: "#22d3ee",
|
secondary: "#06b6d4",
|
||||||
accent: "#4f46e5",
|
accent: "#6366f1",
|
||||||
neutral: "#6b7280",
|
neutral: "#6b7280",
|
||||||
"neutral-content": "#d1d5db",
|
"neutral-content": "#d1d5db",
|
||||||
"base-100": "#ffffff",
|
"base-100": "#ffffff",
|
||||||
|
@ -22,9 +22,9 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dark: {
|
dark: {
|
||||||
primary: "#38bdf8",
|
primary: "#0ea5e9",
|
||||||
secondary: "#0284c7",
|
secondary: "#0e7490",
|
||||||
accent: "#818cf8",
|
accent: "#6366f1",
|
||||||
neutral: "#9ca3af",
|
neutral: "#9ca3af",
|
||||||
"neutral-content": "#404040",
|
"neutral-content": "#404040",
|
||||||
"base-100": "#171717",
|
"base-100": "#171717",
|
||||||
|
|
Ŝarĝante…
Reference in New Issue