mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 02:21:23 +00:00
updates
This commit is contained in:
1 parent
6108d75eea
commit
0bb5a07ef4
13 files changed
+376
-145
No files matched your search
@@ -19,23 +19,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$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,
|
||||
);
|
||||
|
||||
@each $color, $value in $colors {
|
||||
@each $color, $value in $badge-colors {
|
||||
.badge-#{$color} {
|
||||
background-color: $value;
|
||||
color: contrast($value) !important;
|
||||
|
||||
@@ -5,16 +5,23 @@ import AudioPlayer from "components/common/AudioPlayer";
|
||||
import useTimeAgo from "hooks/useTimeAgo";
|
||||
import Badge from "components/common/Badge";
|
||||
import LikeButton from "components/common/LikeButton";
|
||||
import FavoriteButton from "components/common/FavoriteButton";
|
||||
import Button from "components/common/Button";
|
||||
|
||||
interface AudioCardProps {
|
||||
data: any;
|
||||
type: "media" | "weights" | "favorites";
|
||||
}
|
||||
|
||||
export default function AudioCard({ data }: AudioCardProps) {
|
||||
export default function AudioCard({ data, type }: AudioCardProps) {
|
||||
const history = useHistory();
|
||||
|
||||
const handleCardClick = () => {
|
||||
history.push(`/media/${data.token}`);
|
||||
if (type === "media") {
|
||||
history.push(`/media/${data.token}`);
|
||||
} else if (type === "weights") {
|
||||
history.push(`/weights/${data.token}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleInnerClick = (event: any) => {
|
||||
@@ -29,23 +36,60 @@ export default function AudioCard({ data }: AudioCardProps) {
|
||||
|
||||
return (
|
||||
<Card padding={true} onClick={handleCardClick}>
|
||||
<div className="mb-3">
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="Audio" color="teal" />
|
||||
{type === "media" && (
|
||||
<>
|
||||
<div className="mb-3">
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="Audio" color="teal" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 className="fw-semibold text-white mb-1 mt-3">
|
||||
{data.weight_name}
|
||||
</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
</div>
|
||||
|
||||
<div onClick={handleInnerClick}>
|
||||
<AudioPlayer src={data.public_bucket_path} id={data.token} />
|
||||
</div>
|
||||
|
||||
<div className="mt-3" onClick={handleInnerClick}>
|
||||
<LikeButton onToggle={handleLike} likeCount={data.likes} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<h6 className="fw-semibold text-white mb-1 mt-3">{data.weight_name}</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
</div>
|
||||
{type === "weights" && (
|
||||
<>
|
||||
<div>
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="RVC" color="orange" />
|
||||
</div>
|
||||
<div onClick={handleInnerClick}>
|
||||
<FavoriteButton
|
||||
onToggle={handleLike}
|
||||
favoriteCount={data.likes}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div onClick={handleInnerClick}>
|
||||
<AudioPlayer src={data.public_bucket_path} id={data.token} />
|
||||
</div>
|
||||
<div className="d-flex align-items-center mt-3">
|
||||
<div className="flex-grow-1">
|
||||
<h6 className="fw-semibold text-white mb-1">
|
||||
{data.weight_name}
|
||||
</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
</div>
|
||||
<div onClick={handleInnerClick}>
|
||||
<Button label="Use" small={true} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -4,16 +4,23 @@ 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" | "favorites";
|
||||
}
|
||||
|
||||
export default function ImageCard({ data }: ImageCardProps) {
|
||||
export default function ImageCard({ data, type }: ImageCardProps) {
|
||||
const history = useHistory();
|
||||
|
||||
const handleCardClick = () => {
|
||||
history.push(`/media/${data.token}`);
|
||||
if (type === "media") {
|
||||
history.push(`/media/${data.token}`);
|
||||
} else if (type === "weights") {
|
||||
history.push(`/weights/${data.token}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleInnerClick = (event: any) => {
|
||||
@@ -28,34 +35,77 @@ export default function ImageCard({ data }: ImageCardProps) {
|
||||
|
||||
return (
|
||||
<Card padding={false} onClick={handleCardClick}>
|
||||
<img
|
||||
src={data.public_bucket_path}
|
||||
alt={data.weight_name}
|
||||
className="card-img"
|
||||
/>
|
||||
<div className="card-img-overlay">
|
||||
<div className="card-img-gradient" />
|
||||
{type === "media" && (
|
||||
<>
|
||||
<img
|
||||
src={data.public_bucket_path}
|
||||
alt={data.weight_name}
|
||||
className="card-img"
|
||||
/>
|
||||
<div className="card-img-overlay">
|
||||
<div className="card-img-gradient" />
|
||||
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="Image" color="ultramarine" overlay={true} />
|
||||
</div>
|
||||
<div onClick={handleInnerClick}>
|
||||
<LikeButton
|
||||
onToggle={handleLike}
|
||||
likeCount={data.likes}
|
||||
overlay={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="Image" color="ultramarine" overlay={true} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card-img-overlay-text">
|
||||
<div>
|
||||
<h6 className="fw-semibold text-white mb-1">{data.weight_name}</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
<div className="card-img-overlay-text">
|
||||
<div>
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
<div onClick={handleInnerClick} className="mt-2">
|
||||
<LikeButton
|
||||
onToggle={handleLike}
|
||||
likeCount={data.likes}
|
||||
overlay={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{type === "weights" && (
|
||||
<>
|
||||
<img
|
||||
src={data.public_bucket_path}
|
||||
alt={data.weight_name}
|
||||
className="card-img"
|
||||
/>
|
||||
<div className="card-img-overlay">
|
||||
<div className="card-img-gradient" />
|
||||
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="LORA" color="pink" overlay={true} />
|
||||
</div>
|
||||
<div onClick={handleInnerClick}>
|
||||
<FavoriteButton
|
||||
onToggle={handleLike}
|
||||
favoriteCount={data.likes}
|
||||
overlay={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card-img-overlay-text">
|
||||
<div className="d-flex align-items-center mt-3">
|
||||
<div className="flex-grow-1">
|
||||
<h6 className="fw-semibold text-white mb-1">
|
||||
{data.weight_name}
|
||||
</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
</div>
|
||||
<div onClick={handleInnerClick}>
|
||||
<Button label="Use" small={true} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -42,19 +42,19 @@ export default function VideoCard({ data }: VideoCardProps) {
|
||||
<div className="flex-grow-1">
|
||||
<Badge label="Video" color="purple" overlay={true} />
|
||||
</div>
|
||||
<div onClick={handleInnerClick}>
|
||||
<LikeButton
|
||||
onToggle={handleLike}
|
||||
likeCount={data.likes}
|
||||
overlay={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<FontAwesomeIcon icon={faPlayCircle} className="card-video-play" />
|
||||
<div className="card-img-overlay-text">
|
||||
<div>
|
||||
<h6 className="fw-semibold text-white mb-1">{data.weight_name}</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
<div className="mt-2" onClick={handleInnerClick}>
|
||||
<LikeButton
|
||||
onToggle={handleLike}
|
||||
likeCount={data.likes}
|
||||
overlay={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.favorite-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: lighten($secondary, 3%);
|
||||
background-color: rgba(lighten($secondary, 5%), 0.9);
|
||||
color: inherit;
|
||||
border: none;
|
||||
padding: 0;
|
||||
@@ -15,8 +15,16 @@
|
||||
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: lighten($secondary, 10%);
|
||||
background: rgba(lighten($secondary, 10%), 0.9);
|
||||
}
|
||||
|
||||
&:hover .favorite-number {
|
||||
@@ -24,15 +32,18 @@
|
||||
}
|
||||
|
||||
&:hover .icon-default {
|
||||
color: $primary;
|
||||
color: map-get($badge-colors, "yellow");
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background-color: rgba($primary, 0.25);
|
||||
background-color: darken(rgba(map-get($badge-colors, "yellow"), 0.9), 32%);
|
||||
|
||||
&:hover {
|
||||
background-color: darken(rgba($primary, 0.25), 5%);
|
||||
background-color: darken(
|
||||
rgba(map-get($badge-colors, "yellow"), 0.9),
|
||||
25%
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,12 +55,12 @@
|
||||
}
|
||||
|
||||
.favorite-button .icon-toggled {
|
||||
color: $primary;
|
||||
color: map-get($badge-colors, "yellow");
|
||||
animation: pulse 0.3s ease;
|
||||
}
|
||||
|
||||
.favorite-button .icon-toggled:hover {
|
||||
color: $primary;
|
||||
color: map-get($badge-colors, "yellow");
|
||||
}
|
||||
|
||||
.favorite-number {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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 { 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";
|
||||
@@ -9,13 +9,15 @@ import "./FavoriteButton.scss";
|
||||
interface FavoriteButtonProps {
|
||||
initialToggled?: boolean;
|
||||
onToggle: (toggled: boolean) => Promise<void>;
|
||||
FavoriteCount?: number;
|
||||
favoriteCount?: number;
|
||||
overlay?: boolean;
|
||||
}
|
||||
|
||||
export default function FavoriteButton({
|
||||
initialToggled = false,
|
||||
onToggle,
|
||||
FavoriteCount,
|
||||
favoriteCount,
|
||||
overlay,
|
||||
}: FavoriteButtonProps) {
|
||||
const [isToggled, setIsToggled] = useState(initialToggled);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -33,6 +35,7 @@ export default function FavoriteButton({
|
||||
};
|
||||
|
||||
const buttonClass = isToggled ? "favorite-button toggled" : "favorite-button";
|
||||
const buttonShadow = overlay ? "shadow" : "";
|
||||
const iconClass = isToggled ? "icon-toggled" : "icon-default";
|
||||
const toolTip = isToggled ? "Unfavorite" : "Favorite";
|
||||
|
||||
@@ -49,13 +52,13 @@ export default function FavoriteButton({
|
||||
<button
|
||||
onClick={handleClick}
|
||||
disabled={isLoading}
|
||||
className={buttonClass}
|
||||
className={`${buttonClass} ${buttonShadow}`}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={isToggled ? faHeart : faHeartOutline}
|
||||
icon={isToggled ? faBookmark : faBookmarkOutline}
|
||||
className={`${iconClass} me-2`}
|
||||
/>
|
||||
{FavoriteCount && <p className="favorite-number">{FavoriteCount}</p>}
|
||||
{favoriteCount && <p className="favorite-number">{favoriteCount}</p>}
|
||||
</button>
|
||||
</Tippy>
|
||||
</div>
|
||||
|
||||
@@ -48,6 +48,7 @@ export default function LikeButton({
|
||||
trigger="mouseenter"
|
||||
delay={[500, 0]}
|
||||
offset={[0, 12]}
|
||||
placement="bottom"
|
||||
>
|
||||
<button
|
||||
onClick={handleClick}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
@@ -35,6 +35,7 @@ import "tippy.js/dist/tippy.css";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import {
|
||||
faBookmark,
|
||||
faCalendarAlt,
|
||||
faLayerGroup,
|
||||
faPhotoFilmMusic,
|
||||
@@ -45,6 +46,7 @@ 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";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
@@ -360,14 +362,14 @@ function NewProfilePage(this: any, props: Props) {
|
||||
{
|
||||
to: `/profile/${username}/weights`,
|
||||
label: "Weights",
|
||||
content: <div>Weights</div>,
|
||||
content: <WeightsTab />,
|
||||
icon: faLayerGroup,
|
||||
},
|
||||
{
|
||||
to: `/profile/${username}/favorites`,
|
||||
label: "Favorites",
|
||||
content: <div>Favorites</div>,
|
||||
icon: faStar,
|
||||
to: `/profile/${username}/bookmarks`,
|
||||
label: "Bookmarks",
|
||||
content: <div>Bookmarks</div>,
|
||||
icon: faBookmark,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import MasonryGrid from "components/common/MasonryGrid/MasonryGrid";
|
||||
import mockData from "./mockData";
|
||||
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";
|
||||
@@ -12,34 +12,14 @@ import {
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import AudioPlayerProvider from "components/common/AudioPlayer/AudioPlayerContext";
|
||||
import SkeletonCard from "components/common/Card/SkeletonCard";
|
||||
import InfiniteScroll from "react-infinite-scroll-component";
|
||||
|
||||
export default function MediaTab() {
|
||||
const itemsPerPage = 10; // Items per page
|
||||
const initialData = mockData.slice(0, itemsPerPage); // Initial 10 items
|
||||
const [data, setData] = useState(initialData);
|
||||
const [data, setData] = useState(mockMediaData);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [page, setPage] = useState(1); //start from second page
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const fetchMoreData = () => {
|
||||
if (data.length >= mockData.length) {
|
||||
setHasMore(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate an API fetch
|
||||
setTimeout(() => {
|
||||
const startIndex = page * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
const nextItems = mockData.slice(startIndex, endIndex);
|
||||
setData(data.concat(nextItems));
|
||||
setPage(page + 1);
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
const filterOptions = [
|
||||
{ value: "all", label: "All Media" },
|
||||
{ value: "images", label: "Images" },
|
||||
@@ -77,44 +57,32 @@ export default function MediaTab() {
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<InfiniteScroll
|
||||
dataLength={data.length}
|
||||
next={fetchMoreData}
|
||||
hasMore={hasMore}
|
||||
loader={<h4>Loading...</h4>}
|
||||
endMessage={<p style={{ textAlign: "center" }}>No more media</p>}
|
||||
className="overflow-hidden"
|
||||
<MasonryGrid
|
||||
gridRef={gridContainerRef}
|
||||
onLayoutComplete={() => console.log("Layout complete!")}
|
||||
>
|
||||
<MasonryGrid
|
||||
gridRef={gridContainerRef}
|
||||
onLayoutComplete={() => console.log("Layout complete!")}
|
||||
>
|
||||
{data.map((data, index) => {
|
||||
let card;
|
||||
switch (data.media_type) {
|
||||
case "audio":
|
||||
card = <AudioCard key={index} data={data} />;
|
||||
break;
|
||||
case "image":
|
||||
card = <ImageCard key={index} data={data} />;
|
||||
break;
|
||||
case "video":
|
||||
card = <VideoCard key={index} data={data} />;
|
||||
break;
|
||||
default:
|
||||
card = <div key={index}>Unsupported media type</div>;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="col-12 col-sm-6 col-xl-4 grid-item"
|
||||
>
|
||||
{card}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</MasonryGrid>
|
||||
</InfiniteScroll>
|
||||
{data.map((data, index) => {
|
||||
let card;
|
||||
switch (data.media_type) {
|
||||
case "audio":
|
||||
card = <AudioCard key={index} data={data} type="media" />;
|
||||
break;
|
||||
case "image":
|
||||
card = <ImageCard key={index} data={data} type="media" />;
|
||||
break;
|
||||
case "video":
|
||||
card = <VideoCard key={index} data={data} />;
|
||||
break;
|
||||
default:
|
||||
card = <div key={index}>Unsupported media type</div>;
|
||||
}
|
||||
return (
|
||||
<div key={index} className="col-12 col-sm-6 col-xl-4 grid-item">
|
||||
{card}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</MasonryGrid>
|
||||
)}
|
||||
</AudioPlayerProvider>
|
||||
</Panel>
|
||||
|
||||
@@ -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 MediaTab() {
|
||||
const [data, setData] = useState(mockWeightsData);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const gridContainerRef = useRef<HTMLDivElement | null>(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 (
|
||||
<Panel clear={true} padding={true}>
|
||||
<div className="d-flex gap-2 mb-3">
|
||||
<Select
|
||||
icon={faArrowDownWideShort}
|
||||
options={sortOptions}
|
||||
defaultValue={sortOptions[0]}
|
||||
isSearchable={false}
|
||||
/>
|
||||
<Select
|
||||
icon={faFilter}
|
||||
options={filterOptions}
|
||||
defaultValue={filterOptions[0]}
|
||||
isSearchable={false}
|
||||
/>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className="row gx-3 gy-3">
|
||||
{Array.from({ length: 6 }).map((_, index) => (
|
||||
<SkeletonCard key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<MasonryGrid
|
||||
gridRef={gridContainerRef}
|
||||
onLayoutComplete={() => console.log("Layout complete!")}
|
||||
>
|
||||
{data.map((data, index) => {
|
||||
let card;
|
||||
switch (data.media_type) {
|
||||
case "audio":
|
||||
card = <AudioCard key={index} data={data} type="weights" />;
|
||||
break;
|
||||
case "image":
|
||||
card = <ImageCard key={index} data={data} type="weights" />;
|
||||
break;
|
||||
case "video":
|
||||
card = <VideoCard key={index} data={data} />;
|
||||
break;
|
||||
default:
|
||||
card = <div key={index}>Unsupported media type</div>;
|
||||
}
|
||||
return (
|
||||
<div key={index} className="col-12 col-sm-6 col-xl-4 grid-item">
|
||||
{card}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</MasonryGrid>
|
||||
)}
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
let mockData = [
|
||||
let mockMediaData = [
|
||||
{
|
||||
token: "token1",
|
||||
weight_name: "Queen Elizabeth",
|
||||
@@ -381,4 +381,4 @@ let mockData = [
|
||||
},
|
||||
];
|
||||
|
||||
export default mockData;
|
||||
export default mockMediaData;
|
||||
@@ -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;
|
||||
Reference in new issue
Block a user