From dc9db05e75099787480801a623f5692b6e565fbe Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Mon, 9 Sep 2024 23:05:57 -0400 Subject: [PATCH] fully implemented the custom slider for the number of columns to show --- .../LinkViews/LinkComponents/LinkActions.tsx | 27 ++-- .../LinkViews/LinkComponents/LinkCard.tsx | 49 +++++-- .../LinkViews/LinkComponents/LinkList.tsx | 10 +- .../LinkViews/LinkComponents/LinkMasonry.tsx | 50 ++++--- components/LinkViews/Links.tsx | 130 +++++++++++++++--- components/ReadableView.tsx | 5 +- 6 files changed, 192 insertions(+), 79 deletions(-) diff --git a/components/LinkViews/LinkComponents/LinkActions.tsx b/components/LinkViews/LinkComponents/LinkActions.tsx index 9dfe2b27..65ebf597 100644 --- a/components/LinkViews/LinkComponents/LinkActions.tsx +++ b/components/LinkViews/LinkComponents/LinkActions.tsx @@ -16,17 +16,10 @@ import { useRouter } from "next/router"; type Props = { link: LinkIncludingShortenedCollectionAndTags; collection: CollectionIncludingMembersAndLinkCount; - position?: string; - alignToTop?: boolean; - flipDropdown?: boolean; + className?: string; }; -export default function LinkActions({ - link, - position, - alignToTop, - flipDropdown, -}: Props) { +export default function LinkActions({ link, className }: Props) { const { t } = useTranslation(); const permissions = usePermissions(link.collection.id as number); @@ -92,9 +85,7 @@ export default function LinkActions({ <> {isPublicRoute ? (
  • (columns ? heightMap[columns as keyof typeof heightMap] : "h-40"), + [columns] + ); + const { data: collections = [] } = useCollections(); const { data: user = {} } = useUser(); @@ -134,7 +148,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { return (
    selectable ? handleCheckboxClick(link) @@ -151,14 +165,16 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { > {show.image && (
    -
    +
    {previewAvailable(link) ? ( { @@ -167,9 +183,13 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) { }} /> ) : link.preview === "unavailable" ? ( -
    +
    ) : ( -
    +
    )} {show.icon && (
    @@ -184,7 +204,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
    {show.name && ( -

    +

    {unescapeString(link.name)}

    )} @@ -209,11 +229,14 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
    + {/* Overlay on hover */} +
    ); diff --git a/components/LinkViews/LinkComponents/LinkList.tsx b/components/LinkViews/LinkComponents/LinkList.tsx index 90baa8bc..4433fdc6 100644 --- a/components/LinkViews/LinkComponents/LinkList.tsx +++ b/components/LinkViews/LinkComponents/LinkList.tsx @@ -24,15 +24,10 @@ type Props = { link: LinkIncludingShortenedCollectionAndTags; count: number; className?: string; - flipDropdown?: boolean; editMode?: boolean; }; -export default function LinkCardCompact({ - link, - flipDropdown, - editMode, -}: Props) { +export default function LinkCardCompact({ link, editMode }: Props) { const { t } = useTranslation(); const { data: collections = [] } = useCollections(); @@ -142,8 +137,7 @@ export default function LinkCardCompact({
    diff --git a/components/LinkViews/LinkComponents/LinkMasonry.tsx b/components/LinkViews/LinkComponents/LinkMasonry.tsx index 8da4f255..6e51b641 100644 --- a/components/LinkViews/LinkComponents/LinkMasonry.tsx +++ b/components/LinkViews/LinkComponents/LinkMasonry.tsx @@ -3,7 +3,7 @@ import { CollectionIncludingMembersAndLinkCount, LinkIncludingShortenedCollectionAndTags, } from "@/types/global"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import useLinkStore from "@/store/links"; import unescapeString from "@/lib/client/unescapeString"; import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions"; @@ -27,15 +27,29 @@ import clsx from "clsx"; type Props = { link: LinkIncludingShortenedCollectionAndTags; - count: number; - className?: string; - flipDropdown?: boolean; + columns: number; editMode?: boolean; }; -export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { +export default function LinkMasonry({ link, editMode, columns }: Props) { const { t } = useTranslation(); + const heightMap = { + 1: "h-48", + 2: "h-44", + 3: "h-40", + 4: "h-36", + 5: "h-32", + 6: "h-28", + 7: "h-24", + 8: "h-20", + }; + + const imageHeightClass = useMemo( + () => (columns ? heightMap[columns as keyof typeof heightMap] : "h-40"), + [columns] + ); + const { data: collections = [] } = useCollections(); const { data: user = {} } = useUser(); @@ -126,7 +140,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { return (
    selectable ? handleCheckboxClick(link) @@ -150,7 +164,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { width={1280} height={720} alt="" - className="rounded-t-2xl select-none object-cover z-10 h-40 w-full shadow opacity-80 scale-105" + className={`rounded-t-2xl select-none object-cover z-10 ${imageHeightClass} w-full shadow opacity-80 scale-105`} style={show.icon ? { filter: "blur(1px)" } : undefined} draggable="false" onError={(e) => { @@ -159,7 +173,9 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { }} /> ) : link.preview === "unavailable" ? null : ( -
    +
    )} {show.icon && (
    @@ -174,7 +190,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) {
    {show.name && ( -

    +

    {unescapeString(link.name)}

    )} @@ -182,12 +198,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { {show.link && } {show.description && link.description && ( -

    +

    {unescapeString(link.description)}

    )} @@ -226,15 +237,14 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) { )}
    + {/* Overlay on hover */} +
    ); diff --git a/components/LinkViews/Links.tsx b/components/LinkViews/Links.tsx index c8de1e5d..c0253ed3 100644 --- a/components/LinkViews/Links.tsx +++ b/components/LinkViews/Links.tsx @@ -3,7 +3,7 @@ import { LinkIncludingShortenedCollectionAndTags, ViewMode, } from "@/types/global"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useInView } from "react-intersection-observer"; import LinkMasonry from "@/components/LinkViews/LinkComponents/LinkMasonry"; import Masonry from "react-masonry-css"; @@ -11,6 +11,7 @@ import resolveConfig from "tailwindcss/resolveConfig"; import tailwindConfig from "../../tailwind.config.js"; import { useMemo } from "react"; import LinkList from "@/components/LinkViews/LinkComponents/LinkList"; +import useLocalSettingsStore from "@/store/localSettings"; export function CardView({ links, @@ -27,16 +28,68 @@ export function CardView({ hasNextPage?: boolean; placeHolderRef?: any; }) { + const settings = useLocalSettingsStore((state) => state.settings); + + const gridMap = { + 1: "grid-cols-1", + 2: "grid-cols-2", + 3: "grid-cols-3", + 4: "grid-cols-4", + 5: "grid-cols-5", + 6: "grid-cols-6", + 7: "grid-cols-7", + 8: "grid-cols-8", + }; + + const getColumnCount = () => { + const width = window.innerWidth; + if (width >= 1901) return 5; + if (width >= 1501) return 4; + if (width >= 881) return 3; + if (width >= 551) return 2; + return 1; + }; + + const [columnCount, setColumnCount] = useState( + settings.columns || getColumnCount() + ); + + const gridColClass = useMemo( + () => gridMap[columnCount as keyof typeof gridMap], + [columnCount] + ); + + useEffect(() => { + const handleResize = () => { + if (settings.columns === 0) { + // Only recalculate if zustandColumns is zero + setColumnCount(getColumnCount()); + } + }; + + if (settings.columns === 0) { + window.addEventListener("resize", handleResize); + } + + setColumnCount(settings.columns || getColumnCount()); + + return () => { + if (settings.columns === 0) { + window.removeEventListener("resize", handleResize); + } + }; + }, [settings.columns]); + return ( -
    +
    {links?.map((e, i) => { return ( ); })} @@ -76,6 +129,58 @@ export function MasonryView({ hasNextPage?: boolean; placeHolderRef?: any; }) { + const settings = useLocalSettingsStore((state) => state.settings); + + const gridMap = { + 1: "grid-cols-1", + 2: "grid-cols-2", + 3: "grid-cols-3", + 4: "grid-cols-4", + 5: "grid-cols-5", + 6: "grid-cols-6", + 7: "grid-cols-7", + 8: "grid-cols-8", + }; + + const getColumnCount = () => { + const width = window.innerWidth; + if (width >= 1901) return 5; + if (width >= 1501) return 4; + if (width >= 881) return 3; + if (width >= 551) return 2; + return 1; + }; + + const [columnCount, setColumnCount] = useState( + settings.columns || getColumnCount() + ); + + const gridColClass = useMemo( + () => gridMap[columnCount as keyof typeof gridMap], + [columnCount] + ); + + useEffect(() => { + const handleResize = () => { + if (settings.columns === 0) { + // Only recalculate if zustandColumns is zero + setColumnCount(getColumnCount()); + } + }; + + if (settings.columns === 0) { + window.addEventListener("resize", handleResize); + } + + setColumnCount(settings.columns || getColumnCount()); + + return () => { + if (settings.columns === 0) { + window.removeEventListener("resize", handleResize); + } + }; + }, [settings.columns]); + const fullConfig = resolveConfig(tailwindConfig as any); const breakpointColumnsObj = useMemo(() => { @@ -90,18 +195,19 @@ export function MasonryView({ return ( {links?.map((e, i) => { return ( ); })} @@ -144,15 +250,7 @@ export function ListView({ return (
    {links?.map((e, i) => { - return ( - - ); + return ; })} {(hasNextPage || isLoading) && diff --git a/components/ReadableView.tsx b/components/ReadableView.tsx index 942b66c4..6a4e3429 100644 --- a/components/ReadableView.tsx +++ b/components/ReadableView.tsx @@ -3,7 +3,6 @@ import { readabilityAvailable } from "@/lib/shared/getArchiveValidity"; import isValidUrl from "@/lib/shared/isValidUrl"; import { ArchivedFormat, - CollectionIncludingMembersAndLinkCount, LinkIncludingShortenedCollectionAndTags, } from "@/types/global"; import ColorThief, { RGBColor } from "colorthief"; @@ -11,10 +10,8 @@ import DOMPurify from "dompurify"; import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useEffect, useMemo, useState } from "react"; -import LinkActions from "./LinkViews/LinkComponents/LinkActions"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "next-i18next"; -import { useCollections } from "@/hooks/store/collections"; import { useGetLink } from "@/hooks/store/links"; import { IconWeight } from "@phosphor-icons/react"; import Icon from "./Icon";