mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
v2v model view page update
This commit is contained in:
1 parent
0c6e4b7366
commit
9ccd80da31
6 files changed
+190
-47
No files matched your search
@@ -1,17 +1,21 @@
|
||||
import React from "react";
|
||||
import Panel from "./Panel";
|
||||
|
||||
interface PageHeaderModelViewProps {
|
||||
titleIcon?: React.ReactNode;
|
||||
title: string;
|
||||
subText: React.ReactNode;
|
||||
tags?: string[];
|
||||
ratingBtn?: React.ReactNode;
|
||||
ratingStats?: React.ReactNode;
|
||||
extras?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function PageHeaderModelView(props: PageHeaderModelViewProps) {
|
||||
return (
|
||||
<div className="container-panel hero-section pt-3 pb-4">
|
||||
<div className="panel p-3 py-4 p-md-4">
|
||||
<div className="row g-3">
|
||||
<div className="pt-3 pb-4">
|
||||
<Panel padding>
|
||||
<div className="row gy-3">
|
||||
<div className="col-12 col-lg-8">
|
||||
<h2 className="fw-bold">
|
||||
{props.titleIcon}
|
||||
@@ -19,16 +23,27 @@ export default function PageHeaderModelView(props: PageHeaderModelViewProps) {
|
||||
</h2>
|
||||
<p>{props.subText}</p>
|
||||
</div>
|
||||
<div className="col-12 col-lg-4 d-flex flex-wrap justify-content-lg-end gap-2">
|
||||
{props.tags &&
|
||||
props.tags.map((tag, index) => (
|
||||
<div key={index}>
|
||||
<span className="badge badge-tag">{tag}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className="col-12 col-lg-4">
|
||||
<div className="d-flex gap-2 flex-wrap justify-content-lg-end">
|
||||
{props.tags &&
|
||||
props.tags.map((tag, index) => (
|
||||
<div key={index}>
|
||||
<span className="badge badge-tag">{tag}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr className="my-4" />
|
||||
|
||||
<div className="d-flex flex-column flex-lg-row flex-column-reverse gap-3">
|
||||
<div className="d-flex gap-3">
|
||||
{props.ratingBtn}
|
||||
{props.extras}
|
||||
</div>
|
||||
{props.ratingStats}
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -12,7 +12,7 @@ export default function Panel(props: PanelProps) {
|
||||
return (
|
||||
<motion.div className="container-panel" variants={panel}>
|
||||
<div
|
||||
className={`panel ${props.padding ? "p-3 py-4 p-md-4" : ""} ${
|
||||
className={`panel ${props.padding ? "p-3 py-lg-4 p-md-4" : ""} ${
|
||||
props.mb ? "mb-4" : ""
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, { useState } from "react";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faLink } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface ShareButtonProps {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function ShareButton(props: ShareButtonProps) {
|
||||
const [tippyContent, setTippyContent] = useState("Share");
|
||||
|
||||
const copyToClipboard = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(props.url);
|
||||
setTippyContent("Link Copied");
|
||||
setTimeout(() => {
|
||||
setTippyContent("Share");
|
||||
}, 800);
|
||||
} catch (error) {
|
||||
console.error("Failed to copy link to clipboard:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="d-flex">
|
||||
<Tippy
|
||||
content={tippyContent}
|
||||
hideOnClick={false}
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<button className="btn-share" onClick={copyToClipboard} type="button">
|
||||
<span>
|
||||
<FontAwesomeIcon icon={faLink} className="me-2" />
|
||||
</span>
|
||||
Share Link
|
||||
</button>
|
||||
</Tippy>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -869,18 +869,18 @@ styles with important tags:
|
||||
font-weight: 500;
|
||||
font-size: 17px;
|
||||
background-color: lighten($secondary, 4%);
|
||||
border-radius: 50px;
|
||||
border-radius: 0.5rem;
|
||||
border: none;
|
||||
padding: 6px 20px;
|
||||
color: rgba($white, 0.5);
|
||||
transition: 0.1s all;
|
||||
|
||||
&.left {
|
||||
border-radius: 50px 0px 0px 50px;
|
||||
border-radius: 0.5rem 0px 0px 0.5rem;
|
||||
}
|
||||
|
||||
&.right {
|
||||
border-radius: 0px 50px 50px 5px;
|
||||
border-radius: 0px 0.5rem 0.5rem 0px;
|
||||
}
|
||||
|
||||
&.rated {
|
||||
@@ -893,6 +893,25 @@ styles with important tags:
|
||||
}
|
||||
}
|
||||
|
||||
.btn-share {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
background-color: lighten($secondary, 4%);
|
||||
border-radius: 0.5rem;
|
||||
border: none;
|
||||
padding: 8.25px 20px;
|
||||
color: $white;
|
||||
transition: 0.1s all;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($secondary, 10%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: lighten($secondary, 15%);
|
||||
}
|
||||
}
|
||||
|
||||
.rating-icon {
|
||||
color: #ffbc39;
|
||||
|
||||
|
||||
@@ -504,6 +504,7 @@ class PageContainer extends React.Component<Props, State> {
|
||||
|
||||
<Route path="/voice-conversion/:token">
|
||||
<VcModelViewPage
|
||||
sessionWrapper={this.props.sessionWrapper}
|
||||
sessionSubscriptionsWrapper={
|
||||
this.props.sessionSubscriptionsWrapper
|
||||
}
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
faBarsStaggered,
|
||||
faDeleteLeft,
|
||||
faEdit,
|
||||
faEye,
|
||||
faMemoCircleInfo,
|
||||
faMessages,
|
||||
faTrash,
|
||||
faVolumeHigh,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import Panel from "components/common/Panel";
|
||||
import React from "react";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { SessionVoiceConversionResultsList } from "v2/view/_common/SessionVoiceConversionResultsList";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import PageHeaderModelView from "components/common/PageHeaderModelView";
|
||||
import { CommentComponent } from "v2/view/_common/comments/CommentComponent";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { RatingButtons } from "v2/view/_common/ratings/RatingButtons";
|
||||
import { RatingStats } from "v2/view/_common/ratings/RatingStats";
|
||||
import ShareButton from "components/common/ShareButton";
|
||||
|
||||
interface VcModelViewPageProps {
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
inferenceJobsByCategory: any;
|
||||
}
|
||||
@@ -27,15 +37,59 @@ export default function VcModelViewPage(props: VcModelViewPageProps) {
|
||||
<span className="badge-model badge-model-rvc fs-6">RVCv2</span>
|
||||
</div>
|
||||
<p>
|
||||
V2V model created by <Link to="/">Vegito1089</Link>
|
||||
V2V model by <Link to="/">Vegito1089</Link>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
const tags = ["Speaking", "English", "Character", "Singing", "Spanish"];
|
||||
|
||||
let modelCreatorLink = <Link to="">Creator Name</Link>;
|
||||
let modelTitle = title;
|
||||
let modelUseCount = 10000;
|
||||
let modelLanguage = "English";
|
||||
let modelType = "RVCv2";
|
||||
let modelUploadDate = "2021-09-10T06:15:04Z";
|
||||
let modelVisibility = (
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faEye} className="me-2" />
|
||||
Public
|
||||
</div>
|
||||
);
|
||||
|
||||
const voiceDetails = [
|
||||
{ label: "Creator", value: modelCreatorLink },
|
||||
{ label: "Title", value: modelTitle },
|
||||
{ label: "Use count", value: modelUseCount },
|
||||
{ label: "Spoken language", value: modelLanguage },
|
||||
{ label: "Model type", value: modelType },
|
||||
{ label: "Upload date (UTC)", value: modelUploadDate },
|
||||
{ label: "Visibility", value: modelVisibility },
|
||||
];
|
||||
|
||||
let ratingButtons = <></>;
|
||||
if (props.sessionWrapper.isLoggedIn()) {
|
||||
ratingButtons = (
|
||||
<RatingButtons entity_type="v2v_model" entity_token="test" />
|
||||
);
|
||||
}
|
||||
|
||||
let ratingStats = (
|
||||
<RatingStats positive_votes={100} negative_votes={0} total_votes={100} />
|
||||
);
|
||||
|
||||
const shareUrl = window.location.href;
|
||||
const shareButton = <ShareButton url={shareUrl} />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeaderModelView title={title} subText={subText} tags={tags} />
|
||||
<PageHeaderModelView
|
||||
title={title}
|
||||
subText={subText}
|
||||
tags={tags}
|
||||
ratingBtn={ratingButtons}
|
||||
ratingStats={ratingStats}
|
||||
extras={shareButton}
|
||||
/>
|
||||
|
||||
<Panel padding mb>
|
||||
<div className="row g-5">
|
||||
@@ -45,29 +99,7 @@ export default function VcModelViewPage(props: VcModelViewPageProps) {
|
||||
Use Voice
|
||||
</h4>
|
||||
{/* have to replace this below with Voice conversion stuff instead of the textarea */}
|
||||
<form onSubmit={() => {}}>
|
||||
<textarea
|
||||
onChange={() => {}}
|
||||
value={""}
|
||||
className="form-control"
|
||||
placeholder="Textual shenanigans go here..."
|
||||
rows={6}
|
||||
></textarea>
|
||||
<div className="d-flex gap-3 mt-3">
|
||||
<button className="btn btn-primary w-100">
|
||||
<FontAwesomeIcon icon={faVolumeHigh} className="me-2" />
|
||||
Speak
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="btn btn-destructive w-100"
|
||||
onClick={() => {}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDeleteLeft} className="me-2" />
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="opacity-50">voice to voice components here</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-6">
|
||||
<h4 className="mb-3">
|
||||
@@ -87,12 +119,45 @@ export default function VcModelViewPage(props: VcModelViewPageProps) {
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
<Panel padding>
|
||||
<h4 className="text-center text-lg-start mb-4">
|
||||
<FontAwesomeIcon icon={faBarsStaggered} className="me-3" />
|
||||
Voice Details
|
||||
<Panel padding mb>
|
||||
<h4 className="mb-4">
|
||||
<FontAwesomeIcon icon={faMemoCircleInfo} className="me-3" />
|
||||
Voice Model Details
|
||||
</h4>
|
||||
lol
|
||||
<table className="table">
|
||||
<tbody>
|
||||
{voiceDetails.map((item, index) => (
|
||||
<tr key={index}>
|
||||
<th scope="row" className="fw-semibold">
|
||||
{item.label}
|
||||
</th>
|
||||
<td>{item.value}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{/* Model Edit Buttons */}
|
||||
<div className="d-flex flex-column flex-md-row gap-3 mt-5">
|
||||
<Link className={"btn btn-secondary w-100"} to="">
|
||||
<FontAwesomeIcon icon={faEdit} className="me-2" />
|
||||
Edit Model Details
|
||||
</Link>
|
||||
<Link className="btn btn-destructive w-100" to="">
|
||||
<FontAwesomeIcon icon={faTrash} className="me-2" />
|
||||
Delete Model
|
||||
</Link>
|
||||
</div>
|
||||
</Panel>
|
||||
<Panel padding>
|
||||
<h4 className="mb-4">
|
||||
<FontAwesomeIcon icon={faMessages} className="me-3" />
|
||||
Comments
|
||||
</h4>
|
||||
<CommentComponent
|
||||
entityType="user"
|
||||
entityToken="test"
|
||||
sessionWrapper={props.sessionWrapper}
|
||||
/>
|
||||
</Panel>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user