delete modal

This commit is contained in:
BFlat committed 2023-10-30 20:57:49 +07:00
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>
</>
);
}
@@ -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>
);
@@ -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" && (
@@ -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">