diff --git a/components/LinkViews/Layouts/MasonryView.tsx b/components/LinkViews/Layouts/MasonryView.tsx new file mode 100644 index 0000000..7cd707c --- /dev/null +++ b/components/LinkViews/Layouts/MasonryView.tsx @@ -0,0 +1,40 @@ + +import LinkCard from "@/components/LinkViews/LinkCard"; +import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; +import { GridLoader } from "react-spinners"; +import Masonry from 'react-masonry-css' + +export default function MasonryView({ + links, + editMode, + isLoading, +}: { + links: LinkIncludingShortenedCollectionAndTags[]; + editMode?: boolean; + isLoading?: boolean; +}) { + return ( + + {links.map((e, i) => { + return ( + + ); + })} + + {isLoading && links.length > 0 && ( + + )} + + ); +} diff --git a/components/LinkViews/LinkCard.tsx b/components/LinkViews/LinkCard.tsx index 9299442..5c3417d 100644 --- a/components/LinkViews/LinkCard.tsx +++ b/components/LinkViews/LinkCard.tsx @@ -30,6 +30,7 @@ type Props = { }; export default function LinkCard({ link, flipDropdown, editMode }: Props) { + const viewMode = localStorage.getItem("viewMode") || "card"; const { collections } = useCollectionStore(); const { account } = useAccountStore(); @@ -121,8 +122,8 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { ? handleCheckboxClick(link) : editMode ? toast.error( - "You don't have permission to edit or delete this item." - ) + "You don't have permission to edit or delete this item." + ) : undefined } > @@ -132,32 +133,36 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { !editMode && window.open(generateLinkHref(link, account), "_blank") } > -
- {previewAvailable(link) ? ( - { - const target = e.target as HTMLElement; - target.style.display = "none"; - }} - /> - ) : link.preview === "unavailable" ? ( -
- ) : ( -
- )} -
- -
-
+ {viewMode === 'masonry' && !(previewAvailable(link)) ? null : ( + <> +
+ {previewAvailable(link) ? ( + { + const target = e.target as HTMLElement; + target.style.display = "none"; + }} + /> + ) : link.preview === "unavailable" ? ( +
+ ) : ( +
+ )} +
+ +
+
-
+
+ + )}

@@ -229,7 +234,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { setShowInfo(!showInfo)} linkInfo={showInfo} flipDropdown={flipDropdown} diff --git a/components/ViewDropdown.tsx b/components/ViewDropdown.tsx index 5ab821e..9e5a189 100644 --- a/components/ViewDropdown.tsx +++ b/components/ViewDropdown.tsx @@ -26,22 +26,30 @@ export default function ViewDropdown({ viewMode, setViewMode }: Props) {

+ + diff --git a/package.json b/package.json index a08ae19..cd6c826 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "react-dom": "18.2.0", "react-hot-toast": "^2.4.1", "react-image-file-resizer": "^0.4.8", + "react-masonry-css": "^1.0.16", "react-select": "^5.7.4", "react-spinners": "^0.13.8", "socks-proxy-agent": "^8.0.2", diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx index 92456a7..3a23940 100644 --- a/pages/collections/[id].tsx +++ b/pages/collections/[id].tsx @@ -28,6 +28,7 @@ import NewCollectionModal from "@/components/ModalContent/NewCollectionModal"; import BulkDeleteLinksModal from "@/components/ModalContent/BulkDeleteLinksModal"; import toast from "react-hot-toast"; import BulkEditLinksModal from "@/components/ModalContent/BulkEditLinksModal"; +import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; export default function Index() { const { settings } = useLocalSettingsStore(); @@ -110,6 +111,7 @@ export default function Index() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore @@ -125,8 +127,7 @@ export default function Index() { const bulkDeleteLinks = async () => { const load = toast.loading( - `Deleting ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }...` ); @@ -138,8 +139,7 @@ export default function Index() { response.ok && toast.success( - `Deleted ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }!` ); }; @@ -149,9 +149,8 @@ export default function Index() {
{activeCollection && ( @@ -326,11 +325,10 @@ export default function Index() { setEditMode(!editMode); setSelectedLinks([]); }} - className={`btn btn-square btn-sm btn-ghost ${ - editMode + className={`btn btn-square btn-sm btn-ghost ${editMode ? "bg-primary/20 hover:bg-primary/20" : "hover:bg-neutral/20" - }`} + }`} >
diff --git a/pages/dashboard.tsx b/pages/dashboard.tsx index 6fabf33..04882f1 100644 --- a/pages/dashboard.tsx +++ b/pages/dashboard.tsx @@ -16,6 +16,7 @@ import CardView from "@/components/LinkViews/Layouts/CardView"; 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() { @@ -102,6 +103,7 @@ export default function Dashboard() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore diff --git a/pages/links/index.tsx b/pages/links/index.tsx index b6b67c3..949f6be 100644 --- a/pages/links/index.tsx +++ b/pages/links/index.tsx @@ -15,6 +15,7 @@ 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"; export default function Links() { const { links, selectedLinks, deleteLinksById, setSelectedLinks } = @@ -51,8 +52,7 @@ export default function Links() { const bulkDeleteLinks = async () => { const load = toast.loading( - `Deleting ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }...` ); @@ -64,8 +64,7 @@ export default function Links() { response.ok && toast.success( - `Deleted ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }!` ); }; @@ -74,6 +73,7 @@ export default function Links() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore @@ -97,11 +97,10 @@ export default function Links() { setEditMode(!editMode); setSelectedLinks([]); }} - className={`btn btn-square btn-sm btn-ghost ${ - editMode + className={`btn btn-square btn-sm btn-ghost ${editMode ? "bg-primary/20 hover:bg-primary/20" : "hover:bg-neutral/20" - }`} + }`} >
diff --git a/pages/links/pinned.tsx b/pages/links/pinned.tsx index ecdec4e..5e53886 100644 --- a/pages/links/pinned.tsx +++ b/pages/links/pinned.tsx @@ -14,6 +14,7 @@ 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"; export default function PinnedLinks() { const { links, selectedLinks, deleteLinksById, setSelectedLinks } = @@ -49,8 +50,7 @@ export default function PinnedLinks() { const bulkDeleteLinks = async () => { const load = toast.loading( - `Deleting ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }...` ); @@ -62,8 +62,7 @@ export default function PinnedLinks() { response.ok && toast.success( - `Deleted ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }!` ); }; @@ -72,6 +71,7 @@ export default function PinnedLinks() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore @@ -94,11 +94,10 @@ export default function PinnedLinks() { setEditMode(!editMode); setSelectedLinks([]); }} - className={`btn btn-square btn-sm btn-ghost ${ - editMode + className={`btn btn-square btn-sm btn-ghost ${editMode ? "bg-primary/20 hover:bg-primary/20" : "hover:bg-neutral/20" - }`} + }`} >
diff --git a/pages/public/collections/[id].tsx b/pages/public/collections/[id].tsx index d918086..c72f0a5 100644 --- a/pages/public/collections/[id].tsx +++ b/pages/public/collections/[id].tsx @@ -24,6 +24,7 @@ import EditCollectionSharingModal from "@/components/ModalContent/EditCollection 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 = { @@ -109,6 +110,7 @@ export default function PublicCollections() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore @@ -118,9 +120,8 @@ export default function PublicCollections() {
{collection ? ( diff --git a/pages/search.tsx b/pages/search.tsx index f89c799..3e4ce49 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -12,6 +12,7 @@ import CardView from "@/components/LinkViews/Layouts/CardView"; import ListView from "@/components/LinkViews/Layouts/ListView"; import PageHeader from "@/components/PageHeader"; import { GridLoader, PropagateLoader } from "react-spinners"; +import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; export default function Search() { const { links } = useLinkStore(); @@ -49,6 +50,7 @@ export default function Search() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore diff --git a/pages/tags/[id].tsx b/pages/tags/[id].tsx index 34d172f..1b286c8 100644 --- a/pages/tags/[id].tsx +++ b/pages/tags/[id].tsx @@ -15,6 +15,7 @@ import { dropdownTriggerer } from "@/lib/client/utils"; import BulkDeleteLinksModal from "@/components/ModalContent/BulkDeleteLinksModal"; import BulkEditLinksModal from "@/components/ModalContent/BulkEditLinksModal"; import useCollectivePermissions from "@/hooks/useCollectivePermissions"; +import MasonryView from "@/components/LinkViews/Layouts/MasonryView"; export default function Index() { const router = useRouter(); @@ -124,8 +125,7 @@ export default function Index() { const bulkDeleteLinks = async () => { const load = toast.loading( - `Deleting ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }...` ); @@ -137,8 +137,7 @@ export default function Index() { response.ok && toast.success( - `Deleted ${selectedLinks.length} Link${ - selectedLinks.length > 1 ? "s" : "" + `Deleted ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : "" }!` ); }; @@ -151,6 +150,7 @@ export default function Index() { [ViewMode.Card]: CardView, // [ViewMode.Grid]: GridView, [ViewMode.List]: ListView, + [ViewMode.Masonry]: MasonryView, }; // @ts-ignore @@ -197,11 +197,10 @@ export default function Index() {

8 + className={`dropdown dropdown-bottom font-normal ${activeTag?.name.length && activeTag?.name.length > 8 ? "dropdown-end" : "" - }`} + }`} >
diff --git a/types/global.ts b/types/global.ts index b347659..cc171f2 100644 --- a/types/global.ts +++ b/types/global.ts @@ -68,6 +68,7 @@ export enum ViewMode { Card = "card", Grid = "grid", List = "list", + Masonry = "masonry", } export enum Sort { diff --git a/yarn.lock b/yarn.lock index d016ae9..14c49ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5165,6 +5165,11 @@ react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-masonry-css@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/react-masonry-css/-/react-masonry-css-1.0.16.tgz#72b28b4ae3484e250534700860597553a10f1a2c" + integrity sha512-KSW0hR2VQmltt/qAa3eXOctQDyOu7+ZBevtKgpNDSzT7k5LA/0XntNa9z9HKCdz3QlxmJHglTZ18e4sX4V8zZQ== + react-redux@^7.0.3: version "7.2.9" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d"