@@ -1,5 +1,8 @@
|
||||
import Link from "next/link";
|
||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||
import {
|
||||
AccountSettings,
|
||||
CollectionIncludingMembersAndLinkCount,
|
||||
} from "@/types/global";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import ProfilePhoto from "./ProfilePhoto";
|
||||
import usePermissions from "@/hooks/usePermissions";
|
||||
@@ -12,12 +15,11 @@ import { dropdownTriggerer } from "@/lib/client/utils";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { useUser } from "@/hooks/store/user";
|
||||
|
||||
type Props = {
|
||||
export default function CollectionCard({
|
||||
collection,
|
||||
}: {
|
||||
collection: CollectionIncludingMembersAndLinkCount;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export default function CollectionCard({ collection, className }: Props) {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { settings } = useLocalSettingsStore();
|
||||
const { data: user = {} } = useUser();
|
||||
@@ -33,15 +35,9 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||
|
||||
const permissions = usePermissions(collection.id as number);
|
||||
|
||||
const [collectionOwner, setCollectionOwner] = useState({
|
||||
id: null as unknown as number,
|
||||
name: "",
|
||||
username: "",
|
||||
image: "",
|
||||
archiveAsScreenshot: undefined as unknown as boolean,
|
||||
archiveAsMonolith: undefined as unknown as boolean,
|
||||
archiveAsPDF: undefined as unknown as boolean,
|
||||
});
|
||||
const [collectionOwner, setCollectionOwner] = useState<
|
||||
Partial<AccountSettings>
|
||||
>({});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchOwner = async () => {
|
||||
@@ -132,12 +128,12 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||
className="flex items-center absolute bottom-3 left-3 z-10 btn px-2 btn-ghost rounded-full"
|
||||
onClick={() => setEditCollectionSharingModal(true)}
|
||||
>
|
||||
{collectionOwner.id ? (
|
||||
{collectionOwner.id && (
|
||||
<ProfilePhoto
|
||||
src={collectionOwner.image || undefined}
|
||||
name={collectionOwner.name}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
{collection.members
|
||||
.sort((a, b) => (a.userId as number) - (b.userId as number))
|
||||
.map((e, i) => {
|
||||
@@ -151,13 +147,13 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||
);
|
||||
})
|
||||
.slice(0, 3)}
|
||||
{collection.members.length - 3 > 0 ? (
|
||||
{collection.members.length - 3 > 0 && (
|
||||
<div className={`avatar drop-shadow-md placeholder -ml-3`}>
|
||||
<div className="bg-base-100 text-neutral rounded-full w-8 h-8 ring-2 ring-neutral-content">
|
||||
<span>+{collection.members.length - 3}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
<Link
|
||||
href={`/collections/${collection.id}`}
|
||||
@@ -181,12 +177,12 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||
<div className="flex justify-end items-center">
|
||||
<div className="text-right">
|
||||
<div className="font-bold text-sm flex justify-end gap-1 items-center">
|
||||
{collection.isPublic ? (
|
||||
{collection.isPublic && (
|
||||
<i
|
||||
className="bi-globe2 drop-shadow text-neutral"
|
||||
title="This collection is being shared publicly."
|
||||
></i>
|
||||
) : undefined}
|
||||
)}
|
||||
<i
|
||||
className="bi-link-45deg text-lg text-neutral"
|
||||
title="This collection is being shared publicly."
|
||||
@@ -206,24 +202,24 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
{editCollectionModal ? (
|
||||
{editCollectionModal && (
|
||||
<EditCollectionModal
|
||||
onClose={() => setEditCollectionModal(false)}
|
||||
activeCollection={collection}
|
||||
/>
|
||||
) : undefined}
|
||||
{editCollectionSharingModal ? (
|
||||
)}
|
||||
{editCollectionSharingModal && (
|
||||
<EditCollectionSharingModal
|
||||
onClose={() => setEditCollectionSharingModal(false)}
|
||||
activeCollection={collection}
|
||||
/>
|
||||
) : undefined}
|
||||
{deleteCollectionModal ? (
|
||||
)}
|
||||
{deleteCollectionModal && (
|
||||
<DeleteCollectionModal
|
||||
onClose={() => setDeleteCollectionModal(false)}
|
||||
activeCollection={collection}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -272,12 +272,12 @@ const renderItem = (
|
||||
></i>
|
||||
<p className="truncate w-full">{collection.name}</p>
|
||||
|
||||
{collection.isPublic ? (
|
||||
{collection.isPublic && (
|
||||
<i
|
||||
className="bi-globe2 text-sm text-black/50 dark:text-white/50 drop-shadow"
|
||||
title="This collection is being shared publicly."
|
||||
></i>
|
||||
) : undefined}
|
||||
)}
|
||||
<div className="drop-shadow text-neutral text-xs">
|
||||
{collection._count?.links}
|
||||
</div>
|
||||
|
||||
+42
-40
@@ -60,47 +60,49 @@ export default function Dropdown({
|
||||
}
|
||||
}, [points, dropdownHeight]);
|
||||
|
||||
return !points || pos ? (
|
||||
<ClickAwayHandler
|
||||
onMount={(e) => {
|
||||
setDropdownHeight(e.height);
|
||||
setDropdownWidth(e.width);
|
||||
}}
|
||||
style={
|
||||
points
|
||||
? {
|
||||
position: "fixed",
|
||||
top: `${pos?.y}px`,
|
||||
left: `${pos?.x}px`,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onClickOutside={onClickOutside}
|
||||
className={`${
|
||||
className || ""
|
||||
} py-1 shadow-md border border-neutral-content bg-base-200 rounded-md flex flex-col z-20`}
|
||||
>
|
||||
{items.map((e, i) => {
|
||||
const inner = e && (
|
||||
<div className="cursor-pointer rounded-md">
|
||||
<div className="flex items-center gap-2 py-1 px-2 hover:bg-base-100 duration-100">
|
||||
<p className="select-none">{e.name}</p>
|
||||
return (
|
||||
(!points || pos) && (
|
||||
<ClickAwayHandler
|
||||
onMount={(e) => {
|
||||
setDropdownHeight(e.height);
|
||||
setDropdownWidth(e.width);
|
||||
}}
|
||||
style={
|
||||
points
|
||||
? {
|
||||
position: "fixed",
|
||||
top: `${pos?.y}px`,
|
||||
left: `${pos?.x}px`,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onClickOutside={onClickOutside}
|
||||
className={`${
|
||||
className || ""
|
||||
} py-1 shadow-md border border-neutral-content bg-base-200 rounded-md flex flex-col z-20`}
|
||||
>
|
||||
{items.map((e, i) => {
|
||||
const inner = e && (
|
||||
<div className="cursor-pointer rounded-md">
|
||||
<div className="flex items-center gap-2 py-1 px-2 hover:bg-base-100 duration-100">
|
||||
<p className="select-none">{e.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
|
||||
return e && e.href ? (
|
||||
<Link key={i} href={e.href}>
|
||||
{inner}
|
||||
</Link>
|
||||
) : (
|
||||
e && (
|
||||
<div key={i} onClick={e.onClick}>
|
||||
return e && e.href ? (
|
||||
<Link key={i} href={e.href}>
|
||||
{inner}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</ClickAwayHandler>
|
||||
) : null;
|
||||
</Link>
|
||||
) : (
|
||||
e && (
|
||||
<div key={i} onClick={e.onClick}>
|
||||
{inner}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</ClickAwayHandler>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ export default function TagSelection({ onChange, defaultValue }: Props) {
|
||||
options={options}
|
||||
styles={styles}
|
||||
defaultValue={defaultValue}
|
||||
// menuPosition="fixed"
|
||||
isMulti
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -136,7 +136,7 @@ export default function LinkActions({
|
||||
{t("show_link_details")}
|
||||
</div>
|
||||
</li>
|
||||
{permissions === true || permissions?.canUpdate ? (
|
||||
{(permissions === true || permissions?.canUpdate) && (
|
||||
<li>
|
||||
<div
|
||||
role="button"
|
||||
@@ -150,7 +150,7 @@ export default function LinkActions({
|
||||
{t("edit_link")}
|
||||
</div>
|
||||
</li>
|
||||
) : undefined}
|
||||
)}
|
||||
{link.type === "url" && (
|
||||
<li>
|
||||
<div
|
||||
@@ -166,7 +166,7 @@ export default function LinkActions({
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
{permissions === true || permissions?.canDelete ? (
|
||||
{(permissions === true || permissions?.canDelete) && (
|
||||
<li>
|
||||
<div
|
||||
role="button"
|
||||
@@ -196,36 +196,35 @@ export default function LinkActions({
|
||||
{t("delete")}
|
||||
</div>
|
||||
</li>
|
||||
) : undefined}
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{editLinkModal ? (
|
||||
{editLinkModal && (
|
||||
<EditLinkModal
|
||||
onClose={() => setEditLinkModal(false)}
|
||||
activeLink={link}
|
||||
/>
|
||||
) : undefined}
|
||||
{deleteLinkModal ? (
|
||||
)}
|
||||
{deleteLinkModal && (
|
||||
<DeleteLinkModal
|
||||
onClose={() => setDeleteLinkModal(false)}
|
||||
activeLink={link}
|
||||
/>
|
||||
) : undefined}
|
||||
{preservedFormatsModal ? (
|
||||
)}
|
||||
{preservedFormatsModal && (
|
||||
<PreservedFormatsModal
|
||||
onClose={() => setPreservedFormatsModal(false)}
|
||||
link={link}
|
||||
/>
|
||||
) : undefined}
|
||||
{linkDetailModal ? (
|
||||
)}
|
||||
{linkDetailModal && (
|
||||
<LinkDetailModal
|
||||
onClose={() => setLinkDetailModal(false)}
|
||||
onEdit={() => setEditLinkModal(true)}
|
||||
link={link}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
|
||||
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
||||
|
||||
useEffect(() => {
|
||||
let interval: any;
|
||||
let interval: NodeJS.Timeout | null = null;
|
||||
|
||||
if (
|
||||
isVisible &&
|
||||
|
||||
@@ -127,9 +127,9 @@ export default function LinkCardCompact({
|
||||
|
||||
<div className="mt-1 flex flex-col sm:flex-row sm:items-center gap-2 text-xs text-neutral">
|
||||
<div className="flex items-center gap-x-3 text-neutral flex-wrap">
|
||||
{collection ? (
|
||||
{collection && (
|
||||
<LinkCollection link={link} collection={collection} />
|
||||
) : undefined}
|
||||
)}
|
||||
{link.name && <LinkTypeBadge link={link} />}
|
||||
<LinkDate link={link} />
|
||||
</div>
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) {
|
||||
const permissions = usePermissions(collection?.id as number);
|
||||
|
||||
useEffect(() => {
|
||||
let interval: any;
|
||||
let interval: NodeJS.Timeout | null = null;
|
||||
|
||||
if (
|
||||
isVisible &&
|
||||
|
||||
@@ -87,15 +87,13 @@ export default function MobileNavigation({}: Props) {
|
||||
<MobileNavigationButton href={`/collections`} icon={"bi-folder"} />
|
||||
</div>
|
||||
</div>
|
||||
{newLinkModal ? (
|
||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
||||
) : undefined}
|
||||
{newCollectionModal ? (
|
||||
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||
{newCollectionModal && (
|
||||
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
||||
) : undefined}
|
||||
{uploadFileModal ? (
|
||||
)}
|
||||
{uploadFileModal && (
|
||||
<UploadFileModal onClose={() => setUploadFileModal(false)} />
|
||||
) : undefined}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import TextInput from "@/components/TextInput";
|
||||
import toast from "react-hot-toast";
|
||||
import { CollectionIncludingMembersAndLinkCount, Member } from "@/types/global";
|
||||
import {
|
||||
AccountSettings,
|
||||
CollectionIncludingMembersAndLinkCount,
|
||||
Member,
|
||||
} from "@/types/global";
|
||||
import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||
import usePermissions from "@/hooks/usePermissions";
|
||||
import ProfilePhoto from "../ProfilePhoto";
|
||||
@@ -65,15 +69,9 @@ export default function EditCollectionSharingModal({
|
||||
|
||||
const [memberUsername, setMemberUsername] = useState("");
|
||||
|
||||
const [collectionOwner, setCollectionOwner] = useState({
|
||||
id: null as unknown as number,
|
||||
name: "",
|
||||
username: "",
|
||||
image: "",
|
||||
archiveAsScreenshot: undefined as unknown as boolean,
|
||||
archiveAsMonolith: undefined as unknown as boolean,
|
||||
archiveAsPDF: undefined as unknown as boolean,
|
||||
});
|
||||
const [collectionOwner, setCollectionOwner] = useState<
|
||||
Partial<AccountSettings>
|
||||
>({});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchOwner = async () => {
|
||||
@@ -133,7 +131,7 @@ export default function EditCollectionSharingModal({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{collection.isPublic ? (
|
||||
{collection.isPublic && (
|
||||
<div>
|
||||
<p className="mb-2">{t("sharable_link_guide")}</p>
|
||||
<div className="w-full hide-scrollbar overflow-x-auto whitespace-nowrap rounded-md p-2 bg-base-200 border-neutral-content border-solid border flex items-center gap-2 justify-between">
|
||||
@@ -141,7 +139,7 @@ export default function EditCollectionSharingModal({
|
||||
<CopyButton text={publicCollectionURL} />
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
)}
|
||||
|
||||
{permissions === true && <div className="divider my-3"></div>}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ export default function EditLinkModal({ onClose, activeLink }: Props) {
|
||||
|
||||
<div className="divider mb-3 mt-1"></div>
|
||||
|
||||
{link.url ? (
|
||||
{link.url && (
|
||||
<Link
|
||||
href={link.url}
|
||||
className="truncate text-neutral flex gap-2 mb-5 w-fit max-w-full"
|
||||
@@ -87,7 +87,7 @@ export default function EditLinkModal({ onClose, activeLink }: Props) {
|
||||
<i className="bi-link-45deg text-xl" />
|
||||
<p>{shortenedURL}</p>
|
||||
</Link>
|
||||
) : undefined}
|
||||
)}
|
||||
|
||||
<div className="w-full">
|
||||
<p className="mb-2">{t("name")}</p>
|
||||
@@ -103,7 +103,7 @@ export default function EditLinkModal({ onClose, activeLink }: Props) {
|
||||
<div className="grid sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<p className="mb-2">{t("collection")}</p>
|
||||
{link.collection.name ? (
|
||||
{link.collection.name && (
|
||||
<CollectionSelection
|
||||
onChange={setCollection}
|
||||
defaultValue={
|
||||
@@ -113,7 +113,7 @@ export default function EditLinkModal({ onClose, activeLink }: Props) {
|
||||
}
|
||||
creatable={false}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -124,7 +124,7 @@ export default function NewLinkModal({ onClose }: Props) {
|
||||
</div>
|
||||
<div className="sm:col-span-2 col-span-5">
|
||||
<p className="mb-2">{t("collection")}</p>
|
||||
{link.collection.name ? (
|
||||
{link.collection.name && (
|
||||
<CollectionSelection
|
||||
onChange={setCollection}
|
||||
defaultValue={{
|
||||
@@ -132,11 +132,11 @@ export default function NewLinkModal({ onClose }: Props) {
|
||||
value: link.collection.id,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={"mt-2"}>
|
||||
{optionsExpanded ? (
|
||||
{optionsExpanded && (
|
||||
<div className="mt-5">
|
||||
<div className="grid sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
@@ -171,7 +171,7 @@ export default function NewLinkModal({ onClose }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : undefined}
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between items-center mt-5">
|
||||
<div
|
||||
|
||||
@@ -79,7 +79,7 @@ export default function NewUserModal({ onClose }: Props) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{emailEnabled ? (
|
||||
{emailEnabled && (
|
||||
<div>
|
||||
<p className="mb-2">{t("email")}</p>
|
||||
<TextInput
|
||||
@@ -89,7 +89,7 @@ export default function NewUserModal({ onClose }: Props) {
|
||||
value={form.email}
|
||||
/>
|
||||
</div>
|
||||
) : undefined}
|
||||
)}
|
||||
|
||||
<div>
|
||||
<p className="mb-2">
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
ArchivedFormat,
|
||||
AccountSettings,
|
||||
} from "@/types/global";
|
||||
import toast from "react-hot-toast";
|
||||
import Link from "next/link";
|
||||
@@ -35,15 +36,9 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
|
||||
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
||||
|
||||
const [collectionOwner, setCollectionOwner] = useState({
|
||||
id: null as unknown as number,
|
||||
name: "",
|
||||
username: "",
|
||||
image: "",
|
||||
archiveAsScreenshot: undefined as unknown as boolean,
|
||||
archiveAsMonolith: undefined as unknown as boolean,
|
||||
archiveAsPDF: undefined as unknown as boolean,
|
||||
});
|
||||
const [collectionOwner, setCollectionOwner] = useState<
|
||||
Partial<AccountSettings>
|
||||
>({});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchOwner = async () => {
|
||||
@@ -99,7 +94,7 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
await getLink.mutateAsync({ id: link.id as number });
|
||||
})();
|
||||
|
||||
let interval: any;
|
||||
let interval: NodeJS.Timeout | null = null;
|
||||
|
||||
if (!isReady()) {
|
||||
interval = setInterval(async () => {
|
||||
@@ -149,7 +144,7 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
)}
|
||||
|
||||
<div className={`flex flex-col gap-3`}>
|
||||
{monolithAvailable(link) ? (
|
||||
{monolithAvailable(link) && (
|
||||
<PreservedFormatRow
|
||||
name={t("webpage")}
|
||||
icon={"bi-filetype-html"}
|
||||
@@ -157,9 +152,9 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
link={link}
|
||||
downloadable={true}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
|
||||
{screenshotAvailable(link) ? (
|
||||
{screenshotAvailable(link) && (
|
||||
<PreservedFormatRow
|
||||
name={t("screenshot")}
|
||||
icon={"bi-file-earmark-image"}
|
||||
@@ -171,9 +166,9 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
link={link}
|
||||
downloadable={true}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
|
||||
{pdfAvailable(link) ? (
|
||||
{pdfAvailable(link) && (
|
||||
<PreservedFormatRow
|
||||
name={t("pdf")}
|
||||
icon={"bi-file-earmark-pdf"}
|
||||
@@ -181,16 +176,16 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
link={link}
|
||||
downloadable={true}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
|
||||
{readabilityAvailable(link) ? (
|
||||
{readabilityAvailable(link) && (
|
||||
<PreservedFormatRow
|
||||
name={t("readable")}
|
||||
icon={"bi-file-earmark-text"}
|
||||
format={ArchivedFormat.readability}
|
||||
link={link}
|
||||
/>
|
||||
) : undefined}
|
||||
)}
|
||||
|
||||
{!isReady() && !atLeastOneFormatAvailable() ? (
|
||||
<div className={`w-full h-full flex flex-col justify-center p-10`}>
|
||||
@@ -203,17 +198,20 @@ export default function PreservedFormatsModal({ onClose, link }: Props) {
|
||||
<p className="text-center text-2xl">{t("preservation_in_queue")}</p>
|
||||
<p className="text-center text-lg">{t("check_back_later")}</p>
|
||||
</div>
|
||||
) : !isReady() && atLeastOneFormatAvailable() ? (
|
||||
<div className={`w-full h-full flex flex-col justify-center p-5`}>
|
||||
<BeatLoader
|
||||
color="oklch(var(--p))"
|
||||
className="mx-auto mb-3"
|
||||
size={20}
|
||||
/>
|
||||
<p className="text-center">{t("there_are_more_formats")}</p>
|
||||
<p className="text-center text-sm">{t("check_back_later")}</p>
|
||||
</div>
|
||||
) : undefined}
|
||||
) : (
|
||||
!isReady() &&
|
||||
atLeastOneFormatAvailable() && (
|
||||
<div className={`w-full h-full flex flex-col justify-center p-5`}>
|
||||
<BeatLoader
|
||||
color="oklch(var(--p))"
|
||||
className="mx-auto mb-3"
|
||||
size={20}
|
||||
/>
|
||||
<p className="text-center">{t("there_are_more_formats")}</p>
|
||||
<p className="text-center text-sm">{t("check_back_later")}</p>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`flex flex-col sm:flex-row gap-3 items-center justify-center ${
|
||||
|
||||
@@ -150,7 +150,7 @@ export default function UploadFileModal({ onClose }: Props) {
|
||||
<label className="btn h-10 btn-sm w-full border border-neutral-content hover:border-neutral-content flex justify-between">
|
||||
<input
|
||||
type="file"
|
||||
accept=".pdf,.png,.jpg,.jpeg,.html"
|
||||
accept=".pdf,.png,.jpg,.jpeg"
|
||||
className="cursor-pointer custom-file-input"
|
||||
onChange={(e) => e.target.files && setFile(e.target.files[0])}
|
||||
/>
|
||||
@@ -163,7 +163,7 @@ export default function UploadFileModal({ onClose }: Props) {
|
||||
</div>
|
||||
<div className="sm:col-span-2 col-span-5">
|
||||
<p className="mb-2">{t("collection")}</p>
|
||||
{link.collection.name ? (
|
||||
{link.collection.name && (
|
||||
<CollectionSelection
|
||||
onChange={setCollection}
|
||||
defaultValue={{
|
||||
@@ -171,10 +171,10 @@ export default function UploadFileModal({ onClose }: Props) {
|
||||
value: link.collection.id,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{optionsExpanded ? (
|
||||
{optionsExpanded && (
|
||||
<div className="mt-5">
|
||||
<div className="grid sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
@@ -209,7 +209,7 @@ export default function UploadFileModal({ onClose }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : undefined}
|
||||
)}
|
||||
<div className="flex justify-between items-center mt-5">
|
||||
<div
|
||||
onClick={() => setOptionsExpanded(!optionsExpanded)}
|
||||
|
||||
@@ -114,7 +114,7 @@ export default function Navbar() {
|
||||
|
||||
<MobileNavigation />
|
||||
|
||||
{sidebar ? (
|
||||
{sidebar && (
|
||||
<div className="fixed top-0 bottom-0 right-0 left-0 bg-black bg-opacity-10 backdrop-blur-sm flex items-center fade-in z-40">
|
||||
<ClickAwayHandler className="h-full" onClickOutside={toggleSidebar}>
|
||||
<div className="slide-right h-full shadow-lg">
|
||||
@@ -122,16 +122,14 @@ export default function Navbar() {
|
||||
</div>
|
||||
</ClickAwayHandler>
|
||||
</div>
|
||||
) : null}
|
||||
{newLinkModal ? (
|
||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
||||
) : undefined}
|
||||
{newCollectionModal ? (
|
||||
)}
|
||||
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||
{newCollectionModal && (
|
||||
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
||||
) : undefined}
|
||||
{uploadFileModal ? (
|
||||
)}
|
||||
{uploadFileModal && (
|
||||
<UploadFileModal onClose={() => setUploadFileModal(false)} />
|
||||
) : undefined}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,9 +39,7 @@ export default function NoLinksFound({ text }: Props) {
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{newLinkModal ? (
|
||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
||||
) : undefined}
|
||||
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
} from "@/types/global";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useGetLink } from "@/hooks/store/links";
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
@@ -21,8 +20,6 @@ export default function PreservedFormatRow({
|
||||
link,
|
||||
downloadable,
|
||||
}: Props) {
|
||||
const getLink = useGetLink();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function ProfileDropdown() {
|
||||
})}
|
||||
</div>
|
||||
</li>
|
||||
{isAdmin ? (
|
||||
{isAdmin && (
|
||||
<li>
|
||||
<Link
|
||||
href="/admin"
|
||||
@@ -72,7 +72,7 @@ export default function ProfileDropdown() {
|
||||
{t("server_administration")}
|
||||
</Link>
|
||||
</li>
|
||||
) : null}
|
||||
)}
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function ReadableView({ link }: Props) {
|
||||
useEffect(() => {
|
||||
if (link) getLink.mutateAsync({ id: link.id as number });
|
||||
|
||||
let interval: any;
|
||||
let interval: NodeJS.Timeout | null = null;
|
||||
if (
|
||||
link &&
|
||||
(link?.image === "pending" ||
|
||||
@@ -182,7 +182,7 @@ export default function ReadableView({ link }: Props) {
|
||||
link?.name || link?.description || link?.url || ""
|
||||
)}
|
||||
</p>
|
||||
{link?.url ? (
|
||||
{link?.url && (
|
||||
<Link
|
||||
href={link?.url || ""}
|
||||
title={link?.url}
|
||||
@@ -191,11 +191,10 @@ export default function ReadableView({ link }: Props) {
|
||||
>
|
||||
<i className="bi-link-45deg"></i>
|
||||
|
||||
{isValidUrl(link?.url || "")
|
||||
? new URL(link?.url as string).host
|
||||
: undefined}
|
||||
{isValidUrl(link?.url || "") &&
|
||||
new URL(link?.url as string).host}
|
||||
</Link>
|
||||
) : undefined}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import useLocalSettingsStore from "@/store/localSettings";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, ChangeEvent } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
type Props = {
|
||||
@@ -10,14 +10,18 @@ export default function ToggleDarkMode({ className }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { settings, updateSettings } = useLocalSettingsStore();
|
||||
|
||||
const [theme, setTheme] = useState(localStorage.getItem("theme"));
|
||||
const [theme, setTheme] = useState<string | null>(
|
||||
localStorage.getItem("theme")
|
||||
);
|
||||
|
||||
const handleToggle = (e: any) => {
|
||||
const handleToggle = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setTheme(e.target.checked ? "dark" : "light");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateSettings({ theme: theme as string });
|
||||
if (theme) {
|
||||
updateSettings({ theme });
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
return (
|
||||
@@ -34,7 +38,7 @@ export default function ToggleDarkMode({ className }: Props) {
|
||||
type="checkbox"
|
||||
onChange={handleToggle}
|
||||
className="theme-controller"
|
||||
checked={localStorage.getItem("theme") === "light" ? false : true}
|
||||
checked={theme === "dark"}
|
||||
/>
|
||||
<i className="bi-sun-fill text-xl swap-on"></i>
|
||||
<i className="bi-moon-fill text-xl swap-off"></i>
|
||||
|
||||
@@ -74,12 +74,12 @@ const UserListing = (
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{deleteUserModal.isOpen && deleteUserModal.userId ? (
|
||||
{deleteUserModal.isOpen && deleteUserModal.userId && (
|
||||
<DeleteUserModal
|
||||
onClose={() => setDeleteUserModal({ isOpen: false, userId: null })}
|
||||
userId={deleteUserModal.userId}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user