el.xwx.moe/components/PublicPage/PublicLinkCard.tsx

133 lines
4.5 KiB
TypeScript
Raw Normal View History

2023-05-31 09:30:45 -05:00
import Image from "next/image";
import { Link as LinkType, Tag } from "@prisma/client";
2023-11-25 02:27:34 -06:00
import isValidUrl from "@/lib/shared/isValidUrl";
import unescapeString from "@/lib/client/unescapeString";
2023-11-15 12:12:06 -06:00
import { TagIncludingLinkCount } from "@/types/global";
2023-11-19 07:12:37 -06:00
import Link from "next/link";
2023-12-19 16:20:09 -06:00
import { useState } from "react";
import PreservedFormatsModal from "../ModalContent/PreservedFormatsModal";
interface LinksIncludingTags extends LinkType {
2023-11-15 12:12:06 -06:00
tags: TagIncludingLinkCount[];
}
2023-05-31 09:30:45 -05:00
type Props = {
link: LinksIncludingTags;
2023-05-31 09:30:45 -05:00
count: number;
};
export default function LinkCard({ link, count }: Props) {
2023-11-25 02:27:34 -06:00
const url = link.url && isValidUrl(link.url) ? new URL(link.url) : undefined;
2023-06-26 18:35:12 -05:00
2023-05-31 09:30:45 -05:00
const formattedDate = new Date(
link.createdAt as unknown as string
).toLocaleString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
2023-12-19 16:20:09 -06:00
const [preservedFormatsModal, setPreservedFormatsModal] = useState(false);
2023-05-31 09:30:45 -05:00
return (
2023-11-26 04:17:08 -06:00
<div className="border border-solid border-neutral-content bg-base-200 shadow hover:shadow-none duration-100 rounded-lg p-3 flex items-start relative gap-3 group/item">
2023-11-19 07:12:37 -06:00
<div className="flex justify-between items-end gap-5 w-full h-full z-0">
<div className="flex flex-col justify-between w-full">
<div className="flex items-center gap-2">
<p className="text-2xl">
{url && (
<Image
src={`https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${url.origin}&size=32`}
width={30}
height={30}
alt=""
className="select-none z-10 rounded-md shadow border-[1px] border-white bg-white float-left mr-2"
draggable="false"
onError={(e) => {
const target = e.target as HTMLElement;
target.style.display = "none";
}}
/>
)}
{unescapeString(link.name || link.description)}
2023-06-13 23:40:23 -05:00
</p>
2023-11-19 07:12:37 -06:00
</div>
<div className="flex gap-3 items-center flex-wrap my-2">
<div className="flex gap-1 items-center flex-wrap">
{link.tags.map((e, i) => (
<Link
href={"/public/collections/20?q=" + e.name}
key={i}
2023-12-05 03:12:48 -06:00
className="btn btn-xs btn-ghost truncate max-w-[19rem]"
2023-11-19 07:12:37 -06:00
>
2023-12-05 03:12:48 -06:00
#{e.name}
2023-11-19 07:12:37 -06:00
</Link>
))}
2023-05-31 09:30:45 -05:00
</div>
</div>
2023-11-25 04:39:56 -06:00
<div className="flex gap-1 items-center flex-wrap text-sm text-neutral">
2023-11-19 07:12:37 -06:00
<p>{formattedDate}</p>
<p>·</p>
<Link
2023-11-25 02:27:34 -06:00
href={url ? url.href : link.url || ""}
2023-11-19 07:12:37 -06:00
target="_blank"
className="hover:opacity-50 duration-100 truncate w-52 sm:w-fit"
2023-11-25 02:27:34 -06:00
title={url ? url.href : link.url || ""}
2023-11-19 07:12:37 -06:00
>
{url ? url.host : link.url}
</Link>
</div>
<div className="w-full">
{unescapeString(link.description)}{" "}
<Link
2023-12-19 16:20:09 -06:00
href={link.url || ""}
target="_blank"
2023-11-25 04:39:56 -06:00
className="flex gap-1 items-center flex-wrap text-sm text-neutral hover:opacity-50 duration-100 min-w-fit float-right mt-1 ml-2"
2023-11-19 07:12:37 -06:00
>
2023-12-19 16:20:09 -06:00
<p>Visit</p>
2023-12-17 16:06:49 -06:00
<i className={"bi-chevron-right"}></i>
2023-11-19 07:12:37 -06:00
</Link>
2023-05-31 09:30:45 -05:00
</div>
</div>
</div>
2023-12-19 16:20:09 -06:00
<div
className={`dropdown dropdown-left absolute ${"top-3 right-3"} z-20`}
>
<div
tabIndex={0}
role="button"
className="btn btn-ghost btn-sm btn-square text-neutral"
>
<i
id={"expand-dropdown" + link.id}
title="More"
className="bi-three-dots text-xl"
/>
</div>
<ul className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
setPreservedFormatsModal(true);
// updateArchive();
}}
>
Preserved Formats
</div>
</li>
</ul>
</div>
{preservedFormatsModal ? (
<PreservedFormatsModal
onClose={() => setPreservedFormatsModal(false)}
activeLink={link as any}
/>
) : undefined}
2023-11-19 07:12:37 -06:00
</div>
2023-05-31 09:30:45 -05:00
);
}