mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
updates
This commit is contained in:
1 parent
cf3f79dc5f
commit
a65267ec7f
11 files changed
+141
-38
No files matched your search
@@ -4,7 +4,7 @@
|
||||
font-weight: 500;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 13px;
|
||||
padding: 9px 12px;
|
||||
padding: 6px 12px;
|
||||
background-color: $secondary;
|
||||
color: $white;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -3,13 +3,17 @@ import "./CheckableTag.scss";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faXmark } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface Props {
|
||||
interface CheckableTagProps {
|
||||
tag: string;
|
||||
isSelected: boolean;
|
||||
onToggle: (tag: string) => void;
|
||||
}
|
||||
|
||||
export default function CheckableTag({ tag, isSelected, onToggle }: Props) {
|
||||
export default function CheckableTag({
|
||||
tag,
|
||||
isSelected,
|
||||
onToggle,
|
||||
}: CheckableTagProps) {
|
||||
return (
|
||||
<div
|
||||
className={`d-flex align-items-center checkable-tag ${
|
||||
|
||||
@@ -2,12 +2,12 @@ import React from "react";
|
||||
import Input from "../Input";
|
||||
import { faSearch } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface Props {
|
||||
interface ModelSearchProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export default function ModelSearch({ value, onChange }: Props) {
|
||||
export default function ModelSearch({ value, onChange }: ModelSearchProps) {
|
||||
return (
|
||||
<Input
|
||||
icon={faSearch}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export const dummyData = [
|
||||
{ id: 1, name: "Item 1", tags: ["tag1", "tag2"] },
|
||||
{ id: 2, name: "Item 2", tags: ["tag2", "tag3"] },
|
||||
];
|
||||
+12
-2
@@ -5,14 +5,20 @@
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid lighten($panel, 12%);
|
||||
|
||||
.creator-name {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: $white;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.type-tag {
|
||||
font-weight: 600;
|
||||
border-radius: 0.4rem;
|
||||
border-radius: 0.35rem;
|
||||
font-size: 13px;
|
||||
padding: 4px 8px;
|
||||
background-color: $secondary;
|
||||
color: $white;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
@@ -26,4 +32,8 @@
|
||||
background-color: #c6c7e1;
|
||||
}
|
||||
}
|
||||
|
||||
.model-details {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
+59
-16
@@ -1,28 +1,71 @@
|
||||
import React from "react";
|
||||
import "./ModelSearchResults.scss";
|
||||
import { Link } from "react-router-dom";
|
||||
import Button from "../Button";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faChartSimple,
|
||||
faComment,
|
||||
faHeart,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface Props {
|
||||
interface ModelSearchResultsProps {
|
||||
data: any[];
|
||||
}
|
||||
|
||||
export default function ModelSearchResults({ data }: Props) {
|
||||
function shortenNumber(num: number): string {
|
||||
if (Math.abs(num) < 1e3) return num.toString();
|
||||
if (Math.abs(num) < 1e6) return (num / 1e3).toFixed(1) + "k";
|
||||
if (Math.abs(num) < 1e9) return (num / 1e6).toFixed(1) + "M";
|
||||
return num.toString();
|
||||
}
|
||||
|
||||
export default function ModelSearchResults({ data }: ModelSearchResultsProps) {
|
||||
return (
|
||||
<div className="row g-3">
|
||||
{data.map((item) => (
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="model-search-results p-3" key={item.id}>
|
||||
<h5 className="fw-semibold mb-0">{item.name}</h5>
|
||||
<p className="">by {item.creator}</p>
|
||||
<span
|
||||
className={`type-tag ${
|
||||
item.type === "Tacotron2" ? "tt2" : "tt2"
|
||||
}`}
|
||||
>
|
||||
{item.type}
|
||||
</span>
|
||||
{data.map((item) => {
|
||||
return (
|
||||
<div className="col-12 col-lg-6" key={item.id}>
|
||||
<div className="model-search-results p-3">
|
||||
<h5 className="fw-semibold mb-0">{item.name}</h5>
|
||||
<p className="creator-name">
|
||||
by{" "}
|
||||
<Link className="fw-medium" to={`/profile/${item.creator}`}>
|
||||
{item.creator}
|
||||
</Link>
|
||||
</p>
|
||||
<div className="d-flex align-items-end">
|
||||
<div className="flex-grow-1">
|
||||
<span
|
||||
className={`type-tag ${
|
||||
item.type === "Tacotron2" ? "tt2" : "tt2"
|
||||
}`}
|
||||
>
|
||||
{item.type}
|
||||
</span>
|
||||
<div className="d-flex gap-3 model-details fw-medium mt-3">
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faHeart} className="me-2" />
|
||||
{item.likes && shortenNumber(item.likes)}
|
||||
</div>
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faChartSimple} className="me-2" />
|
||||
{item.uses && shortenNumber(item.uses)}
|
||||
</div>
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faComment} className="me-2" />
|
||||
{item.comments && shortenNumber(item.comments)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Button label="Use Voice" small={true} to="/" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
import React from "react";
|
||||
import CheckableTag from "../CheckableTag";
|
||||
|
||||
interface Props {
|
||||
interface ModelTagsProps {
|
||||
tags: string[];
|
||||
selectedTags: string[];
|
||||
onSelectTag: (tag: string) => void;
|
||||
}
|
||||
|
||||
export default function ModelTags({ tags, selectedTags, onSelectTag }: Props) {
|
||||
export default function ModelTags({
|
||||
tags,
|
||||
selectedTags,
|
||||
onSelectTag,
|
||||
}: ModelTagsProps) {
|
||||
return (
|
||||
<div className="d-flex gap-2 flex-wrap">
|
||||
{tags.map((tag) => (
|
||||
|
||||
@@ -41,13 +41,15 @@ export default function PageHeader({
|
||||
{icon}
|
||||
{title}
|
||||
</h2>
|
||||
{showButton && (
|
||||
<Button
|
||||
variant={buttonVariant}
|
||||
label={buttonLabel}
|
||||
to={buttonTo}
|
||||
/>
|
||||
)}
|
||||
<div className="d-none d-md-block">
|
||||
{showButton && (
|
||||
<Button
|
||||
variant={buttonVariant}
|
||||
label={buttonLabel}
|
||||
to={buttonTo}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p>{subText}</p>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./useShortenNumber";
|
||||
@@ -0,0 +1,6 @@
|
||||
export default function useShortenNumber(num: number): string {
|
||||
if (Math.abs(num) < 1e3) return num.toString();
|
||||
if (Math.abs(num) < 1e6) return (num / 1e3).toFixed(1) + "k";
|
||||
if (Math.abs(num) < 1e9) return (num / 1e6).toFixed(1) + "M";
|
||||
return num.toString();
|
||||
}
|
||||
@@ -2,12 +2,13 @@ import React from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import Container from "components/common/Container";
|
||||
import PageHeader from "components/layout/PageHeader";
|
||||
import { faMessageDots } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { faClock, faMessageDots } from "@fortawesome/pro-solid-svg-icons";
|
||||
import ModelSearch from "components/common/ModelSearch";
|
||||
import Panel from "components/common/Panel";
|
||||
import useSearch from "hooks/useSearch/useSearch";
|
||||
import ModelSearchResults from "components/common/ModelSearchResults";
|
||||
import ModelTags from "components/common/ModelTags";
|
||||
import Select from "components/common/Select";
|
||||
|
||||
interface TtsModelSearchPageProps {
|
||||
sessionWrapper: SessionWrapper;
|
||||
@@ -19,18 +20,33 @@ const dummyData = [
|
||||
name: "Spongebob",
|
||||
tags: ["English", "High-pitched", "Character"],
|
||||
type: "Tacotron2",
|
||||
creator: "echelon",
|
||||
likes: 14000,
|
||||
uses: 1000000,
|
||||
comments: 250,
|
||||
time: new Date("2023-09-20T12:00:00Z").toISOString(),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Mariano Closs",
|
||||
tags: ["Spanish", "Low-pitched"],
|
||||
type: "Tacotron2",
|
||||
creator: "echelon",
|
||||
likes: 308290,
|
||||
uses: 30000000,
|
||||
comments: 1200,
|
||||
time: new Date("2023-10-12T12:00:00Z").toISOString(),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Cristiano Ronaldo",
|
||||
tags: ["Portuguese", "Low-pitched"],
|
||||
type: "Tacotron2",
|
||||
creator: "echelon",
|
||||
likes: 17500,
|
||||
uses: 40000000,
|
||||
comments: 250,
|
||||
time: new Date("2023-09-20T12:00:00Z").toISOString(),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -72,12 +88,24 @@ export default function TtsModelSearchPage(props: TtsModelSearchPageProps) {
|
||||
</div>
|
||||
);
|
||||
|
||||
const sortOptions = [
|
||||
{ value: "most liked", label: "Most Liked" },
|
||||
{ value: "most used", label: "Most Used" },
|
||||
{ value: "moset recent", label: "Most Recent" },
|
||||
];
|
||||
const sortTimeOptions = [
|
||||
{ value: "all time", label: "All Time" },
|
||||
{ value: "today", label: "Today" },
|
||||
{ value: "this week", label: "This Week" },
|
||||
{ value: "this month", label: "This Month" },
|
||||
];
|
||||
|
||||
return (
|
||||
<Container type="panel">
|
||||
<PageHeader
|
||||
title="Text to Speech"
|
||||
titleIcon={faMessageDots}
|
||||
subText="Turn text into your favorite character's speaking voice."
|
||||
subText="Turn text into your favorite character's voice."
|
||||
showButton={true}
|
||||
buttonLabel="Create a voice"
|
||||
buttonVariant="secondary"
|
||||
@@ -85,6 +113,15 @@ export default function TtsModelSearchPage(props: TtsModelSearchPageProps) {
|
||||
extension={searchTts}
|
||||
/>
|
||||
<Panel padding={true}>
|
||||
<div className="d-flex gap-2 mb-3">
|
||||
<Select options={sortOptions} defaultValue={sortOptions[0]} />
|
||||
<Select
|
||||
icon={faClock}
|
||||
options={sortTimeOptions}
|
||||
defaultValue={sortTimeOptions[0]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ModelSearchResults data={filteredData} />
|
||||
</Panel>
|
||||
</Container>
|
||||
|
||||
Reference in new issue
Block a user