mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 19:11:29 +00:00
delete modal
This commit is contained in:
1 parent
f9bc875940
commit
40e94963fe
7 files changed
+222
-106
No files matched your search
@@ -0,0 +1,73 @@
|
||||
import React, { useRef, useEffect } from "react";
|
||||
|
||||
interface ModalProps {
|
||||
show: boolean;
|
||||
handleClose: () => void;
|
||||
title: string;
|
||||
content: React.ReactNode;
|
||||
}
|
||||
|
||||
const Modal: React.FC<ModalProps> = ({ show, handleClose, title, content }) => {
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
modalRef.current &&
|
||||
!modalRef.current.contains(event.target as Node)
|
||||
) {
|
||||
handleClose();
|
||||
}
|
||||
};
|
||||
|
||||
// Attach the event listener to the document
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
|
||||
return () => {
|
||||
// Clean up the event listener
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [handleClose]);
|
||||
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="modal-backdrop">
|
||||
<div
|
||||
ref={modalRef}
|
||||
className="modal"
|
||||
role="dialog"
|
||||
style={{ display: "block" }}
|
||||
>
|
||||
<div className="modal-dialog modal-dialog-centered">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h5 className="modal-title">{title}</h5>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={handleClose}
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body">{content}</div>
|
||||
<div className="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
data-dismiss="modal"
|
||||
onClick={handleClose}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./Modal";
|
||||
@@ -842,6 +842,22 @@ styles with important tags:
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5); /* Translucent black */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal {
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: $panel;
|
||||
border-color: lighten($panel, 8%) !important;
|
||||
@@ -850,17 +866,12 @@ styles with important tags:
|
||||
box-shadow: 0px 9px 33px 1px rgba(19, 19, 27, 0.8);
|
||||
-webkit-box-shadow: 0px 9px 33px 1px rgba(19, 19, 27, 0.8);
|
||||
-moz-box-shadow: 0px 9px 33px 1px rgba(19, 19, 27, 0.8);
|
||||
min-height: 550px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-bottom: 1px solid lighten($panel, 8%);
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
background-color: #0d0d14;
|
||||
}
|
||||
|
||||
.modal-header .btn-close {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { faPlus, faWaveform } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import Panel from "components/common/Panel";
|
||||
@@ -6,10 +6,21 @@ import PageHeader from "components/layout/PageHeader";
|
||||
import Container from "components/common/Container";
|
||||
import { Route, NavLink, Switch, Redirect } from "react-router-dom";
|
||||
import ListItems from "./components/ListItems/ListItems";
|
||||
import Modal from "components/common/Modal";
|
||||
|
||||
function VoiceDesignerMainPage() {
|
||||
usePrefixedDocumentTitle("Voice Designer");
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const openModal = () => {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
const voicesList = [
|
||||
{
|
||||
name: "Donald Trump (45th US President)",
|
||||
@@ -30,67 +41,84 @@ function VoiceDesignerMainPage() {
|
||||
const emptyList = [] as any[];
|
||||
|
||||
function MyVoices() {
|
||||
return <ListItems type="voice" data={voicesList} />;
|
||||
return (
|
||||
<ListItems type="voice" data={voicesList} handleDeleteVoice={openModal} />
|
||||
);
|
||||
}
|
||||
|
||||
function MyDatasets() {
|
||||
return <ListItems type="dataset" data={datasetList} />;
|
||||
return (
|
||||
<ListItems
|
||||
type="dataset"
|
||||
data={datasetList}
|
||||
handleDeleteDataset={openModal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container type="panel">
|
||||
<PageHeader
|
||||
title="Voice Designer"
|
||||
titleIcon={faWaveform}
|
||||
subText="Create your own AI voice by providing audio files of the voice you want to clone."
|
||||
showButton={true}
|
||||
buttonLabel="Create New voice"
|
||||
buttonVariant="primary"
|
||||
buttonIcon={faPlus}
|
||||
buttonTo="/voice-designer/create"
|
||||
panel={false}
|
||||
imageUrl="/images/header/voice-designer.png"
|
||||
<>
|
||||
<Container type="panel">
|
||||
<PageHeader
|
||||
title="Voice Designer"
|
||||
titleIcon={faWaveform}
|
||||
subText="Create your own AI voice by providing audio files of the voice you want to clone."
|
||||
showButton={true}
|
||||
buttonLabel="Create New voice"
|
||||
buttonVariant="primary"
|
||||
buttonIcon={faPlus}
|
||||
buttonTo="/voice-designer/create"
|
||||
panel={false}
|
||||
imageUrl="/images/header/voice-designer.png"
|
||||
/>
|
||||
|
||||
<Panel>
|
||||
<nav>
|
||||
<ul className="nav nav-tabs">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<li className="nav-item">
|
||||
<NavLink
|
||||
to="/voice-designer/voices"
|
||||
className="nav-link fs-6 px-3 px-lg-4"
|
||||
activeClassName="active"
|
||||
>
|
||||
My Voices
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<NavLink
|
||||
to="/voice-designer/datasets"
|
||||
className="nav-link fs-6"
|
||||
activeClassName="active"
|
||||
>
|
||||
My Datasets
|
||||
</NavLink>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div className="p-3 p-lg-4">
|
||||
<Switch>
|
||||
<Route path="/voice-designer/voices" exact component={MyVoices} />
|
||||
<Route
|
||||
path="/voice-designer/datasets"
|
||||
exact
|
||||
component={MyDatasets}
|
||||
/>
|
||||
<Redirect to="/voice-designer/voices" />
|
||||
</Switch>
|
||||
</div>
|
||||
</Panel>
|
||||
</Container>
|
||||
|
||||
<Modal
|
||||
show={isModalOpen}
|
||||
handleClose={closeModal}
|
||||
title="My Modal"
|
||||
content={<p>This is a Bootstrap modal.</p>}
|
||||
/>
|
||||
|
||||
<Panel>
|
||||
<nav>
|
||||
<ul className="nav nav-tabs">
|
||||
<div className="d-flex flex-grow-1">
|
||||
<li className="nav-item">
|
||||
<NavLink
|
||||
to="/voice-designer/voices"
|
||||
className="nav-link fs-6 px-3 px-lg-4"
|
||||
activeClassName="active"
|
||||
>
|
||||
My Voices
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<NavLink
|
||||
to="/voice-designer/datasets"
|
||||
className="nav-link fs-6"
|
||||
activeClassName="active"
|
||||
>
|
||||
My Datasets
|
||||
</NavLink>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div className="p-3 p-lg-4">
|
||||
<Switch>
|
||||
<Route path="/voice-designer/voices" exact component={MyVoices} />
|
||||
<Route
|
||||
path="/voice-designer/datasets"
|
||||
exact
|
||||
component={MyDatasets}
|
||||
/>
|
||||
<Redirect to="/voice-designer/voices" />
|
||||
</Switch>
|
||||
</div>
|
||||
</Panel>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+37
-4
@@ -1,21 +1,32 @@
|
||||
import React from "react";
|
||||
import { faWaveform } from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
faEye,
|
||||
faLanguage,
|
||||
faWaveform,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import Panel from "components/common/Panel";
|
||||
import PageHeader from "components/layout/PageHeader";
|
||||
import Container from "components/common/Container";
|
||||
import { VoiceDetails } from "./components/steps/VoiceDetails";
|
||||
import Input from "components/common/Input";
|
||||
import Select from "components/common/Select";
|
||||
import { Button } from "components/common";
|
||||
|
||||
function VoiceDesignerVoiceEditPage() {
|
||||
usePrefixedDocumentTitle("Edit Voice");
|
||||
|
||||
const dummyData = {
|
||||
name: "Name",
|
||||
visibility: "public",
|
||||
language: "English",
|
||||
};
|
||||
|
||||
return (
|
||||
<Container type="panel">
|
||||
<PageHeader
|
||||
title="Edit Voice"
|
||||
titleIcon={faWaveform}
|
||||
subText="Make changes to your voice details"
|
||||
buttonTo="/voice-designer/create"
|
||||
panel={false}
|
||||
showBackButton={true}
|
||||
backbuttonLabel="Back to Voice Designer"
|
||||
@@ -23,7 +34,29 @@ function VoiceDesignerVoiceEditPage() {
|
||||
/>
|
||||
|
||||
<Panel padding={true}>
|
||||
<VoiceDetails view="voice" />
|
||||
<div className="d-flex flex-column gap-4">
|
||||
<div className="row gy-4">
|
||||
<Input label="Name" placeholder="Voice name" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Select
|
||||
value={dummyData.language}
|
||||
icon={faLanguage}
|
||||
label="Language"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Select
|
||||
value={dummyData.visibility}
|
||||
icon={faEye}
|
||||
label="Visibility"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button label="Save" />
|
||||
</div>
|
||||
</Panel>
|
||||
</Container>
|
||||
);
|
||||
|
||||
+11
-4
@@ -7,9 +7,16 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
interface ListItemsProps {
|
||||
data: any[];
|
||||
type: "voice" | "dataset";
|
||||
handleDeleteVoice?: () => void;
|
||||
handleDeleteDataset?: () => void;
|
||||
}
|
||||
|
||||
export default function ListItems({ data, type }: ListItemsProps) {
|
||||
export default function ListItems({
|
||||
data,
|
||||
type,
|
||||
handleDeleteDataset,
|
||||
handleDeleteVoice,
|
||||
}: ListItemsProps) {
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<div className="d-flex flex-column list-items p-5 align-items-center">
|
||||
@@ -93,10 +100,10 @@ export default function ListItems({ data, type }: ListItemsProps) {
|
||||
label="Delete"
|
||||
small={true}
|
||||
variant="danger"
|
||||
to={
|
||||
onClick={
|
||||
type === "dataset"
|
||||
? `/voice-designer/dataset/${item.modelToken}/delete`
|
||||
: `/voice-designer/voice/${item.modelToken}/delete`
|
||||
? handleDeleteDataset
|
||||
: handleDeleteVoice
|
||||
}
|
||||
/>
|
||||
{type === "voice" && (
|
||||
|
||||
+1
-38
@@ -26,46 +26,9 @@ export const SearchFieldClass = {
|
||||
state.isFocused ? "select-separator" : "select-separator",
|
||||
};
|
||||
|
||||
interface VoiceDetailsProps {
|
||||
view?: "voice" | "dataset";
|
||||
}
|
||||
|
||||
function VoiceDetails({ view }: VoiceDetailsProps) {
|
||||
function VoiceDetails() {
|
||||
const { name, visibility, setName, setVisibility } = useVoiceDetailsStore();
|
||||
|
||||
if (view === "voice") {
|
||||
return (
|
||||
<div className="d-flex flex-column gap-4">
|
||||
<div className="row gy-4">
|
||||
<Input label="Name" placeholder="Voice name" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Select
|
||||
classNames={SearchFieldClass}
|
||||
value="English"
|
||||
defaultValue="English"
|
||||
placeholder="English"
|
||||
icon={faLanguage}
|
||||
label="Language"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Select
|
||||
classNames={SearchFieldClass}
|
||||
value={visibility}
|
||||
onChange={(e) => setVisibility(e.target.value)}
|
||||
icon={faEye}
|
||||
label="Visibility"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button label="Save" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column gap-4">
|
||||
<div className="row gy-4">
|
||||
|
||||
Reference in new issue
Block a user