From 30ef557f43a027c0d345c5a5f80f44f33ba5d648 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Fri, 26 Apr 2024 12:18:31 -0400 Subject: [PATCH] small improvements --- components/LinkViews/Layouts/GridView.tsx | 16 -- components/LinkViews/Layouts/MasonryView.tsx | 5 +- components/LinkViews/LinkCard.tsx | 60 ++--- components/LinkViews/LinkGrid.tsx | 111 --------- components/LinkViews/LinkMasonry.tsx | 244 +++++++++++++++++++ pages/collections/[id].tsx | 2 - pages/dashboard.tsx | 3 +- pages/links/index.tsx | 2 - pages/links/pinned.tsx | 2 - pages/public/collections/[id].tsx | 2 - pages/search.tsx | 26 +- pages/tags/[id].tsx | 2 - 12 files changed, 289 insertions(+), 186 deletions(-) delete mode 100644 components/LinkViews/Layouts/GridView.tsx delete mode 100644 components/LinkViews/LinkGrid.tsx create mode 100644 components/LinkViews/LinkMasonry.tsx diff --git a/components/LinkViews/Layouts/GridView.tsx b/components/LinkViews/Layouts/GridView.tsx deleted file mode 100644 index 005ba28..0000000 --- a/components/LinkViews/Layouts/GridView.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import LinkGrid from "@/components/LinkViews/LinkGrid"; -import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; - -export default function GridView({ - links, -}: { - links: LinkIncludingShortenedCollectionAndTags[]; -}) { - return ( -
- {links.map((e, i) => { - return ; - })} -
- ); -} diff --git a/components/LinkViews/Layouts/MasonryView.tsx b/components/LinkViews/Layouts/MasonryView.tsx index 1caca9f..9a06a0e 100644 --- a/components/LinkViews/Layouts/MasonryView.tsx +++ b/components/LinkViews/Layouts/MasonryView.tsx @@ -1,4 +1,4 @@ -import LinkCard from "@/components/LinkViews/LinkCard"; +import LinkMasonry from "@/components/LinkViews/LinkMasonry"; import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; import { GridLoader } from "react-spinners"; import Masonry from "react-masonry-css"; @@ -30,12 +30,11 @@ export default function MasonryView({ {links.map((e, i) => { return ( - - {viewMode === "masonry" && !previewAvailable(link) ? null : ( - <> -
- {previewAvailable(link) ? ( - { - const target = e.target as HTMLElement; - target.style.display = "none"; - }} - /> - ) : link.preview === "unavailable" ? ( -
- ) : ( -
- )} -
- -
-
+
+ {previewAvailable(link) ? ( + { + const target = e.target as HTMLElement; + target.style.display = "none"; + }} + /> + ) : link.preview === "unavailable" ? ( +
+ ) : ( +
+ )} +
+ +
+
-
- - )} +

@@ -234,11 +230,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { setShowInfo(!showInfo)} linkInfo={showInfo} flipDropdown={flipDropdown} diff --git a/components/LinkViews/LinkGrid.tsx b/components/LinkViews/LinkGrid.tsx deleted file mode 100644 index be4d6ed..0000000 --- a/components/LinkViews/LinkGrid.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { - CollectionIncludingMembersAndLinkCount, - LinkIncludingShortenedCollectionAndTags, -} from "@/types/global"; -import { useEffect, useState } from "react"; -import useLinkStore from "@/store/links"; -import useCollectionStore from "@/store/collections"; -import unescapeString from "@/lib/client/unescapeString"; -import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions"; -import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate"; -import LinkCollection from "@/components/LinkViews/LinkComponents/LinkCollection"; -import LinkIcon from "@/components/LinkViews/LinkComponents/LinkIcon"; -import Link from "next/link"; - -type Props = { - link: LinkIncludingShortenedCollectionAndTags; - count: number; - className?: string; -}; - -export default function LinkGrid({ link }: Props) { - const { collections } = useCollectionStore(); - - const { links } = useLinkStore(); - - let shortendURL; - - try { - shortendURL = new URL(link.url || "").host.toLowerCase(); - } catch (error) { - console.log(error); - } - - const [collection, setCollection] = - useState( - collections.find( - (e) => e.id === link.collection.id - ) as CollectionIncludingMembersAndLinkCount - ); - - useEffect(() => { - setCollection( - collections.find( - (e) => e.id === link.collection.id - ) as CollectionIncludingMembersAndLinkCount - ); - }, [collections, links]); - - return ( -

-
link.url && window.open(link.url || "", "_blank")} - className="cursor-pointer" - > - -

- {unescapeString(link.name || link.description) || link.url} -

- -
-
- - · - {link.url ? ( -
{ - e.preventDefault(); - window.open(link.url || "", "_blank"); - }} - className="flex items-center hover:opacity-60 cursor-pointer duration-100" - > -

{shortendURL}

-
- ) : ( -
- {link.type} -
- )} -
- -
-

{unescapeString(link.description)}

- {link.tags[0] ? ( -
-
- {link.tags.map((e, i) => ( - { - e.stopPropagation(); - }} - className="btn btn-xs btn-ghost truncate max-w-[19rem]" - > - #{e.name} - - ))} -
-
- ) : undefined} -
- - {}} - linkInfo={false} - link={link} - collection={collection} - /> -
- ); -} diff --git a/components/LinkViews/LinkMasonry.tsx b/components/LinkViews/LinkMasonry.tsx new file mode 100644 index 0000000..62c6cfb --- /dev/null +++ b/components/LinkViews/LinkMasonry.tsx @@ -0,0 +1,244 @@ +import { + ArchivedFormat, + CollectionIncludingMembersAndLinkCount, + LinkIncludingShortenedCollectionAndTags, +} from "@/types/global"; +import { useEffect, useRef, useState } from "react"; +import useLinkStore from "@/store/links"; +import useCollectionStore from "@/store/collections"; +import unescapeString from "@/lib/client/unescapeString"; +import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions"; +import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate"; +import LinkCollection from "@/components/LinkViews/LinkComponents/LinkCollection"; +import Image from "next/image"; +import { previewAvailable } from "@/lib/shared/getArchiveValidity"; +import Link from "next/link"; +import LinkIcon from "./LinkComponents/LinkIcon"; +import useOnScreen from "@/hooks/useOnScreen"; +import { generateLinkHref } from "@/lib/client/generateLinkHref"; +import useAccountStore from "@/store/account"; +import usePermissions from "@/hooks/usePermissions"; +import toast from "react-hot-toast"; +import LinkTypeBadge from "./LinkComponents/LinkTypeBadge"; + +type Props = { + link: LinkIncludingShortenedCollectionAndTags; + count: number; + className?: string; + flipDropdown?: boolean; + editMode?: boolean; +}; + +export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { + const viewMode = localStorage.getItem("viewMode") || "card"; + const { collections } = useCollectionStore(); + const { account } = useAccountStore(); + + const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore(); + + useEffect(() => { + if (!editMode) { + setSelectedLinks([]); + } + }, [editMode]); + + const handleCheckboxClick = ( + link: LinkIncludingShortenedCollectionAndTags + ) => { + if (selectedLinks.includes(link)) { + setSelectedLinks(selectedLinks.filter((e) => e !== link)); + } else { + setSelectedLinks([...selectedLinks, link]); + } + }; + + let shortendURL; + + try { + if (link.url) { + shortendURL = new URL(link.url).host.toLowerCase(); + } + } catch (error) { + console.log(error); + } + + const [collection, setCollection] = + useState( + collections.find( + (e) => e.id === link.collection.id + ) as CollectionIncludingMembersAndLinkCount + ); + + useEffect(() => { + setCollection( + collections.find( + (e) => e.id === link.collection.id + ) as CollectionIncludingMembersAndLinkCount + ); + }, [collections, links]); + + const ref = useRef(null); + const isVisible = useOnScreen(ref); + const permissions = usePermissions(collection?.id as number); + + useEffect(() => { + let interval: any; + + if ( + isVisible && + !link.preview?.startsWith("archives") && + link.preview !== "unavailable" + ) { + interval = setInterval(async () => { + getLink(link.id as number); + }, 5000); + } + + return () => { + if (interval) { + clearInterval(interval); + } + }; + }, [isVisible, link.preview]); + + const [showInfo, setShowInfo] = useState(false); + + const selectedStyle = selectedLinks.some( + (selectedLink) => selectedLink.id === link.id + ) + ? "border-primary bg-base-300" + : "border-neutral-content"; + + const selectable = + editMode && + (permissions === true || permissions?.canCreate || permissions?.canDelete); + + return ( +
+ selectable + ? handleCheckboxClick(link) + : editMode + ? toast.error( + "You don't have permission to edit or delete this item." + ) + : undefined + } + > +
+ !editMode && window.open(generateLinkHref(link, account), "_blank") + } + > +
+ {previewAvailable(link) ? ( + { + const target = e.target as HTMLElement; + target.style.display = "none"; + }} + /> + ) : link.preview === "unavailable" ? null : ( +
+ )} +
+ +
+
+ + {link.preview !== "unavailable" && ( +
+ )} + +
+

+ {unescapeString(link.name || link.description) || link.url} +

+ + +
+ +
+ +
+
+ {collection && ( + + )} +
+ +
+
+ + {showInfo && ( +
+
setShowInfo(!showInfo)} + className=" float-right btn btn-sm outline-none btn-circle btn-ghost z-10" + > + +
+

Description

+ +
+

+ {link.description ? ( + unescapeString(link.description) + ) : ( + + No description provided. + + )} +

+ {link.tags[0] && ( + <> +

Tags

+ +
+ +
+
+ {link.tags.map((e, i) => ( + { + e.stopPropagation(); + }} + className="btn btn-xs btn-ghost truncate max-w-[19rem]" + > + #{e.name} + + ))} +
+
+ + )} +
+ )} + + setShowInfo(!showInfo)} + linkInfo={showInfo} + flipDropdown={flipDropdown} + /> +
+ ); +} diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx index e1ba2b8..046c855 100644 --- a/pages/collections/[id].tsx +++ b/pages/collections/[id].tsx @@ -21,7 +21,6 @@ import EditCollectionSharingModal from "@/components/ModalContent/EditCollection import DeleteCollectionModal from "@/components/ModalContent/DeleteCollectionModal"; import ViewDropdown from "@/components/ViewDropdown"; import CardView from "@/components/LinkViews/Layouts/CardView"; -// import GridView from "@/components/LinkViews/Layouts/GridView"; import ListView from "@/components/LinkViews/Layouts/ListView"; import { dropdownTriggerer } from "@/lib/client/utils"; import NewCollectionModal from "@/components/ModalContent/NewCollectionModal"; @@ -109,7 +108,6 @@ export default function Index() { const linkView = { [ViewMode.Card]: CardView, - // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, [ViewMode.Masonry]: MasonryView, }; diff --git a/pages/dashboard.tsx b/pages/dashboard.tsx index 04882f1..c940b65 100644 --- a/pages/dashboard.tsx +++ b/pages/dashboard.tsx @@ -17,7 +17,6 @@ import ListView from "@/components/LinkViews/Layouts/ListView"; import ViewDropdown from "@/components/ViewDropdown"; import { dropdownTriggerer } from "@/lib/client/utils"; import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; -// import GridView from "@/components/LinkViews/Layouts/GridView"; export default function Dashboard() { const { collections } = useCollectionStore(); @@ -101,7 +100,7 @@ export default function Dashboard() { const linkView = { [ViewMode.Card]: CardView, - // [ViewMode.Grid]: GridView, + // [ViewMode.Grid]: , [ViewMode.List]: ListView, [ViewMode.Masonry]: MasonryView, }; diff --git a/pages/links/index.tsx b/pages/links/index.tsx index 2b1e67b..d617d15 100644 --- a/pages/links/index.tsx +++ b/pages/links/index.tsx @@ -13,7 +13,6 @@ import useCollectivePermissions from "@/hooks/useCollectivePermissions"; import toast from "react-hot-toast"; import BulkDeleteLinksModal from "@/components/ModalContent/BulkDeleteLinksModal"; import BulkEditLinksModal from "@/components/ModalContent/BulkEditLinksModal"; -// import GridView from "@/components/LinkViews/Layouts/GridView"; import { useRouter } from "next/router"; import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; @@ -73,7 +72,6 @@ export default function Links() { const linkView = { [ViewMode.Card]: CardView, - // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, [ViewMode.Masonry]: MasonryView, }; diff --git a/pages/links/pinned.tsx b/pages/links/pinned.tsx index f201844..a56af06 100644 --- a/pages/links/pinned.tsx +++ b/pages/links/pinned.tsx @@ -12,7 +12,6 @@ import BulkDeleteLinksModal from "@/components/ModalContent/BulkDeleteLinksModal import BulkEditLinksModal from "@/components/ModalContent/BulkEditLinksModal"; import useCollectivePermissions from "@/hooks/useCollectivePermissions"; import toast from "react-hot-toast"; -// import GridView from "@/components/LinkViews/Layouts/GridView"; import { useRouter } from "next/router"; import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; @@ -71,7 +70,6 @@ export default function PinnedLinks() { const linkView = { [ViewMode.Card]: CardView, - // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, [ViewMode.Masonry]: MasonryView, }; diff --git a/pages/public/collections/[id].tsx b/pages/public/collections/[id].tsx index c72f0a5..05574a7 100644 --- a/pages/public/collections/[id].tsx +++ b/pages/public/collections/[id].tsx @@ -25,7 +25,6 @@ import ViewDropdown from "@/components/ViewDropdown"; import CardView from "@/components/LinkViews/Layouts/CardView"; import ListView from "@/components/LinkViews/Layouts/ListView"; import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; -// import GridView from "@/components/LinkViews/Layouts/GridView"; const cardVariants: Variants = { offscreen: { @@ -108,7 +107,6 @@ export default function PublicCollections() { const linkView = { [ViewMode.Card]: CardView, - // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, [ViewMode.Masonry]: MasonryView, }; diff --git a/pages/search.tsx b/pages/search.tsx index 9114f41..27e2361 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -8,7 +8,6 @@ import { useRouter } from "next/router"; import React, { useEffect, useState } from "react"; import ViewDropdown from "@/components/ViewDropdown"; import CardView from "@/components/LinkViews/Layouts/CardView"; -// import GridView from "@/components/LinkViews/Layouts/GridView"; import ListView from "@/components/LinkViews/Layouts/ListView"; import PageHeader from "@/components/PageHeader"; import { GridLoader } from "react-spinners"; @@ -19,7 +18,8 @@ import BulkEditLinksModal from "@/components/ModalContent/BulkEditLinksModal"; import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; export default function Search() { - const { links, selectedLinks, setSelectedLinks, deleteLinksById } = useLinkStore(); + const { links, selectedLinks, setSelectedLinks, deleteLinksById } = + useLinkStore(); const router = useRouter(); @@ -59,7 +59,8 @@ export default function Search() { const bulkDeleteLinks = async () => { const load = toast.loading( - `Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" + `Deleting ${selectedLinks.length} Link${ + selectedLinks.length > 1 ? "s" : "" }...` ); @@ -71,7 +72,8 @@ export default function Search() { response.ok && toast.success( - `Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" + `Deleted ${selectedLinks.length} Link${ + selectedLinks.length > 1 ? "s" : "" }!` ); }; @@ -92,7 +94,6 @@ export default function Search() { const linkView = { [ViewMode.Card]: CardView, - // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, [ViewMode.Masonry]: MasonryView, }; @@ -115,10 +116,11 @@ export default function Search() { setEditMode(!editMode); setSelectedLinks([]); }} - className={`btn btn-square btn-sm btn-ghost ${editMode - ? "bg-primary/20 hover:bg-primary/20" - : "hover:bg-neutral/20" - }`} + className={`btn btn-square btn-sm btn-ghost ${ + editMode + ? "bg-primary/20 hover:bg-primary/20" + : "hover:bg-neutral/20" + }`} >
@@ -199,7 +201,11 @@ export default function Search() {

) : links[0] ? ( - + ) : ( isLoading && (