diff --git a/packages/fakeyou.com/package.json b/packages/fakeyou.com/package.json index 38e9a327c2..d90a3807e1 100644 --- a/packages/fakeyou.com/package.json +++ b/packages/fakeyou.com/package.json @@ -15,6 +15,7 @@ "@fortawesome/pro-regular-svg-icons": "^6.2.1", "@fortawesome/pro-solid-svg-icons": "^6.2.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@react-spring/types": "^9.7.3", "@react-spring/web": "^9.7.3", "@storyteller/components": "0.1.0", "@testing-library/jest-dom": "^4.2.4", @@ -26,8 +27,11 @@ "@types/google.analytics": "^0.0.42", "@types/gtag.js": "^0.0.12", "@types/howler": "^2.1.2", + "@types/imagesloaded": "^4.1.6", + "@types/infinite-scroll": "^4.0.3", "@types/jest": "^24.9.1", "@types/js-cookie": "^3.0.1", + "@types/masonry-layout": "^4.2.7", "@types/node": "^12.12.47", "@types/react": "^16.9.36", "@types/react-dom": "^16.9.8", @@ -42,7 +46,10 @@ "i18next": "^21.6.11", "i18next-browser-languagedetector": "^7.1.0", "i18next-http-backend": "^2.2.1", + "imagesloaded": "^5.0.0", + "infinite-scroll": "^4.0.1", "js-cookie": "^3.0.1", + "masonry-layout": "^4.2.2", "posthog-js": "^1.73.1", "pretty-num": "^0.5.2", "query-string": "^8.1.0", @@ -52,6 +59,7 @@ "react-dom": "^16.13.1", "react-drag-drop-files": "^2.3.9", "react-i18next": "^11.15.4", + "react-infinite-scroll-component": "^6.1.0", "react-range": "^1.8.14", "react-reveal": "^1.2.2", "react-router-dom": "^5.2.0", @@ -62,6 +70,7 @@ "react-wavesurfer.js": "^0.0.8", "sass": "^1.57.1", "typescript": "^3.7.5", + "universal-cookie": "^6.1.1", "uuid": "^8.3.2", "wavesurfer.js": "^6.4.0", "zustand": "^4.3.9" diff --git a/packages/fakeyou.com/public/images/dummy-image-2.jpg b/packages/fakeyou.com/public/images/dummy-image-2.jpg new file mode 100644 index 0000000000..47091841dd Binary files /dev/null and b/packages/fakeyou.com/public/images/dummy-image-2.jpg differ diff --git a/packages/fakeyou.com/public/images/dummy-image-3.jpg b/packages/fakeyou.com/public/images/dummy-image-3.jpg new file mode 100644 index 0000000000..95281df66f Binary files /dev/null and b/packages/fakeyou.com/public/images/dummy-image-3.jpg differ diff --git a/packages/fakeyou.com/public/images/dummy-image-4.jpg b/packages/fakeyou.com/public/images/dummy-image-4.jpg new file mode 100644 index 0000000000..303935dfb3 Binary files /dev/null and b/packages/fakeyou.com/public/images/dummy-image-4.jpg differ diff --git a/packages/fakeyou.com/public/images/dummy-image.jpg b/packages/fakeyou.com/public/images/dummy-image.jpg new file mode 100644 index 0000000000..78a9d69837 Binary files /dev/null and b/packages/fakeyou.com/public/images/dummy-image.jpg differ diff --git a/packages/fakeyou.com/public/images/dummy-video.jpg b/packages/fakeyou.com/public/images/dummy-video.jpg new file mode 100644 index 0000000000..5f59215ce1 Binary files /dev/null and b/packages/fakeyou.com/public/images/dummy-video.jpg differ diff --git a/packages/fakeyou.com/src/components/common/AudioPlayer/AudioPlayer.scss b/packages/fakeyou.com/src/components/common/AudioPlayer/AudioPlayer.scss new file mode 100644 index 0000000000..9fe0d9698b --- /dev/null +++ b/packages/fakeyou.com/src/components/common/AudioPlayer/AudioPlayer.scss @@ -0,0 +1,3 @@ +wave { + z-index: 2; +} diff --git a/packages/fakeyou.com/src/components/common/AudioPlayer/AudioPlayer.tsx b/packages/fakeyou.com/src/components/common/AudioPlayer/AudioPlayer.tsx new file mode 100644 index 0000000000..70237fbfb3 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/AudioPlayer/AudioPlayer.tsx @@ -0,0 +1,98 @@ +import React, { useEffect, useState, useRef } from "react"; +import WaveSurfer from "wavesurfer.js"; +import { BucketConfig } from "@storyteller/components/src/api/BucketConfig"; +import { faPlay, faPause } from "@fortawesome/pro-solid-svg-icons"; +import Button from "components/common/Button"; +import "./AudioPlayer.scss"; +import { useAudioPlayerContext } from "./AudioPlayerContext"; +import useOnScreen from "hooks/useOnScreen"; + +interface AudioPlayerProps { + src: string; + id: string; +} + +export default function AudioPlayer({ src, id }: AudioPlayerProps) { + const { currentPlayingId, setCurrentPlayingId } = useAudioPlayerContext(); + const [isPlaying, setIsPlaying] = useState(false); + const waveformRef = useRef(null); + const waveSurferRef = useRef(null); + const isPlayerOnScreen = useOnScreen(waveformRef); //This stops the audio from playing when the player is not on screen + + useEffect(() => { + const audioLink = new BucketConfig().getGcsUrl(src); + + if (!waveSurferRef.current && waveformRef.current) { + const wavesurferInstance = WaveSurfer.create({ + container: waveformRef.current, + height: 38, + responsive: true, + waveColor: "#cbcbcb", + progressColor: "#fc8481", + cursorColor: "#fc6b68", + cursorWidth: 2, + normalize: true, + }); + + waveSurferRef.current = wavesurferInstance; + + waveSurferRef.current.load(audioLink); + + waveSurferRef.current.on("pause", () => { + setIsPlaying(false); + }); + + waveSurferRef.current.on("play", () => { + setIsPlaying(true); + setCurrentPlayingId(id); + }); + + waveSurferRef.current.on("finish", () => { + waveSurferRef.current?.pause(); + }); + } + + return () => { + // Cleanup when component unmounts + if (waveSurferRef.current) { + waveSurferRef.current.destroy(); + } + }; + }, [src, setCurrentPlayingId, id]); + + useEffect(() => { + if (currentPlayingId !== id && isPlaying) { + setIsPlaying(false); + waveSurferRef.current?.pause(); + } + }, [currentPlayingId, id, isPlaying]); + + useEffect(() => { + if (!isPlayerOnScreen && isPlaying) { + waveSurferRef.current?.pause(); + } + }, [isPlayerOnScreen, isPlaying]); + + const togglePlayPause = () => { + if (waveSurferRef.current) { + if (!isPlaying) { + setCurrentPlayingId(id); + } + waveSurferRef.current.playPause(); + } + }; + + const playButtonIcon = isPlaying ? faPause : faPlay; + + return ( +
+
+ + + + )} + + ); +} diff --git a/packages/fakeyou.com/src/components/common/Card/AudioCard/index.ts b/packages/fakeyou.com/src/components/common/Card/AudioCard/index.ts new file mode 100644 index 0000000000..4eed59149f --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/AudioCard/index.ts @@ -0,0 +1 @@ +export { default } from "./AudioCard"; diff --git a/packages/fakeyou.com/src/components/common/Card/Card.scss b/packages/fakeyou.com/src/components/common/Card/Card.scss new file mode 100644 index 0000000000..d5c08790b7 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/Card.scss @@ -0,0 +1,85 @@ +@import "scss/colours.scss"; + +.card { + background-color: $panel-inner; + border: 1px solid $panel-inner-border; + border-radius: 0.5rem; + overflow: hidden; + transition: 0.2s; + position: relative; + + .card-img { + width: 100%; + transition: 0.4s ease; + object-fit: cover; + object-position: center; + min-height: 300px; + max-height: 500px; + } + + .card-video { + width: 100%; + transition: 0.4s ease; + object-fit: cover; + object-position: center; + min-height: 240px; + max-height: 240px; + } + + .card-img-overlay { + position: absolute; + bottom: 0; + left: 0; + height: 100%; + width: 100%; + } + + .card-video-play { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 50px; + color: rgba($white, 0.5); + transition: 0.2s; + } + + .card-img-gradient { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 40%; + background: linear-gradient(180deg, transparent, darken($bg, 5%)); + } + + .card-img-overlay-text { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 1rem; + color: $white; + text-shadow: 0 0 10px black; + } + + &.card-clickable { + &:hover { + background-color: lighten($panel-inner, 2%); + cursor: pointer; + border: 1px solid lighten($panel-inner-border, 15%); + } + + &:hover > .card-img { + transform: scale(1.05); + } + + &:hover > .card-video { + transform: scale(1.05); + } + + &:hover .card-video-play { + color: rgba($white, 0.8); + } + } +} diff --git a/packages/fakeyou.com/src/components/common/Card/Card.tsx b/packages/fakeyou.com/src/components/common/Card/Card.tsx new file mode 100644 index 0000000000..fe2a469774 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/Card.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import "./Card.scss"; + +interface CardProps { + padding?: boolean; + children?: React.ReactNode; + onClick?: () => void; +} + +export default function Card({ padding, children, onClick }: CardProps) { + return ( +
+ {children} +
+ ); +} diff --git a/packages/fakeyou.com/src/components/common/Card/ImageCard/ImageCard.tsx b/packages/fakeyou.com/src/components/common/Card/ImageCard/ImageCard.tsx new file mode 100644 index 0000000000..9c1b14d01e --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/ImageCard/ImageCard.tsx @@ -0,0 +1,111 @@ +import React from "react"; +import { useHistory } from "react-router-dom"; +import Card from "../Card"; +import useTimeAgo from "hooks/useTimeAgo"; +import Badge from "components/common/Badge"; +import LikeButton from "components/common/LikeButton"; +import Button from "components/common/Button"; +import FavoriteButton from "components/common/FavoriteButton"; + +interface ImageCardProps { + data: any; + type: "media" | "weights"; +} + +export default function ImageCard({ data, type }: ImageCardProps) { + const history = useHistory(); + + const handleCardClick = () => { + if (type === "media") { + history.push(`/media/${data.token}`); + } else if (type === "weights") { + history.push(`/weights/${data.token}`); + } + }; + + const handleInnerClick = (event: any) => { + event.stopPropagation(); + }; + + const timeAgo = useTimeAgo(data.created_at); + + const handleLike = async (data: any) => { + console.log(`The item is now ${data.isLiked ? "liked" : "not liked"}.`); + }; + + return ( + + {type === "media" && ( + <> + {data.weight_name} +
+
+ +
+
+ +
+
+ +
+
+

{timeAgo}

+
+
+ +
+
+
+ + )} + + {type === "weights" && ( + <> + {data.weight_name} +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ {data.weight_name} +
+

{timeAgo}

+
+
+
+
+
+
+ + )} + + ); +} diff --git a/packages/fakeyou.com/src/components/common/Card/ImageCard/index.ts b/packages/fakeyou.com/src/components/common/Card/ImageCard/index.ts new file mode 100644 index 0000000000..e9972abd5b --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/ImageCard/index.ts @@ -0,0 +1 @@ +export { default } from "./ImageCard"; diff --git a/packages/fakeyou.com/src/components/common/Card/SkeletonCard/SkeletonCard.tsx b/packages/fakeyou.com/src/components/common/Card/SkeletonCard/SkeletonCard.tsx new file mode 100644 index 0000000000..e622773985 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/SkeletonCard/SkeletonCard.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import Card from "../Card"; +import Skeleton from "components/common/Skeleton"; + +interface SkeletonCardProps {} + +export default function SkeletonCard(props: SkeletonCardProps) { + return ( +
+ +
+
+
+ +
+
+ +
+
+ +
+ +
+

+ +

+
+ +
+

+ +

+
+
+
+ ); +} diff --git a/packages/fakeyou.com/src/components/common/Card/SkeletonCard/index.ts b/packages/fakeyou.com/src/components/common/Card/SkeletonCard/index.ts new file mode 100644 index 0000000000..7a1d781a94 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/SkeletonCard/index.ts @@ -0,0 +1 @@ +export { default } from "./SkeletonCard"; diff --git a/packages/fakeyou.com/src/components/common/Card/VideoCard/VideoCard.tsx b/packages/fakeyou.com/src/components/common/Card/VideoCard/VideoCard.tsx new file mode 100644 index 0000000000..e478fe27c2 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/VideoCard/VideoCard.tsx @@ -0,0 +1,105 @@ +import React from "react"; +import { useHistory } from "react-router-dom"; +import Card from "../Card"; +import useTimeAgo from "hooks/useTimeAgo"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faPlayCircle } from "@fortawesome/pro-solid-svg-icons"; +import Badge from "components/common/Badge"; +import LikeButton from "components/common/LikeButton"; + +interface VideoCardProps { + data: any; + type: "media" | "weights"; +} + +export default function VideoCard({ data, type }: VideoCardProps) { + const history = useHistory(); + + const handleCardClick = () => { + history.push(`/media/${data.token}`); + }; + + const handleInnerClick = (event: any) => { + event.stopPropagation(); + }; + + const timeAgo = useTimeAgo(data.created_at); + + const handleLike = async (data: any) => { + console.log(`The item is now ${data.isLiked ? "liked" : "not liked"}.`); + }; + + return ( + + {type === "media" && ( + <> + {data.weight_name} +
+
+ +
+
+ +
+
+ +
+
+
+ {data.weight_name} +
+

{timeAgo}

+
+ +
+
+
+
+ + )} + + {type === "weights" && ( + <> + {data.weight_name} +
+
+ +
+
+ +
+
+ +
+
+
+ {data.weight_name} +
+

{timeAgo}

+
+ +
+
+
+
+ + )} + + ); +} diff --git a/packages/fakeyou.com/src/components/common/Card/VideoCard/index.ts b/packages/fakeyou.com/src/components/common/Card/VideoCard/index.ts new file mode 100644 index 0000000000..1e794a9789 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/VideoCard/index.ts @@ -0,0 +1 @@ +export { default } from "./VideoCard"; diff --git a/packages/fakeyou.com/src/components/common/Card/index.ts b/packages/fakeyou.com/src/components/common/Card/index.ts new file mode 100644 index 0000000000..c0424cdb70 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Card/index.ts @@ -0,0 +1 @@ +export { default } from "./Card"; diff --git a/packages/fakeyou.com/src/components/common/FavoriteButton/FavoriteButton.scss b/packages/fakeyou.com/src/components/common/FavoriteButton/FavoriteButton.scss new file mode 100644 index 0000000000..3dcd92c1d4 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/FavoriteButton/FavoriteButton.scss @@ -0,0 +1,83 @@ +@import "scss/colours.scss"; + +.favorite-button { + display: flex; + align-items: center; + background-color: rgba(lighten($secondary, 5%), 0.9); + color: inherit; + border: none; + padding: 0; + font: inherit; + cursor: pointer; + outline: inherit; + font-size: 16px; + transition: 0.2s; + padding: 3px 8px; + border-radius: 0.5rem; + + &.shadow { + box-shadow: 0 0 12px rgba($bg, 0.4) !important; + + &:hover { + box-shadow: 0 0 12px rgba($bg, 0.4) !important; + } + } + + &:hover { + background: rgba(lighten($secondary, 10%), 0.9); + } + + &:hover .favorite-number { + opacity: 1; + } + + &:hover .icon-default { + color: map-get($badge-colors, "yellow"); + opacity: 1; + } + + &.toggled { + background-color: darken(rgba(map-get($badge-colors, "yellow"), 0.9), 32%); + + &:hover { + background-color: darken( + rgba(map-get($badge-colors, "yellow"), 0.9), + 25% + ); + } + } +} + +.favorite-button .icon-default { + color: $white; + opacity: 0.7; + transition: 0.2s; +} + +.favorite-button .icon-toggled { + color: map-get($badge-colors, "yellow"); + animation: pulse 0.3s ease; +} + +.favorite-button .icon-toggled:hover { + color: map-get($badge-colors, "yellow"); +} + +.favorite-number { + font-size: 14px; + font-weight: 400 !important; + opacity: 0.8; + transition: 0.2s; +} + +@keyframes pulse { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.3); + } + 100% { + transform: scale(1); + } +} diff --git a/packages/fakeyou.com/src/components/common/FavoriteButton/FavoriteButton.tsx b/packages/fakeyou.com/src/components/common/FavoriteButton/FavoriteButton.tsx new file mode 100644 index 0000000000..53ff39e4d4 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/FavoriteButton/FavoriteButton.tsx @@ -0,0 +1,66 @@ +import React, { useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faBookmark } from "@fortawesome/pro-solid-svg-icons"; +import { faBookmark as faBookmarkOutline } from "@fortawesome/pro-regular-svg-icons"; +import Tippy from "@tippyjs/react"; +import "tippy.js/dist/tippy.css"; +import "./FavoriteButton.scss"; + +interface FavoriteButtonProps { + initialToggled?: boolean; + onToggle: (toggled: boolean) => Promise; + favoriteCount?: number; + overlay?: boolean; +} + +export default function FavoriteButton({ + initialToggled = false, + onToggle, + favoriteCount, + overlay, +}: FavoriteButtonProps) { + const [isToggled, setIsToggled] = useState(initialToggled); + const [isLoading, setIsLoading] = useState(false); + + const handleClick = async () => { + setIsLoading(true); + try { + await onToggle(!isToggled); + setIsToggled(!isToggled); + } catch (error) { + console.error("Error calling API", error); + } finally { + setIsLoading(false); + } + }; + + const buttonClass = isToggled ? "favorite-button toggled" : "favorite-button"; + const buttonShadow = overlay ? "shadow" : ""; + const iconClass = isToggled ? "icon-toggled" : "icon-default"; + const toolTip = isToggled ? "Unfavorite" : "Favorite"; + + return ( +
+ + + +
+ ); +} diff --git a/packages/fakeyou.com/src/components/common/FavoriteButton/index.ts b/packages/fakeyou.com/src/components/common/FavoriteButton/index.ts new file mode 100644 index 0000000000..7b32c1adad --- /dev/null +++ b/packages/fakeyou.com/src/components/common/FavoriteButton/index.ts @@ -0,0 +1 @@ +export { default } from "./FavoriteButton"; diff --git a/packages/fakeyou.com/src/components/common/LikeButton/LikeButton.scss b/packages/fakeyou.com/src/components/common/LikeButton/LikeButton.scss new file mode 100644 index 0000000000..d5649adddd --- /dev/null +++ b/packages/fakeyou.com/src/components/common/LikeButton/LikeButton.scss @@ -0,0 +1,80 @@ +@import "scss/colours.scss"; + +.like-button { + display: flex; + align-items: center; + background-color: rgba(lighten($secondary, 5%), 0.9); + color: inherit; + border: none; + padding: 0; + font: inherit; + cursor: pointer; + outline: inherit; + font-size: 16px; + transition: 0.2s; + padding: 3px 8px; + border-radius: 0.5rem; + + &.shadow { + box-shadow: 0 0 12px rgba($bg, 0.4) !important; + + &:hover { + box-shadow: 0 0 12px rgba($bg, 0.4) !important; + } + } + + &:hover { + background: rgba(lighten($secondary, 10%), 0.9); + } + + &:hover .like-number { + opacity: 1; + } + + &:hover .icon-default { + color: $primary; + opacity: 1; + } + + &.toggled { + background-color: rgba(#593a48, 0.9); + + &:hover { + background-color: darken(rgba(#593a48, 0.9), 2%); + } + } +} + +.like-button .icon-default { + color: $white; + opacity: 0.7; + transition: 0.2s; +} + +.like-button .icon-toggled { + color: $primary; + animation: pulse 0.3s ease; +} + +.like-button .icon-toggled:hover { + color: $primary; +} + +.like-number { + font-size: 14px; + font-weight: 400 !important; + opacity: 0.8; + transition: 0.2s; +} + +@keyframes pulse { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.3); + } + 100% { + transform: scale(1); + } +} diff --git a/packages/fakeyou.com/src/components/common/LikeButton/LikeButton.tsx b/packages/fakeyou.com/src/components/common/LikeButton/LikeButton.tsx new file mode 100644 index 0000000000..10ffb1cc0f --- /dev/null +++ b/packages/fakeyou.com/src/components/common/LikeButton/LikeButton.tsx @@ -0,0 +1,67 @@ +import React, { useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faHeart } from "@fortawesome/pro-solid-svg-icons"; +import { faHeart as faHeartOutline } from "@fortawesome/pro-regular-svg-icons"; +import Tippy from "@tippyjs/react"; +import "tippy.js/dist/tippy.css"; +import "./LikeButton.scss"; + +interface LikeButtonProps { + initialToggled?: boolean; + onToggle: (toggled: boolean) => Promise; + likeCount?: number; + overlay?: boolean; +} + +export default function LikeButton({ + initialToggled = false, + onToggle, + likeCount, + overlay, +}: LikeButtonProps) { + const [isToggled, setIsToggled] = useState(initialToggled); + const [isLoading, setIsLoading] = useState(false); + + const handleClick = async () => { + setIsLoading(true); + try { + await onToggle(!isToggled); + setIsToggled(!isToggled); + } catch (error) { + console.error("Error calling API", error); + } finally { + setIsLoading(false); + } + }; + + const buttonClass = isToggled ? "like-button toggled" : "like-button"; + const buttonShadow = overlay ? "shadow" : ""; + const iconClass = isToggled ? "icon-toggled" : "icon-default"; + const toolTip = isToggled ? "Unlike" : "Like"; + + return ( +
+ + + +
+ ); +} diff --git a/packages/fakeyou.com/src/components/common/LikeButton/index.ts b/packages/fakeyou.com/src/components/common/LikeButton/index.ts new file mode 100644 index 0000000000..b2a047a3bd --- /dev/null +++ b/packages/fakeyou.com/src/components/common/LikeButton/index.ts @@ -0,0 +1 @@ +export { default } from "./LikeButton"; diff --git a/packages/fakeyou.com/src/components/common/MasonryGrid/MasonryGrid.tsx b/packages/fakeyou.com/src/components/common/MasonryGrid/MasonryGrid.tsx new file mode 100644 index 0000000000..df2b4e27a7 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/MasonryGrid/MasonryGrid.tsx @@ -0,0 +1,56 @@ +import Masonry from "masonry-layout"; //Refer to: https://github.com/desandro/masonry +import imagesLoaded from "imagesloaded"; //Refer to: https://github.com/desandro/imagesloaded +import React, { useEffect } from "react"; + +interface MasonryGridProps { + children: React.ReactNode; + onLayoutComplete?: () => void; + gridRef: React.RefObject; +} + +export default function MasonryGrid({ + children, + onLayoutComplete, + gridRef, +}: MasonryGridProps) { + useEffect(() => { + let masonryInstance: Masonry | null = null; + + const updateLayout = () => { + //Needs this type guard to check that it is not undefined. + if (masonryInstance && typeof masonryInstance.layout === "function") { + masonryInstance.layout(); + } + }; + + if (gridRef.current) { + masonryInstance = new Masonry(gridRef.current, { + itemSelector: ".grid-item", + percentPosition: true, + }); + + //Needs this or images will overflow masonry card. It checks if image is loaded then after it is loaded, it resizes the card. + imagesLoaded(gridRef.current, function () { + updateLayout(); + onLayoutComplete?.(); + }); + } + + //Clean up + return () => { + if (masonryInstance && typeof masonryInstance.destroy === "function") { + masonryInstance.destroy(); + } + }; + }, [gridRef, onLayoutComplete]); + + return ( +
+ {children} +
+ ); +} diff --git a/packages/fakeyou.com/src/components/common/Panel/Panel.tsx b/packages/fakeyou.com/src/components/common/Panel/Panel.tsx index a32bed8dc1..6fec83c458 100644 --- a/packages/fakeyou.com/src/components/common/Panel/Panel.tsx +++ b/packages/fakeyou.com/src/components/common/Panel/Panel.tsx @@ -19,7 +19,7 @@ export default function Panel({ }: PanelProps) { return (
void }) { + return ( +
  • + + {icon && } + {label} + +
  • + ); +} + +function TabContent({ children }: TabContentProps) { + return
    {children}
    ; +} + +function Tabs({ tabs }: TabsProps) { + const location = useLocation(); + const currentPath = location.pathname; + const initialTab = tabs.find((tab) => tab.to === currentPath) || tabs[0]; + const [activeTab, setActiveTab] = useState(initialTab.to); + + const [fade, setFade] = useSpring(() => ({ + opacity: 1, + from: { opacity: 0 }, + config: { duration: 50 }, + })); + + useEffect(() => { + setFade({ opacity: 1 }); + }, [activeTab, setFade]); + + useEffect(() => { + setActiveTab(currentPath); + }, [currentPath]); + + const handleTabClick = (tabTo: string) => { + if (activeTab === tabTo) { + return; + } + setFade({ opacity: 0 }); + setTimeout(() => setActiveTab(tabTo), 50); + }; + + return ( + + ); +} + +export default Tabs; diff --git a/packages/fakeyou.com/src/components/common/Tabs/index.ts b/packages/fakeyou.com/src/components/common/Tabs/index.ts new file mode 100644 index 0000000000..9a31da7f16 --- /dev/null +++ b/packages/fakeyou.com/src/components/common/Tabs/index.ts @@ -0,0 +1 @@ +export { default } from "./Tabs"; diff --git a/packages/fakeyou.com/src/hooks/useOnScreen/index.ts b/packages/fakeyou.com/src/hooks/useOnScreen/index.ts new file mode 100644 index 0000000000..f8c8a7bd10 --- /dev/null +++ b/packages/fakeyou.com/src/hooks/useOnScreen/index.ts @@ -0,0 +1 @@ +export { default } from "./useOnScreen"; diff --git a/packages/fakeyou.com/src/hooks/useOnScreen/useOnScreen.tsx b/packages/fakeyou.com/src/hooks/useOnScreen/useOnScreen.tsx new file mode 100644 index 0000000000..4a66f87bf8 --- /dev/null +++ b/packages/fakeyou.com/src/hooks/useOnScreen/useOnScreen.tsx @@ -0,0 +1,35 @@ +import { useEffect, useState, RefObject } from "react"; + +const useOnScreen = ( + ref: RefObject, + rootMargin: string = "0px" +) => { + const [isIntersecting, setIntersecting] = useState(false); + + useEffect(() => { + const currentRef = ref.current; + + const observer = new IntersectionObserver( + ([entry]) => { + setIntersecting(entry.isIntersecting); + }, + { + rootMargin, + } + ); + + if (currentRef) { + observer.observe(currentRef); + } + + return () => { + if (currentRef) { + observer.unobserve(currentRef); + } + }; + }, [ref, rootMargin]); + + return isIntersecting; +}; + +export default useOnScreen; diff --git a/packages/fakeyou.com/src/scss/colours.scss b/packages/fakeyou.com/src/scss/colours.scss index f3ab02955b..7770768e10 100644 --- a/packages/fakeyou.com/src/scss/colours.scss +++ b/packages/fakeyou.com/src/scss/colours.scss @@ -2,7 +2,6 @@ $primary: #e66462; $secondary: #39394c; $bg: #1a1a27; -$panel: #242433; $input: #39394c; $input-placeholder: #aeaeb3; $danger: #8f4951; @@ -12,8 +11,9 @@ $success: #40ad48; $warning: darken(#f7941c, 5%); $accent: #80cfd3; $workflow: $primary; - -// Light mode colours +$panel: #242433; +$panel-inner: lighten($panel, 4%); +$panel-inner-border: lighten($panel, 8%); $primary-lm: #000; @@ -59,3 +59,19 @@ $danger-dark: darken($danger, 10%); $accent-light: desaturate(lighten($accent, 20%), 15%); $accent-dark: saturate(darken($accent, 15%), 10%); + +$badge-colors: ( + "gray": #5b7282, + "red": #d91f11, + "orange": #e86427, + "yellow": #f5c518, + "lime": #3c7d0e, + "green": #077d55, + "teal": #167b7d, + "turquoise": #067a91, + "aqua": #0073ba, + "blue": #186ade, + "ultramarine": #535fe8, + "purple": #8f49de, + "pink": #cc1d92, +); diff --git a/packages/fakeyou.com/src/scss/site-refresh.scss b/packages/fakeyou.com/src/scss/site-refresh.scss index dfe07cad14..29fad287ff 100644 --- a/packages/fakeyou.com/src/scss/site-refresh.scss +++ b/packages/fakeyou.com/src/scss/site-refresh.scss @@ -148,7 +148,7 @@ styles with important tags: } .container { - max-width: 1200px !important; + max-width: 1280px !important; } .container, @@ -296,20 +296,15 @@ styles with important tags: border-left: none; border-right: none; border-radius: 0px; - box-shadow: 0 0 0 1px rgba(0 0 0 / 16%), 0 70px 65px rgb(0 0 0 / 8%), - 0 30px 30px rgb(0 0 0 / 7%), 0 15px 15px rgb(0 0 0 / 5%), - 0 10px 8px rgb(0 0 0 / 3%), 0 4px 4px rgb(0 0 0 / 2%), + box-shadow: + 0 0 0 1px rgba(0 0 0 / 16%), + 0 70px 65px rgb(0 0 0 / 8%), + 0 30px 30px rgb(0 0 0 / 7%), + 0 15px 15px rgb(0 0 0 / 5%), + 0 10px 8px rgb(0 0 0 / 3%), + 0 4px 4px rgb(0 0 0 / 2%), 0 2px 2px rgb(0 0 0 / 1%) !important; - &.panel-clear { - padding-left: 1rem; - padding-right: 1rem; - background-color: transparent; - border: none; - border-color: transparent !important; - box-shadow: none !important; - } - .video-bg { background-color: $black; } @@ -356,6 +351,15 @@ styles with important tags: } } + .panel-clear { + padding-left: 1rem; + padding-right: 1rem; + background-color: transparent; + border: none; + border-color: transparent !important; + box-shadow: none !important; + } + .menu { border-radius: 0.5rem !important; color: $white; @@ -1020,9 +1024,13 @@ styles with important tags: background-color: $panel !important; min-height: 220px; height: 100%; - box-shadow: 0 0 0 1px rgba(0 0 0 / 30%), 0 70px 65px rgb(0 0 0 / 10%), - 0 30px 30px rgb(0 0 0 / 8%), 0 15px 15px rgb(0 0 0 / 6%), - 0 10px 8px rgb(0 0 0 / 4%), 0 4px 4px rgb(0 0 0 / 2%), + box-shadow: + 0 0 0 1px rgba(0 0 0 / 30%), + 0 70px 65px rgb(0 0 0 / 10%), + 0 30px 30px rgb(0 0 0 / 8%), + 0 15px 15px rgb(0 0 0 / 6%), + 0 10px 8px rgb(0 0 0 / 4%), + 0 4px 4px rgb(0 0 0 / 2%), 0 2px 2px rgb(0 0 0 / 1%) !important; } @@ -1031,9 +1039,13 @@ styles with important tags: border-radius: 0.5rem; background-color: $panel !important; min-height: 650px; - box-shadow: 0 0 0 1px rgba(0 0 0 / 30%), 0 70px 65px rgb(0 0 0 / 10%), - 0 30px 30px rgb(0 0 0 / 8%), 0 15px 15px rgb(0 0 0 / 6%), - 0 10px 8px rgb(0 0 0 / 4%), 0 4px 4px rgb(0 0 0 / 2%), + box-shadow: + 0 0 0 1px rgba(0 0 0 / 30%), + 0 70px 65px rgb(0 0 0 / 10%), + 0 30px 30px rgb(0 0 0 / 8%), + 0 15px 15px rgb(0 0 0 / 6%), + 0 10px 8px rgb(0 0 0 / 4%), + 0 4px 4px rgb(0 0 0 / 2%), 0 2px 2px rgb(0 0 0 / 1%) !important; } @@ -1633,18 +1645,18 @@ textarea { padding-left: var(--bs-gutter-x, 1.75rem); margin-right: auto; margin-left: auto; - max-width: 1200px; + max-width: 1280px; border-radius: 0.5rem; } .panel { border-radius: 0.5rem; border: 1px solid; + } - &.panel-clear { - padding-left: 0rem; - padding-right: 0rem; - } + .panel-clear { + padding-left: 0rem; + padding-right: 0rem; } ul.patrons-list { diff --git a/packages/fakeyou.com/src/v2/view/PageContainer.tsx b/packages/fakeyou.com/src/v2/view/PageContainer.tsx index edd1671dba..2dfba77c17 100644 --- a/packages/fakeyou.com/src/v2/view/PageContainer.tsx +++ b/packages/fakeyou.com/src/v2/view/PageContainer.tsx @@ -8,7 +8,6 @@ import { ModerationIpBanListFc } from "./pages/moderation/moderation_ip_ban_list import { ModerationViewIpBanFc } from "./pages/moderation/moderation_view_ip_ban/ModerationViewIpBanFc"; import { LipsyncEditor } from "./pages/lipsync"; import { ProfileEditFc } from "./pages/profile/profile_edit/ProfileEditFc"; -import { ProfilePage } from "./pages/profile/profile_view/ProfilePage"; import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper"; import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper"; import { SignupPage } from "./pages/signup/SignupPage"; @@ -96,6 +95,8 @@ import { VoiceDesignerVoiceEditPage } from "./pages/voice_designer/VoiceDesigner import VoiceDesignerUseVoicePage from "./pages/voice_designer/VoiceDesignerUseVoicePage"; import { PasswordResetEmailPage } from "./pages/password_reset/PasswordResetEmailPage"; import { PasswordResetVerificationPage } from "./pages/password_reset/PasswordResetVerificationPage"; +import { NewProfilePage } from "./pages/profile/profile_view/NewProfilePage"; +import { ProfilePage } from "./pages/profile/profile_view/ProfilePage"; interface Props { sessionWrapper: SessionWrapper; @@ -305,6 +306,16 @@ class PageContainer extends React.Component< /> + {/* New Profile Page */} + + + + {}} @@ -639,42 +650,39 @@ class PageContainer extends React.Component< {/* Route for initial voice creation */} - - + + {/* Route for editing the dataset details */} - - + + {/* Route for handling dataset token for uploading samples */} - - + + @@ -695,14 +703,16 @@ class PageContainer extends React.Component< - + diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/NewProfilePage.tsx b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/NewProfilePage.tsx new file mode 100644 index 0000000000..e05f01c451 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/NewProfilePage.tsx @@ -0,0 +1,430 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import React, { useCallback, useEffect, useState } from "react"; +import { Gravatar } from "@storyteller/components/src/elements/Gravatar"; +import { Link, Redirect, useLocation } from "react-router-dom"; +import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper"; +import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper"; +import { useParams } from "react-router-dom"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { + faDiscord, + faGithub, + faTwitch, + faTwitter, +} from "@fortawesome/free-brands-svg-icons"; +import { + faBan, + faGear, + faGlobe, + faDollarSign, + faStar, +} from "@fortawesome/free-solid-svg-icons"; + +import { + GetUserByUsername, + GetUserByUsernameIsErr, + GetUserByUsernameIsOk, + User, + UserLookupError, +} from "@storyteller/components/src/api/user/GetUserByUsername"; +import { format } from "date-fns"; +import { WebUrl } from "../../../../../common/WebUrl"; + +import Tippy from "@tippyjs/react"; +import "tippy.js/dist/tippy.css"; + +import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle"; +import { + faBookmark, + faCalendarAlt, + faLayerGroup, + faPhotoFilmMusic, +} from "@fortawesome/pro-solid-svg-icons"; +// import { CommentComponent } from "../../../_common/comments/CommentComponent"; +import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient"; +import { Panel } from "components/common"; +import Container from "components/common/Container"; +import Tabs from "components/common/Tabs"; +import MediaTab from "./tabs/MediaTab"; +import WeightsTab from "./tabs/WeightsTab"; +import BookmarksTab from "./tabs/BookmarksTab"; + +interface Props { + sessionWrapper: SessionWrapper; + sessionSubscriptionsWrapper: SessionSubscriptionsWrapper; +} + +function NewProfilePage(this: any, props: Props) { + const { username }: { username: string } = useParams(); + const { pathname } = useLocation(); + PosthogClient.recordPageview(); + + const [userData, setUserData] = useState(undefined); + const [notFoundState, setNotFoundState] = useState(false); + + const getUser = useCallback(async (username) => { + const response = await GetUserByUsername(username); + if (GetUserByUsernameIsOk(response)) { + setUserData(response); + } else if (GetUserByUsernameIsErr(response)) { + switch (response) { + case UserLookupError.NotFound: + setNotFoundState(true); + break; + } + } + }, []); + + useEffect(() => { + getUser(username); + }, [username, getUser]); + + const documentTitle = + userData?.display_name === undefined + ? undefined + : `${userData.display_name}`; + usePrefixedDocumentTitle(documentTitle); + + if ( + pathname === `/dev-profile/${username}` || + pathname === `/dev-profile/${username}/` + ) { + return ; + } + + if (notFoundState) { + return ( +
    +
    +

    User not found

    +
    + + Back to main + +
    +
    +
    + ); + } + + if (!userData) { + return
    ; + } + + let userEmailHash = userData.email_gravatar_hash; + + let editProfileButton = undefined; + + let banUserButton = undefined; + + let upgradeButton = undefined; + + if (props.sessionWrapper.isLoggedIn()) { + if (props.sessionWrapper.userTokenMatches(userData.user_token)) { + if (!props.sessionSubscriptionsWrapper.hasPaidFeatures()) { + const upgradeLinkUrl = WebUrl.pricingPage(); + + upgradeButton = ( + <> + + + Upgrade + + + ); + } + } + } + + if (props.sessionWrapper.canBanUsers()) { + const currentlyBanned = userData.maybe_moderator_fields?.is_banned; + const banLinkUrl = WebUrl.userProfileBanPage(userData.username); + const buttonLabel = currentlyBanned ? "Unban" : "Ban"; + const banButtonCss = currentlyBanned + ? "btn btn-secondary" + : "btn btn-destructive"; + + banUserButton = ( + <> + + + {buttonLabel} + + + ); + } + + let profileButtonsMobile = ; + + if (props.sessionWrapper.canEditUserProfile(userData.username)) { + const editLinkUrl = WebUrl.userProfileEditPage(userData.username); + + // Mods shouldn't edit preferences. + const buttonLabel = props.sessionWrapper.userTokenMatches( + userData.user_token + ) + ? "Edit Profile & Preferences" + : "Edit Profile"; + + editProfileButton = ( + <> + + + {buttonLabel} + + + ); + + profileButtonsMobile = ( +
    +
    + {upgradeButton} + {editProfileButton} + {banUserButton} +
    +
    + ); + } + + let profileDesc = ( +
    + No profile description. +
    + ); + + if (!!userData.profile_rendered_html) { + profileDesc = ( +
    + ); + } + + let profileRows: Array = []; + let profileJoinDate: Array = []; + + const createdAt = new Date(userData.created_at); + const joinDate = format(createdAt, "LLLL y"); + profileJoinDate.push( +
    + +

    Joined {joinDate}

    +
    + ); + + if (userData.website_url !== undefined && userData.website_url !== null) { + let websiteUrl = {userData.website_url}; + if ( + userData.website_url?.startsWith("http://") || + userData.website_url?.startsWith("https://") + ) { + websiteUrl = ( + + + + + + ); + } + + profileRows.push(
    {websiteUrl}
    ); + } + + if (userData.twitch_username) { + let twitchUrl = `https://twitch.com/${userData.twitch_username}`; + let twitchLink = ( + + + + + + ); + + profileRows.push(
    {twitchLink}
    ); + } + + if (userData.twitter_username) { + let twitterUrl = `https://twitter.com/${userData.twitter_username}`; + let twitterLink = ( + + + + + + ); + profileRows.push(
    {twitterLink}
    ); + } + + if (userData.discord_username) { + profileRows.push( + + Discord +
    +

    {userData.discord_username}

    +
    + } + interactive + hideOnClick + placement="bottom" + theme="fakeyou" + arrow={false} + > + + + + + ); + } + + if (userData.github_username) { + let githubUrl = `https://github.com/${userData.github_username}`; + let githubLink = ( + + + + + + ); + profileRows.push(
    {githubLink}
    ); + } + + if (userData.cashapp_username) { + // NB: URL includes a dollar sign + let cashAppUrl = `https://cash.me/$${userData.cashapp_username}`; + let cashAppLink = ( + + + + + + ); + profileRows.push(
    {cashAppLink}
    ); + } + + const tabs = [ + { + to: `/dev-profile/${username}/media`, + label: "Media", + content: , + icon: faPhotoFilmMusic, + }, + { + to: `/dev-profile/${username}/weights`, + label: "Weights", + content: , + icon: faLayerGroup, + }, + { + to: `/dev-profile/${username}/bookmarks`, + label: "Bookmarks", + content: , + icon: faBookmark, + }, + ]; + + return ( + + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +

    + {userData.display_name} +

    +
    + {banUserButton} + {upgradeButton} + {editProfileButton} +
    +
    +
    {profileJoinDate}
    +
    {profileDesc}
    +
    + {profileRows} +
    +
    +
    +
    + + {profileButtonsMobile} + + + + +
    + ); +} + +export { NewProfilePage }; diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/BookmarksTab.tsx b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/BookmarksTab.tsx new file mode 100644 index 0000000000..1266cc1451 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/BookmarksTab.tsx @@ -0,0 +1,58 @@ +import React, { useRef, useState } from "react"; +import MasonryGrid from "components/common/MasonryGrid/MasonryGrid"; +import AudioCard from "components/common/Card/AudioCard"; +import ImageCard from "components/common/Card/ImageCard"; +import VideoCard from "components/common/Card/VideoCard"; +import Panel from "components/common/Panel"; +import AudioPlayerProvider from "components/common/AudioPlayer/AudioPlayerContext"; +import SkeletonCard from "components/common/Card/SkeletonCard"; +import mockWeightsData from "./mockWeightsData"; + +export default function BookmarksTab() { + const [data, setData] = useState(mockWeightsData); + const [hasMore, setHasMore] = useState(true); + const [isLoading, setIsLoading] = useState(false); + + const gridContainerRef = useRef(null); + + return ( + + + {isLoading ? ( +
    + {Array.from({ length: 6 }).map((_, index) => ( + + ))} +
    + ) : ( + console.log("Layout complete!")} + > + {data.map((data, index) => { + let card; + switch (data.media_type) { + case "audio": + card = ; + break; + case "image": + card = ; + break; + case "video": + card = ; + break; + default: + card =
    Unsupported media type
    ; + } + return ( +
    + {card} +
    + ); + })} +
    + )} +
    +
    + ); +} diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/MediaTab.tsx b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/MediaTab.tsx new file mode 100644 index 0000000000..4244295569 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/MediaTab.tsx @@ -0,0 +1,90 @@ +import React, { useRef, useState } from "react"; +import MasonryGrid from "components/common/MasonryGrid/MasonryGrid"; +import mockMediaData from "./mockMediaData"; +import AudioCard from "components/common/Card/AudioCard"; +import ImageCard from "components/common/Card/ImageCard"; +import VideoCard from "components/common/Card/VideoCard"; +import Panel from "components/common/Panel"; +import { Select } from "components/common/Inputs/Inputs"; +import { + faArrowDownWideShort, + faFilter, +} from "@fortawesome/pro-solid-svg-icons"; +import AudioPlayerProvider from "components/common/AudioPlayer/AudioPlayerContext"; +import SkeletonCard from "components/common/Card/SkeletonCard"; + +export default function MediaTab() { + const [data, setData] = useState(mockMediaData); + const [hasMore, setHasMore] = useState(true); + const [isLoading, setIsLoading] = useState(false); + + const gridContainerRef = useRef(null); + + const filterOptions = [ + { value: "all", label: "All Media" }, + { value: "images", label: "Images" }, + { value: "audio", label: "Audio" }, + { value: "video", label: "Video" }, + ]; + + const sortOptions = [ + { value: "newest", label: "Newest" }, + { value: "oldest", label: "Oldest" }, + { value: "mostliked", label: "Most Liked" }, + ]; + + return ( + +
    + +
    + + {isLoading ? ( +
    + {Array.from({ length: 6 }).map((_, index) => ( + + ))} +
    + ) : ( + console.log("Layout complete!")} + > + {data.map((data, index) => { + let card; + switch (data.media_type) { + case "audio": + card = ; + break; + case "image": + card = ; + break; + case "video": + card = ; + break; + default: + card =
    Unsupported media type
    ; + } + return ( +
    + {card} +
    + ); + })} +
    + )} +
    +
    + ); +} diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/WeightsTab.tsx b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/WeightsTab.tsx new file mode 100644 index 0000000000..cbc9ddac0a --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/WeightsTab.tsx @@ -0,0 +1,86 @@ +import React, { useRef, useState } from "react"; +import MasonryGrid from "components/common/MasonryGrid/MasonryGrid"; +import mockWeightsData from "./mockWeightsData"; +import AudioCard from "components/common/Card/AudioCard"; +import ImageCard from "components/common/Card/ImageCard"; +import VideoCard from "components/common/Card/VideoCard"; +import Panel from "components/common/Panel"; +import { Select } from "components/common/Inputs/Inputs"; +import { + faArrowDownWideShort, + faFilter, +} from "@fortawesome/pro-solid-svg-icons"; +import SkeletonCard from "components/common/Card/SkeletonCard"; + +export default function WeightsTab() { + const [data, setData] = useState(mockWeightsData); + const [isLoading, setIsLoading] = useState(false); + + const gridContainerRef = useRef(null); + + const filterOptions = [ + { value: "all", label: "All Weights" }, + { value: "tts", label: "Text to Speech" }, + { value: "vc", label: "Voice to Voice" }, + { value: "vd", label: "Voice Designer" }, + ]; + + const sortOptions = [ + { value: "newest", label: "Newest" }, + { value: "oldest", label: "Oldest" }, + { value: "mostliked", label: "Most Favorited" }, + ]; + + return ( + +
    + +
    + {isLoading ? ( +
    + {Array.from({ length: 6 }).map((_, index) => ( + + ))} +
    + ) : ( + console.log("Layout complete!")} + > + {data.map((data, index) => { + let card; + switch (data.media_type) { + case "audio": + card = ; + break; + case "image": + card = ; + break; + case "video": + card = ; + break; + default: + card =
    Unsupported media type
    ; + } + return ( +
    + {card} +
    + ); + })} +
    + )} +
    + ); +} diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/mockMediaData.ts b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/mockMediaData.ts new file mode 100644 index 0000000000..1691c1c8c8 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/mockMediaData.ts @@ -0,0 +1,384 @@ +let mockMediaData = [ + { + token: "token1", + weight_name: "Queen Elizabeth", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token2", + weight_name: "Monster House", + media_type: "image", + public_bucket_path: "/images/dummy-image.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token3", + weight_name: "Ronaldo", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token4", + weight_name: "Desert", + media_type: "video", + public_bucket_path: "/images/dummy-video.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token5", + weight_name: "3D Cat", + media_type: "image", + public_bucket_path: "/images/dummy-image-2.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token6", + weight_name: "Superman", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token7", + weight_name: "Son Goku", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token8", + weight_name: "Astronaut in Space", + media_type: "image", + public_bucket_path: "/images/dummy-image-3.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token9", + weight_name: "Monokuma", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token10", + weight_name: "Watery Landscape", + media_type: "image", + public_bucket_path: "/images/dummy-image-4.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token11", + weight_name: "Queen Elizabeth", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token12", + weight_name: "Monster House", + media_type: "image", + public_bucket_path: "/images/dummy-image.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token13", + weight_name: "Ronaldo", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token14", + weight_name: "Desert", + media_type: "video", + public_bucket_path: "/images/dummy-video.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token15", + weight_name: "3D Cat", + media_type: "image", + public_bucket_path: "/images/dummy-image-2.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token16", + weight_name: "Superman", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token17", + weight_name: "Son Goku", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token18", + weight_name: "Astronaut in Space", + media_type: "image", + public_bucket_path: "/images/dummy-image-3.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token19", + weight_name: "Monokuma", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token20", + weight_name: "Watery Landscape", + media_type: "image", + public_bucket_path: "/images/dummy-image-4.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token1", + weight_name: "Queen Elizabeth", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token2", + weight_name: "Monster House", + media_type: "image", + public_bucket_path: "/images/dummy-image.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token3", + weight_name: "Ronaldo", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token4", + weight_name: "Desert", + media_type: "video", + public_bucket_path: "/images/dummy-video.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token5", + weight_name: "3D Cat", + media_type: "image", + public_bucket_path: "/images/dummy-image-2.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token6", + weight_name: "Superman", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token7", + weight_name: "Son Goku", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token8", + weight_name: "Astronaut in Space", + media_type: "image", + public_bucket_path: "/images/dummy-image-3.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token9", + weight_name: "Monokuma", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token10", + weight_name: "Watery Landscape", + media_type: "image", + public_bucket_path: "/images/dummy-image-4.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token11", + weight_name: "Queen Elizabeth", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token12", + weight_name: "Monster House", + media_type: "image", + public_bucket_path: "/images/dummy-image.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token13", + weight_name: "Ronaldo", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token14", + weight_name: "Desert", + media_type: "video", + public_bucket_path: "/images/dummy-video.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token15", + weight_name: "3D Cat", + media_type: "image", + public_bucket_path: "/images/dummy-image-2.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token16", + weight_name: "Superman", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token17", + weight_name: "Son Goku", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token18", + weight_name: "Astronaut in Space", + media_type: "image", + public_bucket_path: "/images/dummy-image-3.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token19", + weight_name: "Monokuma", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token20", + weight_name: "Watery Landscape", + media_type: "image", + public_bucket_path: "/images/dummy-image-4.jpg", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, +]; + +export default mockMediaData; diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/mockWeightsData.ts b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/mockWeightsData.ts new file mode 100644 index 0000000000..665e5975d9 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/tabs/mockWeightsData.ts @@ -0,0 +1,66 @@ +let mockWeightsData = [ + { + token: "token1", + weight_name: "Queen Elizabeth", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 150, + isLiked: true, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token2", + weight_name: "Monster House", + media_type: "image", + public_bucket_path: "/images/dummy-image.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token3", + weight_name: "Ronaldo", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token5", + weight_name: "3D Cat", + media_type: "image", + public_bucket_path: "/images/dummy-image-2.jpg", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, + { + token: "token6", + weight_name: "Superman", + media_type: "audio", + public_bucket_path: + "/media/s/p/x/d/2/spxd2xr7nt7zdezyhp61h00kxatr18pf/fakeyou_rvc_spxd2xr7nt7zdezyhp61h00kxatr18pf.wav", + likes: 200, + isLiked: false, + created_at: "2023-08-10T09:00:00.000Z", + }, +]; + +// Randomize the order of the array +for (let i = mockWeightsData.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [mockWeightsData[i], mockWeightsData[j]] = [ + mockWeightsData[j], + mockWeightsData[i], + ]; +} + +// Update the 'token' property to start at 1 +mockWeightsData.forEach((item, index) => { + item.token = `token${index + 1}`; +}); + +export default mockWeightsData; diff --git a/yarn.lock b/yarn.lock index 78ab0cee98..c60a95c33c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4420,6 +4420,7 @@ __metadata: "@fortawesome/pro-regular-svg-icons": ^6.2.1 "@fortawesome/pro-solid-svg-icons": ^6.2.1 "@fortawesome/react-fontawesome": ^0.2.0 + "@react-spring/types": ^9.7.3 "@react-spring/web": ^9.7.3 "@storyteller/components": 0.1.0 "@testing-library/jest-dom": ^4.2.4 @@ -4431,8 +4432,11 @@ __metadata: "@types/google.analytics": ^0.0.42 "@types/gtag.js": ^0.0.12 "@types/howler": ^2.1.2 + "@types/imagesloaded": ^4.1.6 + "@types/infinite-scroll": ^4.0.3 "@types/jest": ^24.9.1 "@types/js-cookie": ^3.0.1 + "@types/masonry-layout": ^4.2.7 "@types/node": ^12.12.47 "@types/react": ^16.9.36 "@types/react-autocomplete": ^1.8.6 @@ -4451,7 +4455,10 @@ __metadata: i18next: ^21.6.11 i18next-browser-languagedetector: ^7.1.0 i18next-http-backend: ^2.2.1 + imagesloaded: ^5.0.0 + infinite-scroll: ^4.0.1 js-cookie: ^3.0.1 + masonry-layout: ^4.2.2 posthog-js: ^1.73.1 pretty-num: ^0.5.2 query-string: ^8.1.0 @@ -4461,6 +4468,7 @@ __metadata: react-dom: ^16.13.1 react-drag-drop-files: ^2.3.9 react-i18next: ^11.15.4 + react-infinite-scroll-component: ^6.1.0 react-range: ^1.8.14 react-reveal: ^1.2.2 react-router-dom: ^5.2.0 @@ -4471,6 +4479,7 @@ __metadata: react-wavesurfer.js: ^0.0.8 sass: ^1.57.1 typescript: ^3.7.5 + universal-cookie: ^6.1.1 uuid: ^8.3.2 wavesurfer.js: ^6.4.0 zustand: ^4.3.9 @@ -4572,7 +4581,6 @@ __metadata: version: 0.0.0-use.local resolution: "@storyteller/root@workspace:." dependencies: - "@react-spring/types": ^9.7.3 craco: ^0.0.3 cross-env: ^7.0.3 husky: ^8.0.3 @@ -5251,6 +5259,34 @@ __metadata: languageName: node linkType: hard +"@types/imagesloaded@npm:^4.1.6": + version: 4.1.6 + resolution: "@types/imagesloaded@npm:4.1.6" + dependencies: + "@types/jquery": "*" + checksum: adfea961f0295e173ac4f81a58d13b62247576aef057f010da6b651e4191e86d52c97d4386d154c73ca8fd71d05b3bb29da8f9f3e20fda2c677af94a122feb6d + languageName: node + linkType: hard + +"@types/infinite-scroll@npm:^4.0.3": + version: 4.0.3 + resolution: "@types/infinite-scroll@npm:4.0.3" + dependencies: + "@types/isotope-layout": "*" + "@types/jquery": "*" + "@types/masonry-layout": "*" + "@types/packery": "*" + checksum: c7c9a2db7eb6a26c646a63c36fb1b04b381b9bcbae1b5fbc97d36f05eea36d6b17749b52cb906be578087aa203bfce72541b175fd0529df7c71961a7e7608668 + languageName: node + linkType: hard + +"@types/isotope-layout@npm:*": + version: 3.0.12 + resolution: "@types/isotope-layout@npm:3.0.12" + checksum: 7ae477fad4017a2e7ebbd0b5202e26d6febc58bc0604688d99d2ff822157d48eab77c8a89d942afc21ad1b0d51967491d07c9619d2e5722b626964c2c03e71b9 + languageName: node + linkType: hard + "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.4 resolution: "@types/istanbul-lib-coverage@npm:2.0.4" @@ -5305,6 +5341,15 @@ __metadata: languageName: node linkType: hard +"@types/jquery@npm:*": + version: 3.5.29 + resolution: "@types/jquery@npm:3.5.29" + dependencies: + "@types/sizzle": "*" + checksum: 5e959762d6f7050b07b4387b6507a308113384566a77cfc4f8d0f54c2fb0a79f6bc8c057706c6aa4840cde56f32ad0e5814fb53c5f078c5db9e01670a1ecd535 + languageName: node + linkType: hard + "@types/js-cookie@npm:^3.0.1": version: 3.0.2 resolution: "@types/js-cookie@npm:3.0.2" @@ -5326,6 +5371,15 @@ __metadata: languageName: node linkType: hard +"@types/masonry-layout@npm:*, @types/masonry-layout@npm:^4.2.7": + version: 4.2.7 + resolution: "@types/masonry-layout@npm:4.2.7" + dependencies: + "@types/jquery": "*" + checksum: ef12ab8dc278ce0c96239f8542715d87b856db2414dd57c4256bb232f389247522d7f73ddd2bfe717a6c7a5e27ac5ec4dbc44ab95786ee49f97c38d97087cd71 + languageName: node + linkType: hard + "@types/mime@npm:^1": version: 1.3.2 resolution: "@types/mime@npm:1.3.2" @@ -5375,6 +5429,15 @@ __metadata: languageName: node linkType: hard +"@types/packery@npm:*": + version: 1.4.37 + resolution: "@types/packery@npm:1.4.37" + dependencies: + "@types/jquery": "*" + checksum: 8350af4392e89988f4d8ec57827b47503be54365f5486c34ef36af3c0f48f1dc18332805eec7d04b06a6c22c2ef7db6cae03bc840058a9972d08fca21b0bc957 + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.0 resolution: "@types/parse-json@npm:4.0.0" @@ -5538,6 +5601,13 @@ __metadata: languageName: node linkType: hard +"@types/sizzle@npm:*": + version: 2.3.8 + resolution: "@types/sizzle@npm:2.3.8" + checksum: 2ac62443dc917f5f903cbd9afc51c7d6cc1c6569b4e1a15faf04aea5b13b486e7f208650014c3dc4fed34653eded3e00fe5abffe0e6300cbf0e8a01beebf11a6 + languageName: node + linkType: hard + "@types/sockjs@npm:^0.3.33": version: 0.3.33 resolution: "@types/sockjs@npm:0.3.33" @@ -9360,6 +9430,13 @@ __metadata: languageName: node linkType: hard +"desandro-matches-selector@npm:^2.0.0": + version: 2.0.2 + resolution: "desandro-matches-selector@npm:2.0.2" + checksum: 30979e6b45d7720d259d4db11ec026fcbee242deee5ec0944c265d7e386a7358ab29f7417cbc3631830d0dbe6e827940dee31f789ed865dba22880d209fc9f8e + languageName: node + linkType: hard + "destroy@npm:~1.0.4": version: 1.0.4 resolution: "destroy@npm:1.0.4" @@ -10389,6 +10466,20 @@ __metadata: languageName: node linkType: hard +"ev-emitter@npm:^1.0.0": + version: 1.1.1 + resolution: "ev-emitter@npm:1.1.1" + checksum: 3dd78a7620701ef8095794f611dd251bdd9023badf322b3d6fa5e10a660c50e83eec5ee5bbc7654682635cf7b8858c94e2c77e1d10bdc188a2b0593436403476 + languageName: node + linkType: hard + +"ev-emitter@npm:^2.1.0, ev-emitter@npm:^2.1.2": + version: 2.1.2 + resolution: "ev-emitter@npm:2.1.2" + checksum: 1102823ef040684869256100e19a6c6aeeecd422d09a267d7c74e77023136eede2ee86ee475ad1019d30d1f7917557d74542d5665e9f91c398bd5814260af6b3 + languageName: node + linkType: hard + "eventemitter3@npm:^3.1.0": version: 3.1.2 resolution: "eventemitter3@npm:3.1.2" @@ -10869,6 +10960,22 @@ __metadata: languageName: node linkType: hard +"fizzy-ui-utils@npm:^2.0.0": + version: 2.0.7 + resolution: "fizzy-ui-utils@npm:2.0.7" + dependencies: + desandro-matches-selector: ^2.0.0 + checksum: 001e54effa22c4f62728b90a25e8eb5477057ab53d0184e1c3231bbdfc7c34e278418fbcaf7d63c75ede823d82e61245e668ce8cba90e1c5699de960188c654f + languageName: node + linkType: hard + +"fizzy-ui-utils@npm:^3.0.0": + version: 3.0.0 + resolution: "fizzy-ui-utils@npm:3.0.0" + checksum: 73b53e5dc89e033bad3eb9cf111d220502afae083c84fbc842d9453202673284de270f7bbe6cc77a806678e62cf8068da1b4280f0d3a1bf1310110248dfa96cd + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.0.4 resolution: "flat-cache@npm:3.0.4" @@ -11298,6 +11405,10 @@ __metadata: languageName: node linkType: hard +"get-size@npm:^2.0.2": + version: 2.0.3 + resolution: "get-size@npm:2.0.3" + checksum: 18d5a5fdb3f541db8b1e6ad46a5411d4bb7da3061d2ef7e544db3bbce7a13543f05c91fd40c7f68b4bc4bc035c160fed23c45514cde7d5fb18de1cce10208b19 "get-stream@npm:^5.0.0": version: 5.2.0 resolution: "get-stream@npm:5.2.0" @@ -12186,6 +12297,15 @@ __metadata: languageName: node linkType: hard +"imagesloaded@npm:^5.0.0": + version: 5.0.0 + resolution: "imagesloaded@npm:5.0.0" + dependencies: + ev-emitter: ^2.1.2 + checksum: aec1826e866bcf2f92fc533b78e431597096c32dda3cf6de060f9dc2bdf1e39bb600eda244a7280ed09a7d12462fb63cf01e723799d35a86a326592e2f23751b + languageName: node + linkType: hard + "immer@npm:^9.0.7": version: 9.0.12 resolution: "immer@npm:9.0.12" @@ -12243,6 +12363,16 @@ __metadata: languageName: node linkType: hard +"infinite-scroll@npm:^4.0.1": + version: 4.0.1 + resolution: "infinite-scroll@npm:4.0.1" + dependencies: + ev-emitter: ^2.1.0 + fizzy-ui-utils: ^3.0.0 + checksum: e6000c0b82eace9df15ffb007447ecd12b806df60a41c6a06cdc0f931ae419e360be1e713f02e1047e088c75e0060198b25d19de6c3f88bd5fe0f987e326050a + languageName: node + linkType: hard + "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -14374,6 +14504,16 @@ __metadata: languageName: node linkType: hard +"masonry-layout@npm:^4.2.2": + version: 4.2.2 + resolution: "masonry-layout@npm:4.2.2" + dependencies: + get-size: ^2.0.2 + outlayer: ^2.1.0 + checksum: b947029b8fdfb384d17d7749d80a4f00f88d885acea04d77e1fefd36827cc2a345fd40d9ccddf720ed9323e133d8ea498125eece91d2c8517f69fd4e9e1bbdf4 + languageName: node + linkType: hard + "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -15701,6 +15841,17 @@ __metadata: languageName: node linkType: hard +"outlayer@npm:^2.1.0": + version: 2.1.1 + resolution: "outlayer@npm:2.1.1" + dependencies: + ev-emitter: ^1.0.0 + fizzy-ui-utils: ^2.0.0 + get-size: ^2.0.2 + checksum: a8b69d07bad6b498ea1956f89a4bae6d38414d81a5feeae6af06cd8206a1bf47db82f664dc3ccd13b8d2c5886a6cded4a4642d0fafcbbd80f68873b7eb9f4153 + languageName: node + linkType: hard + "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" @@ -17653,6 +17804,17 @@ __metadata: languageName: node linkType: hard +"react-infinite-scroll-component@npm:^6.1.0": + version: 6.1.0 + resolution: "react-infinite-scroll-component@npm:6.1.0" + dependencies: + throttle-debounce: ^2.1.0 + peerDependencies: + react: ">=16.0.0" + checksum: 3708398934366df907dbad215247ebc1033221957ce7e32289ea31750cce70aa16513e2d03743e06c8b868ac7c542d12d5dbb6c830fd408433a4762f3cb5ecfb + languageName: node + linkType: hard + "react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0, react-is@npm:^16.8.4": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -20217,6 +20379,13 @@ __metadata: languageName: node linkType: hard +"throttle-debounce@npm:^2.1.0": + version: 2.3.0 + resolution: "throttle-debounce@npm:2.3.0" + checksum: 6d90aa2ddb294f8dad13d854a1cfcd88fdb757469669a096a7da10f515ee466857ac1e750649cb9da931165c6f36feb448318e7cb92570f0a3679d20e860a925 + languageName: node + linkType: hard + "through2@npm:^2.0.0": version: 2.0.5 resolution: "through2@npm:2.0.5"