mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 09:48:44 +00:00
Merge pull request #433 from storytold/bflat-fy-explore-endpoints
weights endpoint and masonry grid scrolling to top bug fix
This commit is contained in:
12 files changed
+345
-211
No files matched your search
@@ -8,3 +8,17 @@ export enum WeightType {
|
||||
LORA = "loRA",
|
||||
VALL_E = "vall_e",
|
||||
}
|
||||
|
||||
export const weightTypeInfo = {
|
||||
[WeightType.TT2]: { label: "TT2", color: "teal" },
|
||||
[WeightType.HIFIGAN_TT2]: {
|
||||
label: "HifiGAN TT2",
|
||||
color: "blue",
|
||||
},
|
||||
[WeightType.RVCv2]: { label: "RVCv2", color: "orange" },
|
||||
[WeightType.SD_15]: { label: "SD 1.5", color: "green" },
|
||||
[WeightType.SDXL]: { label: "SDXL", color: "purple" },
|
||||
[WeightType.SVC]: { label: "SVC", color: "cyan" },
|
||||
[WeightType.LORA]: { label: "LoRA", color: "pink" },
|
||||
[WeightType.VALL_E]: { label: "VALL-E", color: "ultramarine" },
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import MakeRequest from "../MakeRequest";
|
||||
import { MediaFile } from "./GetMedia";
|
||||
// import { MediaFileType } from "../_common/enums/MediaFileType";
|
||||
import { LazyPagination } from "../_common/SharedFetchTypes";
|
||||
|
||||
export interface ListMediaFilesRequest {}
|
||||
|
||||
@@ -1,28 +1,42 @@
|
||||
// import MakeRequest from "../MakeRequest";
|
||||
import MakeRequest from "../MakeRequest";
|
||||
import { UserDetailsLight } from "../_common/UserDetailsLight";
|
||||
import { WeightCategory } from "../_common/enums/WeightCategory";
|
||||
import { WeightType } from "../_common/enums/WeightType";
|
||||
|
||||
export interface Weight {
|
||||
weight_token: string;
|
||||
weight_type: WeightType;
|
||||
weight_category: WeightCategory;
|
||||
maybe_creator_user: UserDetailsLight | null;
|
||||
weights_type: WeightType;
|
||||
weights_category: WeightCategory;
|
||||
title: string;
|
||||
public_bucket_path: string;
|
||||
creator_set_visibility: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
title: string;
|
||||
creator: UserDetailsLight;
|
||||
description_markdown: string;
|
||||
description_rendered_html: string;
|
||||
file_checksum_sha2: string;
|
||||
file_size_bytes: number;
|
||||
maybe_cached_user_ratings_ratio: number | null;
|
||||
maybe_cover_image_public_bucket_path: string | null;
|
||||
version: number;
|
||||
}
|
||||
|
||||
// export interface GetMediaRequest {}
|
||||
export interface GetWeightRequest {
|
||||
weight_token: "string";
|
||||
}
|
||||
|
||||
// export interface GetMediaResponse {
|
||||
// success: boolean,
|
||||
// media_file?: MediaFile,
|
||||
// }
|
||||
export interface GetWeightResponse {
|
||||
success: boolean;
|
||||
media_file?: Weight;
|
||||
}
|
||||
|
||||
// export const GetMedia = MakeRequest<string, GetMediaRequest, GetMediaResponse, {}>({
|
||||
// method: "GET",
|
||||
// routingFunction: (mediaFileToken: string) => `/v1/media_files/file/${mediaFileToken}`,
|
||||
// });
|
||||
export const GetWeight = MakeRequest<
|
||||
string,
|
||||
GetWeightRequest,
|
||||
GetWeightResponse,
|
||||
{}
|
||||
>({
|
||||
method: "GET",
|
||||
routingFunction: (weightToken: string) => `/v1/weights/weight/${weightToken}`,
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import MakeRequest from "../MakeRequest";
|
||||
import { Weight } from "./GetWeight";
|
||||
import { LazyPagination } from "../_common/SharedFetchTypes";
|
||||
|
||||
export interface ListWeightsRequest {}
|
||||
|
||||
export interface ListWeightsResponse {
|
||||
pagination: LazyPagination;
|
||||
success: boolean;
|
||||
results: Weight[];
|
||||
}
|
||||
|
||||
export interface ListWeightsParams {
|
||||
page_index: number;
|
||||
}
|
||||
|
||||
export const ListWeights = MakeRequest<
|
||||
string,
|
||||
ListWeightsRequest,
|
||||
ListWeightsResponse,
|
||||
ListWeightsParams
|
||||
>({
|
||||
method: "GET",
|
||||
routingFunction: () => `/v1/weights/list`,
|
||||
});
|
||||
@@ -25,13 +25,11 @@ export default function AudioCard({
|
||||
}: AudioCardProps) {
|
||||
const history = useHistory();
|
||||
|
||||
// console.log("🐙",data, data.public_bucket_path);
|
||||
|
||||
const handleCardClick = () => {
|
||||
if (type === "media") {
|
||||
history.push(`/media/${data.token}`);
|
||||
} else if (type === "weights") {
|
||||
history.push(`/weight/${data.token}`);
|
||||
history.push(`/weight/${data.weight_token}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,13 +79,15 @@ export default function AudioCard({
|
||||
{showCreator && (
|
||||
<div className="flex-grow-1">
|
||||
<CreatorName
|
||||
displayName={data.maybe_creator.display_name}
|
||||
gravatarHash={data.maybe_creator.gravatar_hash}
|
||||
avatarIndex={data.maybe_creator.default_avatar.image_index}
|
||||
backgroundIndex={
|
||||
data.maybe_creator.default_avatar.color_index
|
||||
displayName={data.maybe_creator?.display_name || "Anonymous"}
|
||||
gravatarHash={data.maybe_creator?.gravatar_hash || null}
|
||||
avatarIndex={
|
||||
data.maybe_creator?.default_avatar.image_index || 0
|
||||
}
|
||||
username={data.maybe_creator.username}
|
||||
backgroundIndex={
|
||||
data.maybe_creator?.default_avatar.color_index || 0
|
||||
}
|
||||
username={data.maybe_creator?.username || "anonymous"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -126,9 +126,7 @@ export default function AudioCard({
|
||||
|
||||
<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>
|
||||
<h6 className="fw-semibold text-white mb-1">{data.title}</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -144,15 +142,13 @@ export default function AudioCard({
|
||||
{showCreator && (
|
||||
<div className="flex-grow-1">
|
||||
<CreatorName
|
||||
displayName={data.maybe_creator_user.display_name}
|
||||
gravatarHash={data.maybe_creator_user.gravatar_hash}
|
||||
avatarIndex={
|
||||
data.maybe_creator_user.default_avatar.image_index
|
||||
}
|
||||
displayName={data.creator?.display_name || "Anonymous"}
|
||||
gravatarHash={data.creator?.gravatar_hash || null}
|
||||
avatarIndex={data.creator?.default_avatar.image_index || 0}
|
||||
backgroundIndex={
|
||||
data.maybe_creator_user.default_avatar.color_index
|
||||
data.creator?.default_avatar.color_index || 0
|
||||
}
|
||||
username={data.maybe_creator_user.username}
|
||||
username={data.creator?.username || "anonymous"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,7 @@ import FavoriteButton from "components/common/FavoriteButton";
|
||||
import CreatorName from "../CreatorName";
|
||||
import Button from "components/common/Button";
|
||||
import { faArrowRight } from "@fortawesome/pro-solid-svg-icons";
|
||||
import useWeightTypeInfo from "hooks/useWeightTypeInfo/useWeightTypeInfo";
|
||||
|
||||
interface ImageCardProps {
|
||||
data: any;
|
||||
@@ -22,7 +23,7 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
if (type === "media") {
|
||||
history.push(`/media/${data.token}`);
|
||||
} else if (type === "weights") {
|
||||
history.push(`/weight/${data.token}`);
|
||||
history.push(`/weight/${data.weight_token}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -36,6 +37,9 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
console.log(`The item is now ${data.isLiked ? "liked" : "not liked"}.`);
|
||||
};
|
||||
|
||||
const { label: weightBadgeLabel, color: weightBadgeColor } =
|
||||
useWeightTypeInfo(data.weights_type);
|
||||
|
||||
return (
|
||||
<Card padding={false} onClick={handleCardClick}>
|
||||
{type === "media" && (
|
||||
@@ -68,11 +72,17 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
{showCreator && (
|
||||
<div className="flex-grow-1">
|
||||
<CreatorName
|
||||
displayName={data.maybe_creator?.display_name || "" } // these empty strings are fallbacks to prevent errors
|
||||
gravatarHash={data.maybe_creator?.gravatar_hash || "" } // since maybe_creator does not exist until loaded
|
||||
avatarIndex={data.maybe_creator?.default_avatar.image_index || "" } // consider wrapping everything that uses
|
||||
backgroundIndex={data.maybe_creator?.default_avatar.color_index || "" } // !!maybe_creator condition
|
||||
username={data.maybe_creator?.username || "" } // which only displays when that value is defined
|
||||
displayName={
|
||||
data.maybe_creator?.display_name || "Anonymous"
|
||||
}
|
||||
gravatarHash={data.maybe_creator?.gravatar_hash || null}
|
||||
avatarIndex={
|
||||
data.maybe_creator?.default_avatar.image_index || 0
|
||||
}
|
||||
backgroundIndex={
|
||||
data.maybe_creator?.default_avatar.color_index || 0
|
||||
}
|
||||
username={data.maybe_creator?.username || "anonymous"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -89,15 +99,22 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
{type === "weights" && (
|
||||
<>
|
||||
<img
|
||||
src={data.public_bucket_path}
|
||||
alt={data.weight_name}
|
||||
src={
|
||||
data.maybe_cover_image_public_bucket_path ||
|
||||
"/images/avatars/default-pfp.png"
|
||||
}
|
||||
alt={data.title}
|
||||
className="card-img"
|
||||
/>
|
||||
<div className="card-img-overlay">
|
||||
<div className="card-img-gradient" />
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<Badge label="LORA" color="pink" overlay={true} />
|
||||
<Badge
|
||||
label={weightBadgeLabel}
|
||||
color={weightBadgeColor}
|
||||
overlay={true}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
icon={faArrowRight}
|
||||
@@ -112,9 +129,7 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
<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>
|
||||
<h6 className="fw-semibold text-white mb-1">{data.title}</h6>
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,15 +143,15 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
{showCreator && (
|
||||
<div className="flex-grow-1">
|
||||
<CreatorName
|
||||
displayName={data.maybe_creator?.display_name || "" }
|
||||
gravatarHash={data.maybe_creator?.gravatar_hash}
|
||||
displayName={data.creator?.display_name || "Anonymous"}
|
||||
gravatarHash={data.creator?.gravatar_hash || null}
|
||||
avatarIndex={
|
||||
data.maybe_creator?.default_avatar.image_index
|
||||
data.creator?.default_avatar.image_index || 0
|
||||
}
|
||||
backgroundIndex={
|
||||
data.maybe_creator?.default_avatar.color_index
|
||||
data.creator?.default_avatar.color_index || 0
|
||||
}
|
||||
username={data.maybe_creator?.username}
|
||||
username={data.creator?.username || "anonymous"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -144,10 +159,7 @@ export default function ImageCard({ data, type, showCreator }: ImageCardProps) {
|
||||
<div>
|
||||
<LikeButton onToggle={handleLike} likeCount={data.likes} />
|
||||
</div>
|
||||
<FavoriteButton
|
||||
onToggle={handleLike}
|
||||
favoriteCount={data.likes}
|
||||
/>
|
||||
<FavoriteButton onToggle={handleLike} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,11 +64,17 @@ export default function VideoCard({ data, type, showCreator }: VideoCardProps) {
|
||||
{showCreator && (
|
||||
<div className="flex-grow-1">
|
||||
<CreatorName
|
||||
displayName={data.maybe_creator?.display_name || "" }
|
||||
gravatarHash={data.maybe_creator?.gravatar_hash || "" }
|
||||
avatarIndex={data.maybe_creator?.default_avatar.image_index || "" }
|
||||
backgroundIndex={data.maybe_creator?.default_avatar.color_index || "" }
|
||||
username={data.maybe_creator?.username || "" }
|
||||
displayName={
|
||||
data.maybe_creator?.display_name || "Anonymous"
|
||||
}
|
||||
gravatarHash={data.maybe_creator?.gravatar_hash || ""}
|
||||
avatarIndex={
|
||||
data.maybe_creator?.default_avatar.image_index || ""
|
||||
}
|
||||
backgroundIndex={
|
||||
data.maybe_creator?.default_avatar.color_index || ""
|
||||
}
|
||||
username={data.maybe_creator?.username || "anonymous"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import Masonry from "masonry-layout";
|
||||
import imagesLoaded from "imagesloaded";
|
||||
|
||||
interface MasonryGridProps {
|
||||
children: React.ReactNode;
|
||||
@@ -13,38 +13,77 @@ export default function MasonryGrid({
|
||||
onLayoutComplete,
|
||||
gridRef,
|
||||
}: MasonryGridProps) {
|
||||
const masonryInstance = useRef<Masonry | null>(null);
|
||||
|
||||
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, {
|
||||
masonryInstance.current = new Masonry(gridRef.current, {
|
||||
itemSelector: ".grid-item",
|
||||
percentPosition: true,
|
||||
transitionDuration: 0,
|
||||
});
|
||||
|
||||
//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();
|
||||
if (
|
||||
masonryInstance.current &&
|
||||
typeof masonryInstance.current.destroy === "function"
|
||||
) {
|
||||
masonryInstance.current.destroy();
|
||||
}
|
||||
};
|
||||
}, [gridRef]);
|
||||
|
||||
useEffect(() => {
|
||||
const currentGrid = gridRef.current;
|
||||
const currentMasonryInstance = masonryInstance.current;
|
||||
|
||||
if (currentGrid && currentMasonryInstance) {
|
||||
imagesLoaded(currentGrid, function () {
|
||||
if (typeof currentMasonryInstance.layout === "function") {
|
||||
currentMasonryInstance.layout();
|
||||
onLayoutComplete?.();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [gridRef, onLayoutComplete]);
|
||||
|
||||
useEffect(() => {
|
||||
const currentGrid = gridRef.current;
|
||||
const currentMasonryInstance = masonryInstance.current;
|
||||
|
||||
if (currentGrid && currentMasonryInstance) {
|
||||
// Observer to detect when new grid items are added
|
||||
const observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(mutation => {
|
||||
if (mutation.addedNodes.length) {
|
||||
// Append new items to the Masonry layout
|
||||
const newItems = Array.from(mutation.addedNodes).filter(
|
||||
node =>
|
||||
node instanceof HTMLElement &&
|
||||
node.classList.contains("grid-item")
|
||||
);
|
||||
if (newItems.length) {
|
||||
if (typeof currentMasonryInstance.appended === "function") {
|
||||
currentMasonryInstance.appended(newItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Observe the grid for new items
|
||||
observer.observe(currentGrid, {
|
||||
childList: true,
|
||||
});
|
||||
|
||||
// Clean up observer on unmount
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}
|
||||
}, [gridRef]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={gridRef}
|
||||
|
||||
@@ -87,17 +87,14 @@ function Tabs({ tabs }: TabsProps) {
|
||||
))}
|
||||
</ul>
|
||||
<TabContent padding={activeTabProps?.padding}>
|
||||
{tabs.map(tab => (
|
||||
<a.div
|
||||
key={tab.to}
|
||||
style={fade}
|
||||
className={`tab-pane fade ${
|
||||
activeTab === tab.to ? "show active" : ""
|
||||
}`}
|
||||
>
|
||||
{tab.content}
|
||||
</a.div>
|
||||
))}
|
||||
<a.div
|
||||
style={fade}
|
||||
className={`tab-pane fade ${
|
||||
activeTab === activeTabProps?.to ? "show active" : ""
|
||||
}`}
|
||||
>
|
||||
{activeTabProps?.content}
|
||||
</a.div>
|
||||
</TabContent>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { WeightType } from "@storyteller/components/src/api/_common/enums/WeightType";
|
||||
|
||||
type WeightTypeInfo = {
|
||||
[key in WeightType]: { label: string; color: string };
|
||||
};
|
||||
|
||||
const weightTypeInfo: WeightTypeInfo = {
|
||||
[WeightType.TT2]: { label: "TT2", color: "teal" },
|
||||
[WeightType.HIFIGAN_TT2]: { label: "HifiGAN TT2", color: "blue" },
|
||||
[WeightType.RVCv2]: { label: "RVCv2", color: "orange" },
|
||||
[WeightType.SD_15]: { label: "SD 1.5", color: "green" },
|
||||
[WeightType.SDXL]: { label: "SDXL", color: "purple" },
|
||||
[WeightType.SVC]: { label: "SVC", color: "cyan" },
|
||||
[WeightType.LORA]: { label: "LoRA", color: "pink" },
|
||||
[WeightType.VALL_E]: { label: "VALL-E", color: "ultramarine" },
|
||||
};
|
||||
|
||||
export default function useWeightTypeInfo(weightsType: WeightType) {
|
||||
return (
|
||||
weightTypeInfo[weightsType] || {
|
||||
label: "Unknown",
|
||||
color: "gray",
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import SkeletonCard from "components/common/Card/SkeletonCard";
|
||||
import { Link } from "react-router-dom";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faChevronRight } from "@fortawesome/pro-solid-svg-icons";
|
||||
import ImageCard from "components/common/Card/ImageCard";
|
||||
|
||||
export default function FeaturedTab() {
|
||||
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -59,7 +58,7 @@ export default function FeaturedTab() {
|
||||
</MasonryGrid>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{/* <div>
|
||||
<div className="d-flex align-items-center mb-3">
|
||||
<h3 className="fw-semibold mb-0 flex-grow-1">
|
||||
Featured Image Weights
|
||||
@@ -98,7 +97,7 @@ export default function FeaturedTab() {
|
||||
})}
|
||||
</MasonryGrid>
|
||||
)}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,149 +1,157 @@
|
||||
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 Select from "components/common/Select";
|
||||
// import VideoCard from "components/common/Card/VideoCard";
|
||||
import { TempSelect } from "components/common";
|
||||
import {
|
||||
faArrowDownWideShort,
|
||||
faFilter,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import AudioPlayerProvider from "components/common/AudioPlayer/AudioPlayerContext";
|
||||
import SkeletonCard from "components/common/Card/SkeletonCard";
|
||||
import { ListWeights } from "@storyteller/components/src/api/weights/ListWeights";
|
||||
import { Weight } from "@storyteller/components/src/api/weights/GetWeight";
|
||||
import { useLazyLists } from "hooks";
|
||||
import InfiniteScroll from "react-infinite-scroll-component";
|
||||
import { WeightCategory } from "@storyteller/components/src/api/_common/enums/WeightCategory";
|
||||
|
||||
export default function WeightsTab() {
|
||||
export default function MediaTab() {
|
||||
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [data] = useState(mockWeightsData);
|
||||
const [isLoading] = useState(false);
|
||||
const [selectedFilter, setSelectedFilter] = useState("all");
|
||||
|
||||
const [list, listSet] = useState<Weight[]>([]);
|
||||
const weights = useLazyLists({
|
||||
fetcher: ListWeights,
|
||||
list,
|
||||
listSet,
|
||||
requestList: true,
|
||||
});
|
||||
|
||||
const filterOptions = [
|
||||
{ value: "all", label: "All Weights" },
|
||||
{ value: "tts", label: "Text to Speech" },
|
||||
{ value: "vc", label: "Voice to Voice" },
|
||||
{ value: "sd", label: "Image Generation" },
|
||||
{ value: "images", label: "Image Generation" },
|
||||
{ value: "audio", label: "Audio" },
|
||||
{ value: "video", label: "Video" },
|
||||
];
|
||||
|
||||
const sortOptions = [
|
||||
{ value: "newest", label: "Newest" },
|
||||
{ value: "oldest", label: "Oldest" },
|
||||
{ value: "mostliked", label: "Most Bookmarked" },
|
||||
{ value: "mostliked", label: "Most Liked" },
|
||||
];
|
||||
|
||||
const modelTtsOptions = [
|
||||
{ value: "all", label: "All Types" },
|
||||
{ value: "tt2", label: "Tacotron 2" },
|
||||
];
|
||||
|
||||
const modelVcOptions = [
|
||||
{ value: "all", label: "All Types" },
|
||||
{ value: "rvc", label: "RVCv2" },
|
||||
{ value: "svc", label: "SoVitsSvc" },
|
||||
];
|
||||
|
||||
const modelSdOptions = [
|
||||
{ value: "all", label: "All Types" },
|
||||
{ value: "lora", label: "LoRA" },
|
||||
{ value: "SD15", label: "SD 1.5" },
|
||||
{ value: "SDXL", label: "SD XL" },
|
||||
];
|
||||
|
||||
const handleFilterChange = (option: any) => {
|
||||
const selectedOption = option as { value: string; label: string };
|
||||
setSelectedFilter(selectedOption.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex flex-wrap gap-3 mb-3">
|
||||
<div className="d-flex gap-2 flex-grow-1">
|
||||
<Select
|
||||
icon={faArrowDownWideShort}
|
||||
options={sortOptions}
|
||||
defaultValue={sortOptions[0]}
|
||||
isSearchable={false}
|
||||
<TempSelect
|
||||
{...{
|
||||
icon: faArrowDownWideShort,
|
||||
options: sortOptions,
|
||||
name: "sort",
|
||||
onChange: weights.onChange,
|
||||
value: weights.sort,
|
||||
}}
|
||||
/>
|
||||
|
||||
<Select
|
||||
icon={faFilter}
|
||||
options={filterOptions}
|
||||
defaultValue={filterOptions[0]}
|
||||
isSearchable={false}
|
||||
onChange={handleFilterChange}
|
||||
<TempSelect
|
||||
{...{
|
||||
icon: faFilter,
|
||||
options: filterOptions,
|
||||
name: "filter",
|
||||
onChange: weights.onChange,
|
||||
value: weights.filter,
|
||||
}}
|
||||
/>
|
||||
|
||||
{selectedFilter === "tts" && (
|
||||
<Select
|
||||
options={modelTtsOptions}
|
||||
defaultValue={modelTtsOptions[0]}
|
||||
isSearchable={false}
|
||||
/>
|
||||
)}
|
||||
{selectedFilter === "sd" && (
|
||||
<Select
|
||||
options={modelSdOptions}
|
||||
defaultValue={modelSdOptions[0]}
|
||||
isSearchable={false}
|
||||
/>
|
||||
)}
|
||||
{selectedFilter === "vc" && (
|
||||
<Select
|
||||
options={modelVcOptions}
|
||||
defaultValue={modelVcOptions[0]}
|
||||
isSearchable={false}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</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"
|
||||
showCreator={true}
|
||||
showCover={true}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "image":
|
||||
card = (
|
||||
<ImageCard
|
||||
key={index}
|
||||
data={data}
|
||||
type="weights"
|
||||
showCreator={true}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "video":
|
||||
card = <VideoCard key={index} data={data} type="weights" />;
|
||||
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}
|
||||
<AudioPlayerProvider>
|
||||
{isLoading ? (
|
||||
<div className="row gx-3 gy-3">
|
||||
{Array.from({ length: 6 }).map((_, index) => (
|
||||
<SkeletonCard key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<InfiniteScroll
|
||||
dataLength={weights.list.length}
|
||||
next={weights.getMore}
|
||||
hasMore={!weights.list.length || !!weights.next}
|
||||
loader={
|
||||
<div className="mt-4 d-flex justify-content-center">
|
||||
<div className="spinner-border text-light" role="status">
|
||||
<span className="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</MasonryGrid>
|
||||
)}
|
||||
}
|
||||
endMessage={
|
||||
<p className="text-center mt-4 opacity-75">No more results.</p>
|
||||
}
|
||||
className="overflow-hidden"
|
||||
>
|
||||
<MasonryGrid
|
||||
gridRef={gridContainerRef}
|
||||
onLayoutComplete={() => console.log("Layout complete!")}
|
||||
>
|
||||
{weights.list.map((data: any, index: number) => {
|
||||
let card;
|
||||
switch (data.weights_category) {
|
||||
case WeightCategory.TTS:
|
||||
card = (
|
||||
<AudioCard
|
||||
key={index}
|
||||
data={data}
|
||||
type="weights"
|
||||
showCreator={true}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case WeightCategory.VC:
|
||||
card = (
|
||||
<AudioCard
|
||||
key={index}
|
||||
data={data}
|
||||
type="weights"
|
||||
showCreator={true}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case WeightCategory.ZS:
|
||||
card = (
|
||||
<AudioCard
|
||||
key={index}
|
||||
data={data}
|
||||
type="weights"
|
||||
showCreator={true}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case WeightCategory.SD:
|
||||
card = (
|
||||
<ImageCard
|
||||
key={index}
|
||||
data={data}
|
||||
type="weights"
|
||||
showCreator={true}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
card = <div>Unsupported weight type</div>;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="col-12 col-sm-6 col-xl-4 grid-item"
|
||||
>
|
||||
{card}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</MasonryGrid>
|
||||
</InfiniteScroll>
|
||||
)}
|
||||
</AudioPlayerProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user