more modals replaced
This commit is contained in:
parent
2c9541734a
commit
a3c6d9b42e
|
@ -12,23 +12,17 @@ type Props = {
|
||||||
export default function Checkbox({ label, state, className, onClick }: Props) {
|
export default function Checkbox({ label, state, className, onClick }: Props) {
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
className={`cursor-pointer flex items-center gap-2 ${className || ""}`}
|
className={`label cursor-pointer flex gap-2 justify-start ${
|
||||||
|
className || ""
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={state}
|
checked={state}
|
||||||
onChange={onClick}
|
onChange={onClick}
|
||||||
className="peer sr-only"
|
className="checkbox checkbox-primary"
|
||||||
/>
|
/>
|
||||||
<FontAwesomeIcon
|
<span className="label-text">{label}</span>
|
||||||
icon={faSquareCheck}
|
|
||||||
className="w-5 h-5 text-primary peer-checked:block hidden"
|
|
||||||
/>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={faSquare}
|
|
||||||
className="w-5 h-5 text-primary peer-checked:hidden block"
|
|
||||||
/>
|
|
||||||
<span className="rounded select-none">{label}</span>
|
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import EditCollectionModal from "./Modals/EditCollectionModal";
|
import EditCollectionModal from "./Modals/EditCollectionModal";
|
||||||
import EditCollectionSharingModal from "./Modals/EditCollectionSharingModal";
|
import EditCollectionSharingModal from "./Modals/EditCollectionSharingModal";
|
||||||
|
import DeleteCollectionModal from "./Modals/DeleteCollectionModal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
collection: CollectionIncludingMembersAndLinkCount;
|
collection: CollectionIncludingMembersAndLinkCount;
|
||||||
|
@ -62,6 +63,7 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
const [editCollectionModal, setEditCollectionModal] = useState(false);
|
const [editCollectionModal, setEditCollectionModal] = useState(false);
|
||||||
const [editCollectionSharingModal, setEditCollectionSharingModal] =
|
const [editCollectionSharingModal, setEditCollectionSharingModal] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
const [deleteCollectionModal, setDeleteCollectionModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
@ -109,15 +111,7 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
(document?.activeElement as HTMLElement)?.blur();
|
(document?.activeElement as HTMLElement)?.blur();
|
||||||
collection &&
|
setDeleteCollectionModal(true);
|
||||||
setModal({
|
|
||||||
modal: "COLLECTION",
|
|
||||||
state: true,
|
|
||||||
method: "UPDATE",
|
|
||||||
isOwner: permissions === true,
|
|
||||||
active: collection,
|
|
||||||
defaultIndex: permissions === true ? 2 : 1,
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{permissions === true ? "Delete Collection" : "Leave Collection"}
|
{permissions === true ? "Delete Collection" : "Leave Collection"}
|
||||||
|
@ -132,7 +126,7 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
{collectionOwner.id ? (
|
{collectionOwner.id ? (
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
src={collectionOwner.image || undefined}
|
src={collectionOwner.image || undefined}
|
||||||
className="w-7 h-7"
|
dimensionClass="w-7 h-7"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{collection.members
|
{collection.members
|
||||||
|
@ -212,6 +206,12 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
modalId={"edit-collection-sharing-modal" + collection.id}
|
modalId={"edit-collection-sharing-modal" + collection.id}
|
||||||
activeCollection={collection}
|
activeCollection={collection}
|
||||||
/>
|
/>
|
||||||
|
<DeleteCollectionModal
|
||||||
|
isOpen={deleteCollectionModal}
|
||||||
|
onClose={() => setDeleteCollectionModal(false)}
|
||||||
|
modalId={"delete-collection-modal" + collection.id}
|
||||||
|
activeCollection={collection}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import TextInput from "@/components/TextInput";
|
||||||
|
import useCollectionStore from "@/store/collections";
|
||||||
|
import toast, { Toaster } from "react-hot-toast";
|
||||||
|
import {
|
||||||
|
faFolder,
|
||||||
|
faRightFromBracket,
|
||||||
|
faTrashCan,
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { HexColorPicker } from "react-colorful";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
modalId: string;
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: Function;
|
||||||
|
activeCollection: CollectionIncludingMembersAndLinkCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function DeleteCollectionModal({
|
||||||
|
modalId,
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
activeCollection,
|
||||||
|
}: Props) {
|
||||||
|
const modal = document.getElementById(modalId);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
modal?.addEventListener("close", () => {
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
modal?.addEventListener("close", () => {
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
const [collection, setCollection] =
|
||||||
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCollection(activeCollection);
|
||||||
|
setInputField("");
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
|
const { removeCollection } = useCollectionStore();
|
||||||
|
const router = useRouter();
|
||||||
|
const [inputField, setInputField] = useState("");
|
||||||
|
|
||||||
|
const permissions = usePermissions(collection.id as number);
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
if (permissions === true) if (collection.name !== inputField) return null;
|
||||||
|
|
||||||
|
if (!submitLoader) {
|
||||||
|
setSubmitLoader(true);
|
||||||
|
if (!collection) return null;
|
||||||
|
|
||||||
|
setSubmitLoader(true);
|
||||||
|
|
||||||
|
const load = toast.loading("Deleting...");
|
||||||
|
|
||||||
|
let response;
|
||||||
|
|
||||||
|
response = await removeCollection(collection.id as any);
|
||||||
|
|
||||||
|
toast.dismiss(load);
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
toast.success(`Deleted.`);
|
||||||
|
(document.getElementById(modalId) as any).close();
|
||||||
|
router.push("/collections");
|
||||||
|
} else toast.error(response.data as string);
|
||||||
|
|
||||||
|
setSubmitLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<dialog
|
||||||
|
id={modalId}
|
||||||
|
className="modal backdrop-blur-sm overflow-y-auto"
|
||||||
|
open={isOpen}
|
||||||
|
>
|
||||||
|
<Toaster
|
||||||
|
position="top-center"
|
||||||
|
reverseOrder={false}
|
||||||
|
toastOptions={{
|
||||||
|
className:
|
||||||
|
"border border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 dark:text-white",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="modal-box max-h-full overflow-y-visible border border-neutral-content w-11/12 max-w-2xl">
|
||||||
|
<form method="dialog">
|
||||||
|
<button className="btn btn-sm outline-none btn-circle btn-ghost absolute right-3 top-3">
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p className="text-xl mb-5 font-thin text-red-500">
|
||||||
|
{permissions === true ? "Delete" : "Leave"} Collection
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{permissions === true ? (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<p>
|
||||||
|
To confirm, type "
|
||||||
|
<span className="font-bold">{collection.name}</span>
|
||||||
|
" in the box below:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={inputField}
|
||||||
|
onChange={(e) => setInputField(e.target.value)}
|
||||||
|
placeholder={`Type "${collection.name}" Here.`}
|
||||||
|
className="w-3/4 mx-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div role="alert" className="alert alert-warning">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="stroke-current shrink-0 h-6 w-6"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>
|
||||||
|
<b>
|
||||||
|
Warning: Deleting this collection will permanently erase all
|
||||||
|
its contents
|
||||||
|
</b>
|
||||||
|
, and it will become inaccessible to everyone, including
|
||||||
|
members with previous access.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<p>Click the button below to leave the current collection.</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
disabled={permissions === true && inputField !== collection.name}
|
||||||
|
className={`ml-auto btn w-fit text-white flex items-center gap-2 duration-100 ${
|
||||||
|
permissions === true
|
||||||
|
? inputField === collection.name
|
||||||
|
? "bg-red-500 hover:bg-red-400 hover:dark:bg-red-600 cursor-pointer"
|
||||||
|
: "cursor-not-allowed bg-red-300 dark:bg-red-900"
|
||||||
|
: "bg-red-500 hover:bg-red-400 hover:dark:bg-red-600 cursor-pointer"
|
||||||
|
}`}
|
||||||
|
onClick={submit}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={permissions === true ? faTrashCan : faRightFromBracket}
|
||||||
|
className="h-5"
|
||||||
|
/>
|
||||||
|
{permissions === true ? "Delete" : "Leave"} Collection
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="dialog" className="modal-backdrop">
|
||||||
|
<button>close</button>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import useCollectionStore from "@/store/collections";
|
||||||
import toast, { Toaster } from "react-hot-toast";
|
import toast, { Toaster } from "react-hot-toast";
|
||||||
import { faFolder } from "@fortawesome/free-solid-svg-icons";
|
import { faFolder } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { HexColorPicker } from "react-colorful";
|
import { HexColorPicker } from "react-colorful";
|
||||||
import { Collection } from "@prisma/client";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,8 @@ import toast, { Toaster } from "react-hot-toast";
|
||||||
import {
|
import {
|
||||||
faClose,
|
faClose,
|
||||||
faCrown,
|
faCrown,
|
||||||
faFolder,
|
|
||||||
faUserPlus,
|
faUserPlus,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { HexColorPicker } from "react-colorful";
|
|
||||||
import { Collection } from "@prisma/client";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { CollectionIncludingMembersAndLinkCount, Member } from "@/types/global";
|
import { CollectionIncludingMembersAndLinkCount, Member } from "@/types/global";
|
||||||
import getPublicUserData from "@/lib/client/getPublicUserData";
|
import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
|
|
|
@ -110,7 +110,6 @@ export default function Navbar() {
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
src={account.image ? account.image : undefined}
|
src={account.image ? account.image : undefined}
|
||||||
priority={true}
|
priority={true}
|
||||||
className=""
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ul className="dropdown-content z-[1] menu p-1 shadow bg-base-200 border border-neutral-content rounded-xl w-40 mt-1">
|
<ul className="dropdown-content z-[1] menu p-1 shadow bg-base-200 border border-neutral-content rounded-xl w-40 mt-1">
|
||||||
|
|
|
@ -8,6 +8,7 @@ type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
priority?: boolean;
|
priority?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
dimensionClass?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ProfilePhoto({
|
export default function ProfilePhoto({
|
||||||
|
@ -15,6 +16,7 @@ export default function ProfilePhoto({
|
||||||
className,
|
className,
|
||||||
priority,
|
priority,
|
||||||
name,
|
name,
|
||||||
|
dimensionClass,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [image, setImage] = useState("");
|
const [image, setImage] = useState("");
|
||||||
|
|
||||||
|
@ -28,7 +30,11 @@ export default function ProfilePhoto({
|
||||||
}, [src]);
|
}, [src]);
|
||||||
|
|
||||||
return !image ? (
|
return !image ? (
|
||||||
<div className={`avatar w-8 h-8 placeholder ${className || ""}`}>
|
<div
|
||||||
|
className={`avatar placeholder ${className || ""} ${
|
||||||
|
dimensionClass || "w-8 h-8 "
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<div className="bg-base-100 text-neutral rounded-full w-full h-full ring-2 ring-neutral-content">
|
<div className="bg-base-100 text-neutral rounded-full w-full h-full ring-2 ring-neutral-content">
|
||||||
{name ? (
|
{name ? (
|
||||||
<span className="text-2xl capitalize">{name.slice(0, 1)}</span>
|
<span className="text-2xl capitalize">{name.slice(0, 1)}</span>
|
||||||
|
@ -41,7 +47,11 @@ export default function ProfilePhoto({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={`avatar w-8 h-8 drop-shadow-md ${className || ""}`}>
|
<div
|
||||||
|
className={`avatar drop-shadow-md ${className || ""} ${
|
||||||
|
dimensionClass || "w-8 h-8 "
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<div className="rounded-full w-full h-full ring-2 ring-neutral-content">
|
<div className="rounded-full w-full h-full ring-2 ring-neutral-content">
|
||||||
<Image
|
<Image
|
||||||
alt=""
|
alt=""
|
||||||
|
|
|
@ -112,10 +112,7 @@ export default function Index() {
|
||||||
onClick={() => setEditCollectionSharingModal(true)}
|
onClick={() => setEditCollectionSharingModal(true)}
|
||||||
>
|
>
|
||||||
{collectionOwner.id ? (
|
{collectionOwner.id ? (
|
||||||
<ProfilePhoto
|
<ProfilePhoto src={collectionOwner.image || undefined} />
|
||||||
src={collectionOwner.image || undefined}
|
|
||||||
className="w-7 h-7"
|
|
||||||
/>
|
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{activeCollection.members
|
{activeCollection.members
|
||||||
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
||||||
|
|
|
@ -153,7 +153,7 @@ export default function PublicCollections() {
|
||||||
{collectionOwner.id ? (
|
{collectionOwner.id ? (
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
src={collectionOwner.image || undefined}
|
src={collectionOwner.image || undefined}
|
||||||
className="w-7 h-7"
|
dimensionClass="w-7 h-7"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{collection.members
|
{collection.members
|
||||||
|
|
|
@ -162,6 +162,7 @@ export default function Account() {
|
||||||
<p className="mb-2">Display Name</p>
|
<p className="mb-2">Display Name</p>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={user.name || ""}
|
value={user.name || ""}
|
||||||
|
className="bg-base-200"
|
||||||
onChange={(e) => setUser({ ...user, name: e.target.value })}
|
onChange={(e) => setUser({ ...user, name: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,6 +170,7 @@ export default function Account() {
|
||||||
<p className="mb-2">Username</p>
|
<p className="mb-2">Username</p>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={user.username || ""}
|
value={user.username || ""}
|
||||||
|
className="bg-base-200"
|
||||||
onChange={(e) => setUser({ ...user, username: e.target.value })}
|
onChange={(e) => setUser({ ...user, username: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -184,6 +186,7 @@ export default function Account() {
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<TextInput
|
<TextInput
|
||||||
value={user.email || ""}
|
value={user.email || ""}
|
||||||
|
className="bg-base-200"
|
||||||
onChange={(e) => setUser({ ...user, email: e.target.value })}
|
onChange={(e) => setUser({ ...user, email: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -196,7 +199,7 @@ export default function Account() {
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
priority={true}
|
priority={true}
|
||||||
src={user.image ? user.image : undefined}
|
src={user.image ? user.image : undefined}
|
||||||
className="h-auto border-none w-28"
|
dimensionClass="w-28 h-28"
|
||||||
/>
|
/>
|
||||||
{user.image && (
|
{user.image && (
|
||||||
<div
|
<div
|
||||||
|
@ -206,13 +209,13 @@ export default function Account() {
|
||||||
image: "",
|
image: "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
className="absolute top-1 left-1 w-5 h-5 flex items-center justify-center border p-1 border-slate-200 rounded-full bg-base-200 text-center select-none cursor-pointer duration-100 hover:text-red-500"
|
className="absolute top-1 left-1 btn btn-xs btn-circle btn-neutral btn-outline bg-base-100"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faClose} className="w-3 h-3" />
|
<FontAwesomeIcon icon={faClose} className="w-3 h-3" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="absolute -bottom-3 left-0 right-0 mx-auto w-fit text-center">
|
<div className="absolute -bottom-3 left-0 right-0 mx-auto w-fit text-center">
|
||||||
<label className="border border-slate-200 rounded-md bg-base-200 px-2 text-center select-none cursor-pointer duration-100 hover:border-primary">
|
<label className="btn btn-xs btn-secondary btn-outline bg-base-100">
|
||||||
Browse...
|
Browse...
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
@ -240,71 +243,60 @@ export default function Account() {
|
||||||
<div className="flex gap-3 flex-col">
|
<div className="flex gap-3 flex-col">
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-2">Import your data from other platforms.</p>
|
<p className="mb-2">Import your data from other platforms.</p>
|
||||||
<div
|
<details className="dropdown">
|
||||||
onClick={() => setImportDropdown(true)}
|
<summary
|
||||||
className="w-fit relative"
|
className="flex gap-2 text-sm btn btn-outline btn-secondary btn-xs"
|
||||||
id="import-dropdown"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
id="import-dropdown"
|
id="import-dropdown"
|
||||||
className="border border-slate-200 rounded-md bg-base-200 px-2 text-center select-none cursor-pointer duration-100 hover:border-primary"
|
|
||||||
>
|
>
|
||||||
Import From
|
Import From
|
||||||
</div>
|
</summary>
|
||||||
{importDropdown ? (
|
<ul className="shadow menu dropdown-content z-[1] p-1 bg-base-200 border border-neutral-content rounded-xl mt-1 w-60">
|
||||||
<ClickAwayHandler
|
<li>
|
||||||
onClickOutside={(e: Event) => {
|
<label
|
||||||
const target = e.target as HTMLInputElement;
|
className="px-2 py-1 rounded-lg"
|
||||||
if (target.id !== "import-dropdown")
|
htmlFor="import-linkwarden-file"
|
||||||
setImportDropdown(false);
|
title="JSON File"
|
||||||
}}
|
>
|
||||||
className={`absolute top-7 left-0 w-52 py-1 shadow-md border border-neutral-content bg-base-200 rounded-md flex flex-col z-20`}
|
From Linkwarden
|
||||||
>
|
<input
|
||||||
<div className="cursor-pointer rounded-md">
|
type="file"
|
||||||
<label
|
name="photo"
|
||||||
htmlFor="import-linkwarden-file"
|
id="import-linkwarden-file"
|
||||||
title="JSON File"
|
accept=".json"
|
||||||
className="flex items-center gap-2 py-1 px-2 hover:bg-neutral-content duration-100 cursor-pointer"
|
className="hidden"
|
||||||
>
|
onChange={(e) =>
|
||||||
Linkwarden File...
|
importBookmarks(e, MigrationFormat.linkwarden)
|
||||||
<input
|
}
|
||||||
type="file"
|
/>
|
||||||
name="photo"
|
</label>
|
||||||
id="import-linkwarden-file"
|
</li>
|
||||||
accept=".json"
|
<li>
|
||||||
className="hidden"
|
<label
|
||||||
onChange={(e) =>
|
className="px-2 py-1 rounded-lg"
|
||||||
importBookmarks(e, MigrationFormat.linkwarden)
|
htmlFor="import-html-file"
|
||||||
}
|
title="HTML File"
|
||||||
/>
|
>
|
||||||
</label>
|
From Bookmarks HTML file
|
||||||
<label
|
<input
|
||||||
htmlFor="import-html-file"
|
type="file"
|
||||||
title="HTML File"
|
name="photo"
|
||||||
className="flex items-center gap-2 py-1 px-2 hover:bg-neutral-content duration-100 cursor-pointer"
|
id="import-html-file"
|
||||||
>
|
accept=".html"
|
||||||
Bookmarks HTML file...
|
className="hidden"
|
||||||
<input
|
onChange={(e) =>
|
||||||
type="file"
|
importBookmarks(e, MigrationFormat.htmlFile)
|
||||||
name="photo"
|
}
|
||||||
id="import-html-file"
|
/>
|
||||||
accept=".html"
|
</label>
|
||||||
className="hidden"
|
</li>
|
||||||
onChange={(e) =>
|
</ul>
|
||||||
importBookmarks(e, MigrationFormat.htmlFile)
|
</details>
|
||||||
}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</ClickAwayHandler>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-2">Download your data instantly.</p>
|
<p className="mb-2">Download your data instantly.</p>
|
||||||
<Link className="w-fit" href="/api/v1/migration">
|
<Link className="w-fit" href="/api/v1/migration">
|
||||||
<div className="border w-fit border-slate-200 rounded-md bg-base-200 px-2 text-center select-none cursor-pointer duration-100 hover:border-primary">
|
<div className="btn btn-outline btn-secondary btn-xs">
|
||||||
Export Data
|
Export Data
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -339,7 +331,7 @@ export default function Account() {
|
||||||
visibility to your profile. Separated by comma.
|
visibility to your profile. Separated by comma.
|
||||||
</p>
|
</p>
|
||||||
<textarea
|
<textarea
|
||||||
className="w-full resize-none border rounded-md duration-100 bg-base-200 p-2 outline-none border-neutral-content focus:border-sky-300 dark:focus:border-sky-600"
|
className="w-full resize-none border rounded-md duration-100 bg-base-200 p-2 outline-none border-neutral-content focus:border-primary"
|
||||||
placeholder="Your profile is hidden from everyone right now..."
|
placeholder="Your profile is hidden from everyone right now..."
|
||||||
value={whitelistedUsersTextbox}
|
value={whitelistedUsersTextbox}
|
||||||
onChange={(e) => setWhiteListedUsersTextbox(e.target.value)}
|
onChange={(e) => setWhiteListedUsersTextbox(e.target.value)}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default function Api() {
|
||||||
<div className="divider my-3"></div>
|
<div className="divider my-3"></div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<div className="badge bg-orange-500 rounded-md border border-black w-fit px-2 text-black">
|
<div className="badge badge-warning rounded-md w-fit p-4">
|
||||||
Status: Under Development
|
Status: Under Development
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,9 @@ import SettingsLayout from "@/layouts/SettingsLayout";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faSun, faMoon } from "@fortawesome/free-solid-svg-icons";
|
import { faSun, faMoon } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { faClose } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import { AccountSettings } from "@/types/global";
|
import { AccountSettings } from "@/types/global";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import TextInput from "@/components/TextInput";
|
|
||||||
import { resizeImage } from "@/lib/client/resizeImage";
|
|
||||||
import ProfilePhoto from "@/components/ProfilePhoto";
|
|
||||||
import SubmitButton from "@/components/SubmitButton";
|
import SubmitButton from "@/components/SubmitButton";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Checkbox from "@/components/Checkbox";
|
import Checkbox from "@/components/Checkbox";
|
||||||
|
@ -16,7 +12,7 @@ import LinkPreview from "@/components/LinkPreview";
|
||||||
import useLocalSettingsStore from "@/store/localSettings";
|
import useLocalSettingsStore from "@/store/localSettings";
|
||||||
|
|
||||||
export default function Appearance() {
|
export default function Appearance() {
|
||||||
const { settings, updateSettings } = useLocalSettingsStore();
|
const { updateSettings } = useLocalSettingsStore();
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ export default function Password() {
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
value={newPassword}
|
value={newPassword}
|
||||||
|
className="bg-base-200"
|
||||||
onChange={(e) => setNewPassword1(e.target.value)}
|
onChange={(e) => setNewPassword1(e.target.value)}
|
||||||
placeholder="••••••••••••••"
|
placeholder="••••••••••••••"
|
||||||
type="password"
|
type="password"
|
||||||
|
@ -67,6 +68,7 @@ export default function Password() {
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
value={newPassword2}
|
value={newPassword2}
|
||||||
|
className="bg-base-200"
|
||||||
onChange={(e) => setNewPassword2(e.target.value)}
|
onChange={(e) => setNewPassword2(e.target.value)}
|
||||||
placeholder="••••••••••••••"
|
placeholder="••••••••••••••"
|
||||||
type="password"
|
type="password"
|
||||||
|
|
Ŝarĝante…
Reference in New Issue