diff --git a/package-lock.json b/package-lock.json
index 5f9b316..16ec59e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,13 +8,21 @@
"name": "tts-playground",
"version": "0.1.0",
"dependencies": {
+ "@headlessui/react": "^1.7.17",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "clsx": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-icons": "^4.11.0",
+ "react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
+ "react-type-animation": "^3.1.0",
"web-vitals": "^2.1.4"
+ },
+ "devDependencies": {
+ "tailwindcss": "^3.3.3"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -2363,6 +2371,21 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@headlessui/react": {
+ "version": "1.7.17",
+ "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.17.tgz",
+ "integrity": "sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==",
+ "dependencies": {
+ "client-only": "^0.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": "^16 || ^17 || ^18",
+ "react-dom": "^16 || ^17 || ^18"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
@@ -3241,6 +3264,14 @@
}
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
+ "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -5973,6 +6004,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
+ },
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -5983,6 +6019,14 @@
"wrap-ansi": "^7.0.0"
}
},
+ "node_modules/clsx": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
+ "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -14658,6 +14702,14 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
},
+ "node_modules/react-icons": {
+ "version": "4.11.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz",
+ "integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -14671,6 +14723,36 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz",
+ "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==",
+ "dependencies": {
+ "@remix-run/router": "1.8.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz",
+ "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==",
+ "dependencies": {
+ "@remix-run/router": "1.8.0",
+ "react-router": "6.15.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -14743,6 +14825,16 @@
}
}
},
+ "node_modules/react-type-animation": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/react-type-animation/-/react-type-animation-3.1.0.tgz",
+ "integrity": "sha512-Ju74SpUFpSINqlGU8UeFAF+AnAn0nZcc8MB0Ho6QvRkh8uDKkOzAiMD3l9xEmkbKXnSYsljfVgIDM/zwqEImpQ==",
+ "peerDependencies": {
+ "prop-types": "^15.5.4",
+ "react": ">= 15.0.0",
+ "react-dom": ">= 15.0.0"
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
diff --git a/package.json b/package.json
index 84bf3c3..2ca85de 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,17 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@headlessui/react": "^1.7.17",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "clsx": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-icons": "^4.11.0",
+ "react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
+ "react-type-animation": "^3.1.0",
"web-vitals": "^2.1.4"
},
"scripts": {
@@ -34,5 +39,8 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "tailwindcss": "^3.3.3"
}
}
diff --git a/public/index.html b/public/index.html
index aa069f2..786c047 100644
--- a/public/index.html
+++ b/public/index.html
@@ -7,7 +7,7 @@
-
React App
+ Siddhant
diff --git a/src/App.css b/src/App.css
index 74b5e05..79b7195 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,38 +1,123 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+@import url("https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@500&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500&family=Source+Code+Pro:wght@500&display=swap");
+
.App {
text-align: center;
+ font-family: "Source Code Pro", monospace;
+}
+
+.head {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 20vh;
+ font-size: 3rem;
+ color: #dbd9d9;
+}
+
+.middle {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-evenly;
+ margin-top: 5rem;
+ font-size: 2rem;
+ color: #dbd9d9;
+}
+
+.body {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-evenly;
+ margin-top: 3rem;
+ font-size: 2rem;
+ color: #dbd9d9;
}
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+.body-text {
+ width: 100%;
+ max-width: 35rem;
+ padding: 0.3rem;
+ background-color: #2d2d43;
+ border-radius: 1.2rem;
}
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
+.name-field {
+ border: 0;
+ outline: 0;
+ color: #dbd9d9;
+ background: transparent;
+ border-bottom: 1px solid #dbd9d9;
+ width: 10rem;
+ text-align: center;
+ font-family: "Source Code Pro", monospace;
+ font-size: 2rem;
}
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
+.form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
+ font-family: "Plus Jakarta Sans", sans-serif;
+ height: 100vh;
+}
+
+.form-body {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 2rem;
+ padding: 5%;
+ border: 2px solid #dbd9d930;
+ border-radius: 1.2rem;
+}
+
+.form-field {
+ border: 0;
+ outline: 0;
+ color: #dbd9d9;
+ background: transparent;
+ border-bottom: 1px solid #dbd9d953;
+ width: 22rem;
+ max-width: 50vw;
+ font-family: "Source Code Pro", monospace;
+ font-size: 1.2rem;
+}
+
+.form-drop {
+ margin-top: 0.5rem;
+}
+
+.form-check {
+ margin-top: 0.5rem;
+ width: 22rem;
+ max-width: 50vw;
+}
+
+.form-buttons {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-evenly;
+ width: 22rem;
}
-.App-link {
- color: #61dafb;
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ margin: 0;
}
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
+body {
+ background: #222233;
+ height: 100vh;
}
diff --git a/src/App.js b/src/App.js
index 3784575..10ba7d4 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,23 +1,104 @@
-import logo from './logo.svg';
-import './App.css';
+import { useState } from "react";
+import { TypeAnimation } from "react-type-animation";
+import { BrowserRouter, Routes, Route } from "react-router-dom";
+import { TTS_API } from "./api";
+
+import "./App.css";
+import Form from "./components/Form";
function App() {
+ const [flag, setFlag] = useState(false);
+ const [name, setName] = useState("");
+ const [isSubmit, setIsSubmit] = useState(false);
+ const handleButtonClick = async () => {
+ try {
+ const response = await TTS_API.brianTTS(
+ `Hello, ${name}! Welcome to our website. We're glad to have you here.`
+ );
+ if (response.status !== 200) {
+ const errorText = await response.text();
+ alert(errorText);
+ return;
+ }
+ const mp3 = await response.blob();
+ const blobUrl = URL.createObjectURL(mp3);
+ const audio = new Audio(blobUrl);
+ audio.pause();
+ audio.load();
+ audio.play();
+ } catch (error) {
+ console.error("An error occurred:", error);
+ }
+ };
return (
-
+
+
+ } />
+
+
+
+ {flag ? (
+
Hello World!👋
+ ) : (
+
{
+ setFlag(true);
+ },
+ ]}
+ speed={10}
+ />
+ )}
+
+
+
+
+ {flag ? (
+ <>
+
Hi there!👀 What's your name?
+
{
+ setName(e.target.value);
+ setIsSubmit(false);
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") {
+ setIsSubmit(true);
+ handleButtonClick();
+ }
+ }}
+ >
+ >
+ ) : (
+ <>>
+ )}
+
+
+
+ {isSubmit ? (
+
+ {
+ setFlag(true);
+ },
+ ]}
+ speed={20}
+ >
+
+ ) : (
+ <>>
+ )}
+
+
);
}
diff --git a/src/api/TTS.js b/src/api/TTS.js
new file mode 100644
index 0000000..f34c587
--- /dev/null
+++ b/src/api/TTS.js
@@ -0,0 +1,10 @@
+import { STREAM_ELEMENTS_URI } from "./config";
+
+export const TTS_API = {
+ brianTTS: (text) => {
+ return fetch(
+ `${STREAM_ELEMENTS_URI}?voice=Brian&text=` +
+ encodeURIComponent(text.trim())
+ );
+ },
+};
diff --git a/src/api/config.js b/src/api/config.js
new file mode 100644
index 0000000..6be4b04
--- /dev/null
+++ b/src/api/config.js
@@ -0,0 +1,2 @@
+export const STREAM_ELEMENTS_URI =
+ "https://api.streamelements.com/kappa/v2/speech";
diff --git a/src/api/index.js b/src/api/index.js
new file mode 100644
index 0000000..435505d
--- /dev/null
+++ b/src/api/index.js
@@ -0,0 +1 @@
+export { TTS_API } from "./TTS";
diff --git a/src/atoms/button/Button.js b/src/atoms/button/Button.js
new file mode 100644
index 0000000..1b524c6
--- /dev/null
+++ b/src/atoms/button/Button.js
@@ -0,0 +1,51 @@
+import React, { memo } from "react";
+
+const appearances = {
+ primary:
+ "flex flex-row active:scale-95 cursor-pointer transition ease-in-out duration-300 justify-center items-center rounded-[8px] not-italic font-bold text-white text-center relative",
+ white:
+ "flex flex-row active:scale-95 cursor-pointer transition ease-in-out duration-300 justify-center items-center border-solid border-2 border-[#EEEEEE] rounded-[8px] not-italic font-bold text-gray-900 text-center relative",
+ dark: "flex flex-row active:scale-95 cursor-pointer transition ease-in-out duration-300 justify-center items-center rounded-[8px] not-italic font-bold text-white text-center relative",
+ ghost:
+ "flex flex-row active:scale-95 cursor-pointer hover:bg-gray-50 transition ease-in-out duration-300 justify-center items-center border-solid border-[1px] border-[#dbd9d9] rounded-[8px] not-italic font-bold text-[#dbd9d9] hover:text-neutral-900 text-center relative",
+};
+
+const colors = {
+ primary: "#5359EA",
+ white: "#FFFFFF",
+ dark: "#111827",
+ ghost: "",
+};
+
+const sizes = {
+ sm: "gap-2 min-w-[79px] h-10 text-sm px-4 py-2.5",
+ md: "gap-2.5 min-w-[102px] h-12 text-base px-6 py-3",
+ lg: "gap-2.5 min-w-[118px] h-14 text-base px-8 py-4",
+};
+
+const ButtonComponent = ({
+ appearance,
+ type,
+ size,
+ leftIcon,
+ rightIcon,
+ children,
+ onClick,
+}) => {
+ return (
+
+ );
+};
+
+export default memo(ButtonComponent);
diff --git a/src/atoms/button/index.tsx b/src/atoms/button/index.tsx
new file mode 100644
index 0000000..150e111
--- /dev/null
+++ b/src/atoms/button/index.tsx
@@ -0,0 +1,3 @@
+import Button from "./Button";
+
+export default Button;
diff --git a/src/atoms/checkbox/Checkbox.js b/src/atoms/checkbox/Checkbox.js
new file mode 100644
index 0000000..9f31dd0
--- /dev/null
+++ b/src/atoms/checkbox/Checkbox.js
@@ -0,0 +1,68 @@
+import React from "react";
+import { HiCheck } from "react-icons/hi";
+
+const Checkbox = ({ active, title, size = "base", showBg, onClick }) => {
+ const sizeArray = ["xs", "sm", "base", "lg", "xl"];
+
+ return (
+
+ {showBg && (
+
+ )}
+ {!showBg && (
+
+ )}
+
+ );
+};
+
+export default Checkbox;
diff --git a/src/atoms/checkbox/index.tsx b/src/atoms/checkbox/index.tsx
new file mode 100644
index 0000000..8d18d05
--- /dev/null
+++ b/src/atoms/checkbox/index.tsx
@@ -0,0 +1,3 @@
+import Checkbox from "./Checkbox";
+
+export default Checkbox;
diff --git a/src/atoms/dropdown/Dropdown.js b/src/atoms/dropdown/Dropdown.js
new file mode 100644
index 0000000..3302371
--- /dev/null
+++ b/src/atoms/dropdown/Dropdown.js
@@ -0,0 +1,104 @@
+import React, { Fragment, useState } from "react";
+import { Menu, Transition } from "@headlessui/react";
+
+function classNames(...classes) {
+ return classes.filter(Boolean).join(" ");
+}
+
+const Dropdown = ({
+ items,
+ placeholder,
+ overlay,
+ disabled,
+ selectedValue,
+ setSelected,
+ onClick,
+}) => {
+ const [key, setKey] = useState(selectedValue);
+ return (
+
+ );
+};
+
+export default Dropdown;
diff --git a/src/atoms/dropdown/index.tsx b/src/atoms/dropdown/index.tsx
new file mode 100644
index 0000000..1de75f0
--- /dev/null
+++ b/src/atoms/dropdown/index.tsx
@@ -0,0 +1,3 @@
+import Dropdown from "./Dropdown";
+
+export default Dropdown;
diff --git a/src/components/Form.js b/src/components/Form.js
new file mode 100644
index 0000000..87d1700
--- /dev/null
+++ b/src/components/Form.js
@@ -0,0 +1,123 @@
+import React, { useState } from "react";
+
+import "../App.css";
+import Button from "../atoms/button/Button";
+import Dropdown from "../atoms/dropdown/Dropdown";
+import Checkbox from "../atoms/checkbox/Checkbox";
+
+function isValidEmail(email) {
+ return /\S+@\S+\.\S+/.test(email);
+}
+
+function Form() {
+ const [key, setKey] = useState(-1);
+ const [name, setName] = useState("");
+ const [age, setAge] = useState(0);
+ const [email, setEmail] = useState("");
+ const [location, setLocation] = useState("");
+ const [gender, setGender] = useState("");
+ const [isChecked, setIsChecked] = useState(false);
+ const dropdownData1 = {
+ optionName: "Male",
+ optionIcon: <>>,
+ };
+ const dropdownData2 = {
+ optionName: "Female",
+ optionIcon: <>>,
+ };
+ const dropdownData3 = {
+ optionName: "Other",
+ optionIcon: <>>,
+ };
+ const handleDrop = (e) => {
+ setGender(e.target.outerText);
+ };
+ const handleCheck = () =>
+ isChecked ? setIsChecked(false) : setIsChecked(true);
+ const handleClear = () => window.location.reload();
+ const handleSubmit = () => {
+ if (!name || !age || !email || !location || !gender)
+ alert("One or more fields are empty");
+ else if (!isValidEmail(email)) alert("Invalid email");
+ else if (!isChecked) alert("You need to agree to the T&C");
+ else alert("Form successfully submitted");
+ };
+ return (
+
+ );
+}
+
+export default Form;
diff --git a/src/components/TTS.js b/src/components/TTS.js
new file mode 100644
index 0000000..693336b
--- /dev/null
+++ b/src/components/TTS.js
@@ -0,0 +1,38 @@
+import React, { useState } from "react";
+import { TTS_API } from "../api";
+
+function TTS_Page() {
+ const [audioSrc, setAudioSrc] = useState("");
+ const handleButtonClick = async () => {
+ try {
+ const response = await TTS_API.brianTTS("");
+
+ if (response.status !== 200) {
+ const errorText = await response.text();
+ alert(errorText);
+ return;
+ }
+
+ const mp3 = await response.blob();
+ const blobUrl = URL.createObjectURL(mp3);
+ setAudioSrc(blobUrl);
+
+ const audio = document.getElementById("audio");
+ audio.pause();
+ audio.load();
+ audio.play();
+ } catch (error) {
+ console.error("An error occurred:", error);
+ }
+ };
+ return (
+
+
+
+
+ );
+}
+
+export default TTS_Page;
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..37cc651
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ["./src/**/*.{js,jsx,ts,tsx}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};