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"