many bug fixes + add links and collections together + more changes
This commit is contained in:
parent
a3c6d9b42e
commit
a36769c521
|
@ -5,7 +5,6 @@ import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, 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 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 getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
|
@ -20,7 +19,6 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CollectionCard({ collection, className }: Props) {
|
export default function CollectionCard({ collection, className }: Props) {
|
||||||
const { setModal } = useModalStore();
|
|
||||||
const { settings } = useLocalSettingsStore();
|
const { settings } = useLocalSettingsStore();
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
|
|
|
@ -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-secondary/30 rounded-xl select-none">
|
<div className="p-4 bg-primary/20 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">
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import useCollectionStore from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Select from "react-select";
|
|
||||||
import { styles } from "./styles";
|
import { styles } from "./styles";
|
||||||
import { Options } from "./types";
|
import { Options } from "./types";
|
||||||
|
import CreatableSelect from "react-select/creatable";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onChange: any;
|
onChange: any;
|
||||||
|
@ -13,9 +13,14 @@ type Props = {
|
||||||
value?: number;
|
value?: number;
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CollectionSelection({ onChange, defaultValue }: Props) {
|
export default function CollectionSelection({
|
||||||
|
onChange,
|
||||||
|
defaultValue,
|
||||||
|
id,
|
||||||
|
}: Props) {
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
@ -43,7 +48,8 @@ export default function CollectionSelection({ onChange, defaultValue }: Props) {
|
||||||
}, [collections]);
|
}, [collections]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<CreatableSelect
|
||||||
|
key={id || "key"}
|
||||||
isClearable={false}
|
isClearable={false}
|
||||||
className="react-select-container"
|
className="react-select-container"
|
||||||
classNamePrefix="react-select"
|
classNamePrefix="react-select"
|
||||||
|
|
|
@ -10,11 +10,9 @@ import {
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Dropdown from "./Dropdown";
|
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import useCollectionStore from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import useModalStore from "@/store/modals";
|
|
||||||
import { faCalendarDays } from "@fortawesome/free-regular-svg-icons";
|
import { faCalendarDays } from "@fortawesome/free-regular-svg-icons";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
@ -30,22 +28,11 @@ type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DropdownTrigger =
|
|
||||||
| {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
| false;
|
|
||||||
|
|
||||||
export default function LinkCard({ link, count, className }: Props) {
|
export default function LinkCard({ link, count, className }: Props) {
|
||||||
const { setModal } = useModalStore();
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const permissions = usePermissions(link.collection.id as number);
|
const permissions = usePermissions(link.collection.id as number);
|
||||||
|
|
||||||
const [expandDropdown, setExpandDropdown] = useState<DropdownTrigger>(false);
|
|
||||||
|
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
|
|
||||||
const { links } = useLinkStore();
|
const { links } = useLinkStore();
|
||||||
|
@ -82,8 +69,6 @@ export default function LinkCard({ link, count, className }: Props) {
|
||||||
|
|
||||||
const load = toast.loading("Applying...");
|
const load = toast.loading("Applying...");
|
||||||
|
|
||||||
setExpandDropdown(false);
|
|
||||||
|
|
||||||
const response = await updateLink({
|
const response = await updateLink({
|
||||||
...link,
|
...link,
|
||||||
pinnedBy: isAlreadyPinned ? undefined : [{ id: account.id }],
|
pinnedBy: isAlreadyPinned ? undefined : [{ id: account.id }],
|
||||||
|
@ -98,8 +83,6 @@ export default function LinkCard({ link, count, className }: Props) {
|
||||||
const updateArchive = async () => {
|
const updateArchive = async () => {
|
||||||
const load = toast.loading("Sending request...");
|
const load = toast.loading("Sending request...");
|
||||||
|
|
||||||
setExpandDropdown(false);
|
|
||||||
|
|
||||||
const response = await fetch(`/api/v1/links/${link.id}/archive`, {
|
const response = await fetch(`/api/v1/links/${link.id}/archive`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
});
|
});
|
||||||
|
@ -122,7 +105,6 @@ export default function LinkCard({ link, count, className }: Props) {
|
||||||
toast.dismiss(load);
|
toast.dismiss(load);
|
||||||
|
|
||||||
response.ok && toast.success(`Link Deleted.`);
|
response.ok && toast.success(`Link Deleted.`);
|
||||||
setExpandDropdown(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const url = isValidUrl(link.url) ? new URL(link.url) : undefined;
|
const url = isValidUrl(link.url) ? new URL(link.url) : undefined;
|
||||||
|
|
|
@ -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-secondary p-2 rounded-l-md">
|
<div className="text-white bg-primary 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-secondary p-2 rounded-l-md">
|
<div className="text-white bg-primary p-2 rounded-l-md">
|
||||||
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" />
|
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,15 @@ export default function DeleteCollectionModal({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const modal = document.getElementById(modalId);
|
const modal = document.getElementById(modalId);
|
||||||
|
|
||||||
|
const [collection, setCollection] =
|
||||||
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
modal?.scrollTo(0, 0);
|
||||||
|
|
||||||
|
setCollection(activeCollection);
|
||||||
|
setInputField("");
|
||||||
|
|
||||||
modal?.addEventListener("close", () => {
|
modal?.addEventListener("close", () => {
|
||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
|
@ -40,14 +48,6 @@ export default function DeleteCollectionModal({
|
||||||
};
|
};
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
const [collection, setCollection] =
|
|
||||||
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCollection(activeCollection);
|
|
||||||
setInputField("");
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { removeCollection } = useCollectionStore();
|
const { removeCollection } = useCollectionStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -85,7 +85,7 @@ export default function DeleteCollectionModal({
|
||||||
return (
|
return (
|
||||||
<dialog
|
<dialog
|
||||||
id={modalId}
|
id={modalId}
|
||||||
className="modal backdrop-blur-sm overflow-y-auto"
|
className="modal backdrop-blur-sm overflow-y-auto p-5"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|
|
@ -23,6 +23,9 @@ export default function EditCollectionModal({
|
||||||
const modal = document.getElementById(modalId);
|
const modal = document.getElementById(modalId);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
modal?.scrollTo(0, 0);
|
||||||
|
setCollection(activeCollection);
|
||||||
|
|
||||||
modal?.addEventListener("close", () => {
|
modal?.addEventListener("close", () => {
|
||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
|
@ -37,10 +40,6 @@ export default function EditCollectionModal({
|
||||||
const [collection, setCollection] =
|
const [collection, setCollection] =
|
||||||
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCollection(activeCollection);
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { updateCollection } = useCollectionStore();
|
const { updateCollection } = useCollectionStore();
|
||||||
|
|
||||||
|
@ -71,7 +70,7 @@ export default function EditCollectionModal({
|
||||||
return (
|
return (
|
||||||
<dialog
|
<dialog
|
||||||
id={modalId}
|
id={modalId}
|
||||||
className="modal backdrop-blur-sm overflow-y-auto"
|
className="modal backdrop-blur-sm overflow-y-auto p-5"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|
|
@ -31,6 +31,16 @@ export default function EditCollectionSharingModal({
|
||||||
const modal = document.getElementById(modalId);
|
const modal = document.getElementById(modalId);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const fetchOwner = async () => {
|
||||||
|
const owner = await getPublicUserData(collection.ownerId as number);
|
||||||
|
setCollectionOwner(owner);
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchOwner();
|
||||||
|
|
||||||
|
modal?.scrollTo(0, 0);
|
||||||
|
setCollection(activeCollection);
|
||||||
|
|
||||||
modal?.addEventListener("close", () => {
|
modal?.addEventListener("close", () => {
|
||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
|
@ -45,10 +55,6 @@ export default function EditCollectionSharingModal({
|
||||||
const [collection, setCollection] =
|
const [collection, setCollection] =
|
||||||
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCollection(activeCollection);
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { updateCollection } = useCollectionStore();
|
const { updateCollection } = useCollectionStore();
|
||||||
|
|
||||||
|
@ -92,15 +98,6 @@ export default function EditCollectionSharingModal({
|
||||||
image: "",
|
image: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchOwner = async () => {
|
|
||||||
const owner = await getPublicUserData(collection.ownerId as number);
|
|
||||||
setCollectionOwner(owner);
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchOwner();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setMemberState = (newMember: Member) => {
|
const setMemberState = (newMember: Member) => {
|
||||||
if (!collection) return null;
|
if (!collection) return null;
|
||||||
|
|
||||||
|
@ -115,7 +112,7 @@ export default function EditCollectionSharingModal({
|
||||||
return (
|
return (
|
||||||
<dialog
|
<dialog
|
||||||
id={modalId}
|
id={modalId}
|
||||||
className="modal backdrop-blur-sm overflow-y-auto"
|
className="modal backdrop-blur-sm overflow-y-auto p-5"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|
|
@ -58,6 +58,8 @@ export default function EditLinkModal({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
modal?.scrollTo(0, 0);
|
||||||
|
|
||||||
setLink(activeLink);
|
setLink(activeLink);
|
||||||
|
|
||||||
modal?.addEventListener("close", () => {
|
modal?.addEventListener("close", () => {
|
||||||
|
@ -97,7 +99,7 @@ export default function EditLinkModal({
|
||||||
return (
|
return (
|
||||||
<dialog
|
<dialog
|
||||||
id={modalId}
|
id={modalId}
|
||||||
className="modal backdrop-blur-sm overflow-y-auto"
|
className="modal backdrop-blur-sm overflow-y-auto p-5"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|
|
@ -20,18 +20,6 @@ export default function NewCollectionModal({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const modal = document.getElementById(modalId);
|
const modal = document.getElementById(modalId);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
modal?.addEventListener("close", () => {
|
|
||||||
onClose();
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
modal?.addEventListener("close", () => {
|
|
||||||
onClose();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const initial = {
|
const initial = {
|
||||||
name: "",
|
name: "",
|
||||||
description: "",
|
description: "",
|
||||||
|
@ -41,7 +29,19 @@ export default function NewCollectionModal({
|
||||||
const [collection, setCollection] = useState<Partial<Collection>>(initial);
|
const [collection, setCollection] = useState<Partial<Collection>>(initial);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
modal?.scrollTo(0, 0);
|
||||||
|
|
||||||
|
modal?.addEventListener("close", () => {
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
|
|
||||||
setCollection(initial);
|
setCollection(initial);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
modal?.addEventListener("close", () => {
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
|
};
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
|
@ -74,7 +74,7 @@ export default function NewCollectionModal({
|
||||||
return (
|
return (
|
||||||
<dialog
|
<dialog
|
||||||
id={modalId}
|
id={modalId}
|
||||||
className="modal backdrop-blur-sm overflow-y-auto"
|
className="modal backdrop-blur-sm overflow-y-auto p-5"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|
|
@ -43,6 +43,8 @@ export default function NewLinkModal({ modalId, isOpen, onClose }: Props) {
|
||||||
const { addLink } = useLinkStore();
|
const { addLink } = useLinkStore();
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
|
|
||||||
|
const [resetCollectionSelection, setResetCollectionSelection] = useState("");
|
||||||
|
|
||||||
const [optionsExpanded, setOptionsExpanded] = useState(false);
|
const [optionsExpanded, setOptionsExpanded] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -66,6 +68,10 @@ export default function NewLinkModal({ modalId, isOpen, onClose }: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setResetCollectionSelection(Date.now().toString());
|
||||||
|
console.log(link);
|
||||||
|
|
||||||
|
modal?.scrollTo(0, 0);
|
||||||
setOptionsExpanded(false);
|
setOptionsExpanded(false);
|
||||||
if (router.query.id) {
|
if (router.query.id) {
|
||||||
const currentCollection = collections.find(
|
const currentCollection = collections.find(
|
||||||
|
@ -89,7 +95,6 @@ export default function NewLinkModal({ modalId, isOpen, onClose }: Props) {
|
||||||
setLink({
|
setLink({
|
||||||
...initial,
|
...initial,
|
||||||
collection: {
|
collection: {
|
||||||
// id: ,
|
|
||||||
name: "Unorganized",
|
name: "Unorganized",
|
||||||
ownerId: data?.user.id as number,
|
ownerId: data?.user.id as number,
|
||||||
},
|
},
|
||||||
|
@ -120,7 +125,7 @@ export default function NewLinkModal({ modalId, isOpen, onClose }: Props) {
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
toast.success(`Created!`);
|
toast.success(`Created!`);
|
||||||
(document.getElementById(modalId) as any).close();
|
(document?.getElementById(modalId) as any)?.close();
|
||||||
} else toast.error(response.data as string);
|
} else toast.error(response.data as string);
|
||||||
|
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
|
@ -132,7 +137,7 @@ export default function NewLinkModal({ modalId, isOpen, onClose }: Props) {
|
||||||
return (
|
return (
|
||||||
<dialog
|
<dialog
|
||||||
id={modalId}
|
id={modalId}
|
||||||
className="modal backdrop-blur-sm overflow-y-auto"
|
className="modal backdrop-blur-sm overflow-y-auto p-5"
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
>
|
>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
@ -166,21 +171,11 @@ export default function NewLinkModal({ modalId, isOpen, onClose }: Props) {
|
||||||
{link.collection.name ? (
|
{link.collection.name ? (
|
||||||
<CollectionSelection
|
<CollectionSelection
|
||||||
onChange={setCollection}
|
onChange={setCollection}
|
||||||
// defaultValue={{
|
defaultValue={{
|
||||||
// label: link.collection.name,
|
|
||||||
// value: link.collection.id,
|
|
||||||
// }}
|
|
||||||
defaultValue={
|
|
||||||
link.collection.id
|
|
||||||
? {
|
|
||||||
value: link.collection.id,
|
|
||||||
label: link.collection.name,
|
label: link.collection.name,
|
||||||
}
|
value: link.collection.id,
|
||||||
: {
|
}}
|
||||||
value: null as unknown as number,
|
id={resetCollectionSelection}
|
||||||
label: "Unorganized",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -165,12 +165,12 @@ export default function Navbar() {
|
||||||
<NewLinkModal
|
<NewLinkModal
|
||||||
isOpen={newLinkModal}
|
isOpen={newLinkModal}
|
||||||
onClose={() => setNewLinkModal(false)}
|
onClose={() => setNewLinkModal(false)}
|
||||||
modalId="new-link-modal"
|
modalId="new-link-modal-nav"
|
||||||
/>
|
/>
|
||||||
<NewCollectionModal
|
<NewCollectionModal
|
||||||
isOpen={newCollectionModal}
|
isOpen={newCollectionModal}
|
||||||
onClose={() => setNewCollectionModal(false)}
|
onClose={() => setNewCollectionModal(false)}
|
||||||
modalId="new-collection-modal"
|
modalId="new-collection-modal-nav"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import useModalStore from "@/store/modals";
|
import NewLinkModal from "./Modals/NewLinkModal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
text?: string;
|
text?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function NoLinksFound({ text }: Props) {
|
export default function NoLinksFound({ text }: Props) {
|
||||||
const { setModal } = useModalStore();
|
const [newLinkModal, setNewLinkModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border border-solid border-neutral-content w-full h-full flex flex-col justify-center p-10 rounded-2xl bg-base-200">
|
<div className="border border-solid border-neutral-content w-full h-full flex flex-col justify-center p-10 rounded-2xl bg-base-200">
|
||||||
|
@ -18,23 +18,24 @@ export default function NoLinksFound({ text }: Props) {
|
||||||
<div className="text-center w-full mt-4">
|
<div className="text-center w-full mt-4">
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setModal({
|
setNewLinkModal(true);
|
||||||
modal: "LINK",
|
|
||||||
state: true,
|
|
||||||
method: "CREATE",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
className="inline-flex gap-1 relative w-[11.4rem] items-center font-semibold select-none cursor-pointer p-2 px-3 rounded-full 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 Link
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<NewLinkModal
|
||||||
|
isOpen={newLinkModal}
|
||||||
|
onClose={() => setNewLinkModal(false)}
|
||||||
|
modalId="new-link-modal"
|
||||||
|
/>
|
||||||
</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-secondary text-white text-xs rounded-md cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]"
|
className="btn btn-xs btn-outline truncate max-w-[19rem]"
|
||||||
>
|
>
|
||||||
{e.name}
|
{e.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
|
import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
|
||||||
|
@ -11,11 +11,13 @@ type Props = {
|
||||||
export default function SearchBar({ placeholder }: Props) {
|
export default function SearchBar({ placeholder }: Props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const routeQuery = router.query.q;
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState(
|
useEffect(() => {
|
||||||
routeQuery ? decodeURIComponent(routeQuery as string) : ""
|
router.query.q
|
||||||
);
|
? setSearchQuery(decodeURIComponent(router.query.q as string))
|
||||||
|
: setSearchQuery("");
|
||||||
|
}, [router.query.q]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center relative group">
|
<div className="flex items-center relative group">
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/account`
|
active === `/settings/account`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 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`}
|
||||||
>
|
>
|
||||||
|
@ -58,7 +58,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/appearance`
|
active === `/settings/appearance`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 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`}
|
||||||
>
|
>
|
||||||
|
@ -75,7 +75,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/archive`
|
active === `/settings/archive`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 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`}
|
||||||
>
|
>
|
||||||
|
@ -92,7 +92,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/api`
|
active === `/settings/api`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 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`}
|
||||||
>
|
>
|
||||||
|
@ -106,7 +106,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/password`
|
active === `/settings/password`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 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`}
|
||||||
>
|
>
|
||||||
|
@ -121,7 +121,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/settings/billing`
|
active === `/settings/billing`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/20"
|
: "hover:bg-neutral/20"
|
||||||
} duration-100 py-2 px-2 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`}
|
||||||
>
|
>
|
||||||
|
|
|
@ -60,9 +60,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<Link href={`/dashboard`}>
|
<Link href={`/dashboard`}>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/dashboard`
|
active === `/dashboard` ? "bg-primary/20" : "hover:bg-neutral/20"
|
||||||
? "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
|
||||||
|
@ -76,7 +74,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<Link href={`/links`}>
|
<Link href={`/links`}>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/links` ? "bg-secondary/30" : "hover:bg-neutral/20"
|
active === `/links` ? "bg-primary/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
|
||||||
|
@ -91,7 +89,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/collections`
|
active === `/collections`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/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`}
|
||||||
>
|
>
|
||||||
|
@ -107,7 +105,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/links/pinned`
|
active === `/links/pinned`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/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`}
|
||||||
>
|
>
|
||||||
|
@ -154,7 +152,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/collections/${e.id}`
|
active === `/collections/${e.id}`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/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`}
|
||||||
>
|
>
|
||||||
|
@ -222,7 +220,7 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
active === `/tags/${e.id}`
|
active === `/tags/${e.id}`
|
||||||
? "bg-secondary/30"
|
? "bg-primary/20"
|
||||||
: "hover:bg-neutral/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`}
|
||||||
>
|
>
|
||||||
|
|
|
@ -21,17 +21,15 @@ export default function SubmitButton({
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type={type ? type : undefined}
|
type={type ? type : undefined}
|
||||||
className={`text-white flex items-center gap-2 py-2 px-5 rounded-md text-lg tracking-wide select-none font-semibold duration-100 w-fit ${
|
className={`btn btn-primary text-white tracking-wider w-fit flex items-center gap-2 ${
|
||||||
loading
|
className || ""
|
||||||
? "bg-sky-600 cursor-auto"
|
}`}
|
||||||
: "bg-sky-700 hover:bg-sky-600 cursor-pointer"
|
|
||||||
} ${className || ""}`}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!loading && onClick) onClick();
|
if (!loading && onClick) onClick();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{icon && <FontAwesomeIcon icon={icon} className="h-5" />}
|
{icon && <FontAwesomeIcon icon={icon} className="h-5" />}
|
||||||
<p className="text-center w-full">{label}</p>
|
<p>{label}</p>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { useEffect, useState } from "react";
|
||||||
import MainLayout from "@/layouts/MainLayout";
|
import MainLayout from "@/layouts/MainLayout";
|
||||||
import ProfilePhoto from "@/components/ProfilePhoto";
|
import ProfilePhoto from "@/components/ProfilePhoto";
|
||||||
import SortDropdown from "@/components/SortDropdown";
|
import SortDropdown from "@/components/SortDropdown";
|
||||||
import useModalStore from "@/store/modals";
|
|
||||||
import useLinks from "@/hooks/useLinks";
|
import useLinks from "@/hooks/useLinks";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
import NoLinksFound from "@/components/NoLinksFound";
|
import NoLinksFound from "@/components/NoLinksFound";
|
||||||
|
@ -18,10 +17,9 @@ import useAccountStore from "@/store/account";
|
||||||
import getPublicUserData from "@/lib/client/getPublicUserData";
|
import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
import EditCollectionModal from "@/components/Modals/EditCollectionModal";
|
import EditCollectionModal from "@/components/Modals/EditCollectionModal";
|
||||||
import EditCollectionSharingModal from "@/components/Modals/EditCollectionSharingModal";
|
import EditCollectionSharingModal from "@/components/Modals/EditCollectionSharingModal";
|
||||||
|
import DeleteCollectionModal from "@/components/Modals/DeleteCollectionModal";
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
const { setModal } = useModalStore();
|
|
||||||
|
|
||||||
const { settings } = useLocalSettingsStore();
|
const { settings } = useLocalSettingsStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -76,6 +74,7 @@ export default function Index() {
|
||||||
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 (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
|
@ -206,15 +205,7 @@ export default function Index() {
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
(document?.activeElement as HTMLElement)?.blur();
|
(document?.activeElement as HTMLElement)?.blur();
|
||||||
activeCollection &&
|
setDeleteCollectionModal(true);
|
||||||
setModal({
|
|
||||||
modal: "COLLECTION",
|
|
||||||
state: true,
|
|
||||||
method: "UPDATE",
|
|
||||||
isOwner: permissions === true,
|
|
||||||
active: activeCollection,
|
|
||||||
defaultIndex: permissions === true ? 2 : 1,
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{permissions === true
|
{permissions === true
|
||||||
|
@ -254,6 +245,12 @@ export default function Index() {
|
||||||
modalId={"edit-collection-sharing-modal" + activeCollection.id}
|
modalId={"edit-collection-sharing-modal" + activeCollection.id}
|
||||||
activeCollection={activeCollection}
|
activeCollection={activeCollection}
|
||||||
/>
|
/>
|
||||||
|
<DeleteCollectionModal
|
||||||
|
isOpen={deleteCollectionModal}
|
||||||
|
onClose={() => setDeleteCollectionModal(false)}
|
||||||
|
modalId={"delete-collection-modal" + activeCollection.id}
|
||||||
|
activeCollection={activeCollection}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
|
@ -9,7 +9,6 @@ import CollectionCard from "@/components/CollectionCard";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import MainLayout from "@/layouts/MainLayout";
|
import MainLayout from "@/layouts/MainLayout";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import useModalStore from "@/store/modals";
|
|
||||||
import SortDropdown from "@/components/SortDropdown";
|
import SortDropdown from "@/components/SortDropdown";
|
||||||
import { Sort } from "@/types/global";
|
import { Sort } from "@/types/global";
|
||||||
import useSort from "@/hooks/useSort";
|
import useSort from "@/hooks/useSort";
|
||||||
|
@ -23,8 +22,6 @@ export default function Collections() {
|
||||||
|
|
||||||
const { data } = useSession();
|
const { data } = useSession();
|
||||||
|
|
||||||
const { setModal } = useModalStore();
|
|
||||||
|
|
||||||
useSort({ sortBy, setData: setSortedCollections, data: collections });
|
useSort({ sortBy, setData: setSortedCollections, data: collections });
|
||||||
|
|
||||||
const [newCollectionModal, setNewCollectionModal] = useState(false);
|
const [newCollectionModal, setNewCollectionModal] = useState(false);
|
||||||
|
@ -68,11 +65,7 @@ export default function Collections() {
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
(document?.activeElement as HTMLElement)?.blur();
|
(document?.activeElement as HTMLElement)?.blur();
|
||||||
setModal({
|
setNewCollectionModal(true);
|
||||||
modal: "COLLECTION",
|
|
||||||
state: true,
|
|
||||||
method: "CREATE",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
New Collection
|
New Collection
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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 DashboardItem from "@/components/DashboardItem";
|
import DashboardItem from "@/components/DashboardItem";
|
||||||
|
import NewLinkModal from "@/components/Modals/NewLinkModal";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
|
@ -99,6 +100,8 @@ export default function Dashboard() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [newLinkModal, setNewLinkModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<div style={{ flex: "1 1 auto" }} className="p-5 flex flex-col gap-5">
|
<div style={{ flex: "1 1 auto" }} className="p-5 flex flex-col gap-5">
|
||||||
|
@ -187,11 +190,7 @@ export default function Dashboard() {
|
||||||
<div className="text-center w-full mt-4 flex flex-wrap gap-4 justify-center">
|
<div className="text-center w-full mt-4 flex flex-wrap gap-4 justify-center">
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setModal({
|
setNewLinkModal(true);
|
||||||
modal: "LINK",
|
|
||||||
state: true,
|
|
||||||
method: "CREATE",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
className="inline-flex gap-1 relative w-[11rem] items-center btn btn-accent text-white group"
|
className="inline-flex gap-1 relative w-[11rem] items-center btn btn-accent text-white group"
|
||||||
>
|
>
|
||||||
|
@ -200,24 +199,28 @@ export default function Dashboard() {
|
||||||
className="w-5 h-5 left-4 group-hover:ml-[4rem] 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 Item
|
Create New Link
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<details className="dropdown">
|
<div className="dropdown dropdown-bottom">
|
||||||
<summary className="flex gap-2 text-sm btn btn-outline group">
|
<div
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
className="flex gap-2 text-sm btn btn-outline btn-neutral group"
|
||||||
|
id="import-dropdown"
|
||||||
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faFileImport}
|
icon={faFileImport}
|
||||||
className="w-5 h-5 duration-100"
|
className="w-5 h-5 duration-100"
|
||||||
id="import-dropdown"
|
|
||||||
/>
|
/>
|
||||||
<span className="duration-100" id="import-dropdown">
|
<p>Import From</p>
|
||||||
Import Your Bookmarks
|
</div>
|
||||||
</span>
|
|
||||||
</summary>
|
|
||||||
<ul className="shadow menu dropdown-content z-[1] p-1 bg-base-200 border border-neutral-content rounded-xl mt-1 w-60">
|
<ul className="shadow menu dropdown-content z-[1] p-1 bg-base-200 border border-neutral-content rounded-xl mt-1 w-60">
|
||||||
<li>
|
<li>
|
||||||
<label
|
<label
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
className="px-2 py-1 rounded-lg"
|
className="px-2 py-1 rounded-lg"
|
||||||
htmlFor="import-linkwarden-file"
|
htmlFor="import-linkwarden-file"
|
||||||
title="JSON File"
|
title="JSON File"
|
||||||
|
@ -237,6 +240,8 @@ export default function Dashboard() {
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label
|
<label
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
className="px-2 py-1 rounded-lg"
|
className="px-2 py-1 rounded-lg"
|
||||||
htmlFor="import-html-file"
|
htmlFor="import-html-file"
|
||||||
title="HTML File"
|
title="HTML File"
|
||||||
|
@ -255,7 +260,7 @@ export default function Dashboard() {
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -288,7 +293,6 @@ export default function Dashboard() {
|
||||||
className={`grid overflow-hidden 2xl:grid-cols-3 xl:grid-cols-2 grid-cols-1 gap-5 w-full`}
|
className={`grid overflow-hidden 2xl:grid-cols-3 xl:grid-cols-2 grid-cols-1 gap-5 w-full`}
|
||||||
>
|
>
|
||||||
{links
|
{links
|
||||||
|
|
||||||
.filter((e) => e.pinnedBy && e.pinnedBy[0])
|
.filter((e) => e.pinnedBy && e.pinnedBy[0])
|
||||||
.map((e, i) => <LinkCard key={i} link={e} count={i} />)
|
.map((e, i) => <LinkCard key={i} link={e} count={i} />)
|
||||||
.slice(0, showLinks)}
|
.slice(0, showLinks)}
|
||||||
|
@ -311,6 +315,11 @@ export default function Dashboard() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<NewLinkModal
|
||||||
|
isOpen={newLinkModal}
|
||||||
|
onClose={() => setNewLinkModal(false)}
|
||||||
|
modalId="new-link-modal"
|
||||||
|
/>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ export default function Index() {
|
||||||
<Link key={i} href={`/tags/${e.id}`} className="z-10">
|
<Link key={i} href={`/tags/${e.id}`} className="z-10">
|
||||||
<p
|
<p
|
||||||
title={e.name}
|
title={e.name}
|
||||||
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="btn btn-xs btn-outline truncate max-w-[19rem]"
|
||||||
>
|
>
|
||||||
{e.name}
|
{e.name}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -9,7 +9,6 @@ import Head from "next/head";
|
||||||
import useLinks from "@/hooks/useLinks";
|
import useLinks from "@/hooks/useLinks";
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import ProfilePhoto from "@/components/ProfilePhoto";
|
import ProfilePhoto from "@/components/ProfilePhoto";
|
||||||
import useModalStore from "@/store/modals";
|
|
||||||
import ModalManagement from "@/components/ModalManagement";
|
import ModalManagement from "@/components/ModalManagement";
|
||||||
import ToggleDarkMode from "@/components/ToggleDarkMode";
|
import ToggleDarkMode from "@/components/ToggleDarkMode";
|
||||||
import getPublicUserData from "@/lib/client/getPublicUserData";
|
import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
|
@ -37,16 +36,9 @@ const cardVariants: Variants = {
|
||||||
|
|
||||||
export default function PublicCollections() {
|
export default function PublicCollections() {
|
||||||
const { links } = useLinkStore();
|
const { links } = useLinkStore();
|
||||||
const { modal, setModal } = useModalStore();
|
|
||||||
|
|
||||||
const { settings } = useLocalSettingsStore();
|
const { settings } = useLocalSettingsStore();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
modal
|
|
||||||
? (document.body.style.overflow = "hidden")
|
|
||||||
: (document.body.style.overflow = "auto");
|
|
||||||
}, [modal]);
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [collectionOwner, setCollectionOwner] = useState({
|
const [collectionOwner, setCollectionOwner] = useState({
|
||||||
|
|
|
@ -236,10 +236,14 @@ export default function Index() {
|
||||||
</p>
|
</p>
|
||||||
</Link>
|
</Link>
|
||||||
{link?.tags.map((e, i) => (
|
{link?.tags.map((e, i) => (
|
||||||
<Link key={i} href={`/tags/${e.id}`} className="z-10">
|
<Link
|
||||||
|
key={i}
|
||||||
|
href={"/public/collections/20?q=" + e.name}
|
||||||
|
className="z-10"
|
||||||
|
>
|
||||||
<p
|
<p
|
||||||
title={e.name}
|
title={e.name}
|
||||||
className="px-2 py-1 bg-sky-200 dark:bg-sky-900 text-xs rounded-3xl cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]"
|
className="btn btn-xs btn-outline truncate max-w-[19rem]"
|
||||||
>
|
>
|
||||||
{e.name}
|
{e.name}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -155,7 +155,7 @@ export default function Account() {
|
||||||
|
|
||||||
<div className="divider my-3"></div>
|
<div className="divider my-3"></div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-5">
|
||||||
<div className="grid sm:grid-cols-2 gap-3 auto-rows-auto">
|
<div className="grid sm:grid-cols-2 gap-3 auto-rows-auto">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<div>
|
<div>
|
||||||
|
@ -215,7 +215,7 @@ export default function Account() {
|
||||||
</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="btn btn-xs btn-secondary btn-outline bg-base-100">
|
<label className="btn btn-xs btn-neutral btn-outline bg-base-100">
|
||||||
Browse...
|
Browse...
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
@ -243,16 +243,20 @@ 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>
|
||||||
<details className="dropdown">
|
<div className="dropdown dropdown-bottom">
|
||||||
<summary
|
<div
|
||||||
className="flex gap-2 text-sm btn btn-outline btn-secondary btn-xs"
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
className="flex gap-2 text-sm btn btn-outline btn-neutral btn-xs"
|
||||||
id="import-dropdown"
|
id="import-dropdown"
|
||||||
>
|
>
|
||||||
Import From
|
Import From
|
||||||
</summary>
|
</div>
|
||||||
<ul className="shadow menu dropdown-content z-[1] p-1 bg-base-200 border border-neutral-content rounded-xl mt-1 w-60">
|
<ul className="shadow menu dropdown-content z-[1] p-1 bg-base-200 border border-neutral-content rounded-xl mt-1 w-60">
|
||||||
<li>
|
<li>
|
||||||
<label
|
<label
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
className="px-2 py-1 rounded-lg"
|
className="px-2 py-1 rounded-lg"
|
||||||
htmlFor="import-linkwarden-file"
|
htmlFor="import-linkwarden-file"
|
||||||
title="JSON File"
|
title="JSON File"
|
||||||
|
@ -272,6 +276,8 @@ export default function Account() {
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label
|
<label
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
className="px-2 py-1 rounded-lg"
|
className="px-2 py-1 rounded-lg"
|
||||||
htmlFor="import-html-file"
|
htmlFor="import-html-file"
|
||||||
title="HTML File"
|
title="HTML File"
|
||||||
|
@ -290,13 +296,13 @@ export default function Account() {
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</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="btn btn-outline btn-secondary btn-xs">
|
<div className="btn btn-outline btn-neutral btn-xs">
|
||||||
Export Data
|
Export Data
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -365,15 +371,15 @@ export default function Account() {
|
||||||
You will be prompted to enter your password before the deletion
|
You will be prompted to enter your password before the deletion
|
||||||
process.
|
process.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="/settings/delete"
|
href="/settings/delete"
|
||||||
className="mx-auto lg:mx-0 text-white mt-3 flex items-center gap-2 py-1 px-3 rounded-md text-lg tracking-wide select-none font-semibold duration-100 w-fit bg-red-500 hover:bg-red-400 cursor-pointer"
|
className="mx-auto lg:mx-0 text-white flex items-center gap-2 py-1 px-3 rounded-md text-lg tracking-wide select-none font-semibold duration-100 w-fit bg-red-500 hover:bg-red-400 cursor-pointer"
|
||||||
>
|
>
|
||||||
<p className="text-center w-full">Delete Your Account</p>
|
<p className="text-center w-full">Delete Your Account</p>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</SettingsLayout>
|
</SettingsLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default function Appearance() {
|
||||||
|
|
||||||
<div className="divider my-3"></div>
|
<div className="divider my-3"></div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-5">
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-3">Select Theme</p>
|
<p className="mb-3">Select Theme</p>
|
||||||
<div className="flex gap-3 w-full">
|
<div className="flex gap-3 w-full">
|
||||||
|
|
|
@ -6,8 +6,8 @@ module.exports = {
|
||||||
themes: [
|
themes: [
|
||||||
{
|
{
|
||||||
light: {
|
light: {
|
||||||
primary: "#0ea5e9",
|
primary: "#0284c7",
|
||||||
secondary: "#06b6d4",
|
secondary: "#0891b2",
|
||||||
accent: "#6366f1",
|
accent: "#6366f1",
|
||||||
neutral: "#6b7280",
|
neutral: "#6b7280",
|
||||||
"neutral-content": "#d1d5db",
|
"neutral-content": "#d1d5db",
|
||||||
|
@ -22,8 +22,8 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dark: {
|
dark: {
|
||||||
primary: "#0ea5e9",
|
primary: "#38bdf8",
|
||||||
secondary: "#0e7490",
|
secondary: "#22d3ee",
|
||||||
accent: "#6366f1",
|
accent: "#6366f1",
|
||||||
neutral: "#9ca3af",
|
neutral: "#9ca3af",
|
||||||
"neutral-content": "#404040",
|
"neutral-content": "#404040",
|
||||||
|
|
Ŝarĝante…
Reference in New Issue