Commit df84396d by chenway

init

parents
node_modules
<a name="readme-top"></a>
<br />
<div align="center">
<h3 align="center">Kodi front-end website</h3>
<p align="center">
Front-end Web for Kodi
<br />
<a href="https://cd.i.strikingly.com/ai-support/web"><strong>Explore the docs »</strong></a>
<br />
<br />
<a href="http://ai-support.pages.i.strikingly.com/web/">View Demo</a>
</p>
</div>
<!-- TABLE OF CONTENTS -->
<details>
<summary>Table of Contents</summary>
<ol>
<li>
<a href="#about-the-project">About The Project</a>
<ul>
<li><a href="#built-with">Built With</a></li>
</ul>
</li>
<li>
<a href="#getting-started">Getting Started</a>
<ul>
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#installation">Installation</a></li>
</ul>
</li>
<li><a href="#usage">Usage</a></li>
<li><a href="#contact">Contact</a></li>
<li><a href="#acknowledgments">Acknowledgments</a></li>
</ol>
</details>
<!-- ABOUT THE PROJECT -->
## About The Project
This project is the front-end website of Kodi server. It's a website built with React. On the website, the users are able to enter question, and then click Kodi-Template or Kodi-Support to get corresponding answers. Every generated answer will be sent to our google sheet. After that, they can click "Copy Good Answer" is the answer is great, or click "Thumb down" or "Regenerate" is the answer is not good.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
### Built With
* [![React][React.js]][React-url]
* [![Bootstrap][Bootstrap.com]][Bootstrap-url]
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- GETTING STARTED -->
## Getting Started
This is an example of how you may give instructions on setting up your project locally.
To get a local copy up and running follow these simple example steps.
### Prerequisites
This is an example of how to list things you need to use the software and how to install them.
* npm
```sh
npm install npm@latest -g
```
### Installation
1. Clone the repo
```sh
git clone git@cd.i.strikingly.com:ai-support/web.git
```
2. Install NPM packages
```sh
npm install
```
3. Runs the app in the development mode. Open http://localhost:3000 to view it in your browser.
```sh
npm start
```
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- USAGE EXAMPLES -->
## Usage
### Explaination of core files
* App.js: The main file of the website. It defines all the main functionalities of this web, including entering the question, sending the question to the server by fetch, getting streaming response from the server, and send feedback of the response.
* modal.js: Include 2 modal objects. The first one EmailModal is the Modal Popup that will show when the user first opens the website. An email is needed to be submitted to use the web. The second one is the FeedbackModal. When the user click the button "Feedback", the FeedbackModal will occur where user can write their feedback and send to the target google sheet.
* .gitlab-ci.yml: The .gitlab-ci.yml file is a configuration file used by GitLab CI/CD to define the pipeline stages and jobs for building and deploying this project. It's required for this project to be deployed on GitLab pages.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- CONTACT -->
## Contact
Project Link: [https://cd.i.strikingly.com/ai-support/web](https://cd.i.strikingly.com/ai-support/web)
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- ACKNOWLEDGMENTS -->
## Acknowledgments
* [React Bootstrap](https://react-bootstrap.github.io/)
* [React](https://react.dev/)
* [Javascript](https://www.javascript.com/)
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- MARKDOWN LINKS & IMAGES -->
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
[React.js]: https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB
[React-url]: https://reactjs.org/
[Bootstrap.com]: https://img.shields.io/badge/Bootstrap-563D7C?style=for-the-badge&logo=bootstrap&logoColor=white
[Bootstrap-url]: https://getbootstrap.com
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "kodi",
"version": "0.1.0",
"private": true,
"homepage": "http://ai-support.pages.i.strikingly.com/web",
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-bootstrap": "^2.7.4",
"react-dom": "^18.2.0",
"react-icons": "^4.8.0",
"react-router-dom": "^6.14.2",
"react-scripts": "5.0.1",
"socket.io": "^4.5.1",
"socket.io-client": "^4.5.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css'>
<title>chat</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<!-- <div id="root"></div> -->
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css'>
<title>Kodi</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<div id="message-box" class="col s12 m8 l9 white z-depth-1"></div>
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.spacer {
margin-bottom: 150px; /* Adjust the value as needed */
}
\ No newline at end of file
import React from 'react';
import { Route, Routes } from "react-router-dom";
import Chat from './Components/Chat';
import Kodi from './Components/Kodi';
function App() {
return (
<Routes>
<Route path="/" element={<Kodi />} />
<Route path="/web" element={<Kodi />} />
<Route path="/chat" element={<Chat />} />
</Routes>
);
}
export default App;
\ No newline at end of file
import { useState } from "react";
import {
Button,
Col,
Container,
Form,
FormLabel,
Navbar,
Row,
} from "react-bootstrap";
import io from "socket.io-client";
import "../App.css";
import Chatbox from "./Chatbox";
let messageBox = document.querySelector("#message-box");
// const url = 'https://8788-103-84-218-44.ngrok-free.app'
const url = 'https://strk-ai-support.ngrok.app/'
// const url = 'http://localhost:8000'
const socket = io(url, {
extraHeaders: {
"ngrok-skip-browser-warning": "123",
},
});
// socket.emit("join", {
// username: "test",
// room: "default",
// });
socket.on("connect", (data) => {
console.log(data);
});
socket.on("send msg", function (data) {
console.log(data);
console.log(socket.id);
let msg = null;
let msgbox = document.createElement("div");
msgbox.className = "row";
msg = `
<div class="col">
<div class="tag z-depth-3">
<span class="teal-text"><b>${data.user}</b>: ${data.message}
</span>
</div>
</div>`;
msgbox.innerHTML = msg;
messageBox.appendChild(msgbox);
messageBox.scrollTop = messageBox.scrollHeight;
});
function Chat() {
const [languageSupport, setLanguageSupport] = useState("English");
const [languageUser, setLanguageUser] = useState("Simple Chinese");
const [userMessage, setUserMessage] = useState("");
const [supportMessage, setSupportMessage] = useState("");
const [supportName, setSupportName] = useState("");
const [userName, setUserName] = useState("");
const sendUserMessage = (event, user) => {
if (!supportName || !userName) {
alert("Please enter user name and support name");
return;
}
if (userMessage) {
socket.emit("send msg", {
user: "user",
message: userMessage,
languageSupport: languageSupport,
languageUser: languageUser,
});
setUserMessage("");
} else {
alert("Message cannot be empty");
}
};
const sendSupportMessage = (event, user) => {
if (!supportName || !userName) {
alert("Please enter user name and support name");
return;
}
if (supportMessage) {
socket.emit("send msg", {
user: "support",
message: supportMessage,
languageSupport: languageSupport,
languageUser: languageUser,
});
setSupportMessage("");
} else {
alert("Message cannot be empty");
}
};
const setName = () => {
console.log(supportName);
console.log(userName);
if (supportName && userName) {
socket.emit("set room", {
support_name: supportName,
user_name: userName,
});
socket.emit("join", {
username: supportName,
room: supportName + '-' + userName,
});
}
}
return (
<Container>
<Navbar bg="dark" variant="dark">
<Navbar.Brand href="#home">Chat Room</Navbar.Brand>
<Navbar.Collapse className="justify-content-end"></Navbar.Collapse>
</Navbar>
<Row>
<Col>
<FormLabel>user name</FormLabel>
<Form.Control
type="text"
value={userName}
onChange={(e) => setUserName(e.target.value)}
placeholder="Enter user name"
/>
</Col>
<Col>
<FormLabel>support name</FormLabel>
<Form.Control
type="text"
value={supportName}
onChange={(e) => setSupportName(e.target.value)}
placeholder="Enter support name"
/>
</Col>
<Button onClick={(e) => setName()}>Submit(You should set user name and support name first!)</Button>
</Row>
<Row>
<Col>
<FormLabel>user</FormLabel>
<Form.Control
as="select"
onChange={(e) => setLanguageUser(e.target.value)}
>
<option value="Simplified Chinese">Simplified Chinese</option>
<option value="Traditional Chinese">Traditional Chinese</option>
<option value="Italiano">Italiano</option>
<option value="German">German</option>
<option value="Japanese">Japanese</option>
<option value="French">French</option>
<option value="Arabic">Arabic</option>
<option value="Spanish">Spanish</option>
<option value="Dutch">Dutch</option>
<option value="Portuguese">Portuguese</option>
<option value="Finnish">Finnish</option>
<option value="Norwegian">Norwegian</option>
<option value="Swedish">Swedish</option>
<option value="Czech">Czech</option>
<option value="Romanian">Romanian</option>
<option value="Indonesian">Indonesian</option>
<option value="Polish">Polish</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Korean">Korean</option>
</Form.Control>
<Form.Control
type="text"
value={userMessage}
onChange={(e) => setUserMessage(e.target.value)}
placeholder="Enter message"
/>
<Button onClick={(e) => sendUserMessage(e, "user")}>Send</Button>
</Col>
<Col>
<FormLabel>support</FormLabel>
<Form.Control
as="select"
onChange={(e) => setLanguageSupport(e.target.value)}
>
<option value="English">English</option>
<option value="Simplified Chinese">Simplified Chinese</option>
{/* add other languages here */}
</Form.Control>
<Form.Control
type="text"
value={supportMessage}
onChange={(e) => setSupportMessage(e.target.value)}
placeholder="Enter message"
/>
<Button onClick={(e) => sendSupportMessage(e, "support")}>
Send
</Button>
</Col>
</Row>
<Chatbox />
</Container>
);
}
export default Chat;
import React from "react";
// import ChatFeed from "react-chat-ui";/
import { ChatFeed, ChatBubble, BubbleGroup, Message } from "react-chat-ui";
const styles = {
button: {
backgroundColor: "#fff",
borderColor: "#1D2129",
borderStyle: "solid",
borderRadius: 20,
borderWidth: 2,
color: "#1D2129",
fontSize: 18,
fontWeight: "300",
paddingTop: 8,
paddingBottom: 8,
paddingLeft: 16,
paddingRight: 16,
outline: "none"
},
selected: {
color: "#fff",
backgroundColor: "#0084FF",
borderColor: "#0084FF"
}
};
const users = {
0: "You",
Mark: "Mark",
2: "Evan"
};
const customBubble = props => (
<div>
<p>{`${props.message.senderName} ${props.message.id ? "says" : "said"}: ${
props.message.message
}`}</p>
</div>
);
class Chat extends React.Component {
constructor() {
super();
this.state = {
messages: [
new Message({ id: "Mary", message: "Hey guys!", senderName: "Mary" }),
new Message({
id: 2,
message: (
<p>
<span>11:50:</span>Hey! Eve here. react-chat-ui is pretty dooope.
</p>
),
senderName: "Eve"
})
],
useCustomBubble: false,
curr_user: 0
};
}
onPress(user) {
this.setState({ curr_user: user });
}
onMessageSubmit(e) {
const input = this.message;
e.preventDefault();
if (!input.value) {
return false;
}
this.pushMessage(this.state.curr_user, input.value);
input.value = "";
return true;
}
pushMessage(recipient, message) {
const prevState = this.state;
const newMessage = new Message({
id: recipient,
message,
senderName: users[recipient]
});
prevState.messages.push(newMessage);
this.setState(this.state);
}
render() {
return (
<div className="container">
<div className="chatfeed-wrapper">
<ChatFeed
chatBubble={this.state.useCustomBubble && customBubble}
maxHeight={250}
messages={this.state.messages} // Boolean: list of message objects
showSenderName
/>
<form onSubmit={e => this.onMessageSubmit(e)}>
<input
ref={m => {
this.message = m;
}}
placeholder="Type a message..."
className="message-input"
/>
</form>
<div style={{ display: "flex", justifyContent: "space-around" }}>
<button
style={{
...styles.button,
...(this.state.curr_user === 0 ? styles.selected : {})
}}
onClick={() => this.onPress(0)}
>
You
</button>
<button
style={{
...styles.button,
...(this.state.curr_user === "Mary" ? styles.selected : {})
}}
onClick={() => this.onPress("Mary")}
>
Mary
</button>
<button
style={{
...styles.button,
...(this.state.curr_user === 2 ? styles.selected : {})
}}
onClick={() => this.onPress(2)}
>
Eve
</button>
</div>
<div
style={{ display: "flex", justifyContent: "center", marginTop: 10 }}
>
<button
style={{
...styles.button,
...(this.state.useCustomBubble ? styles.selected : {})
}}
onClick={() =>
this.setState({ useCustomBubble: !this.state.useCustomBubble })
}
>
Custom Bubbles
</button>
</div>
</div>
</div>
);
}
}
export default Chatbox;
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.spacer {
margin-bottom: 150px; /* Adjust the value as needed */
}
\ No newline at end of file
import React, { useState, useEffect } from 'react';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import Modal from 'react-bootstrap/Modal';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import Toast from 'react-bootstrap/Toast';
export function EmailPopup() {
const [show, setShow] = useState(false);
const storedEmail = localStorage.getItem('email')
useEffect(() => {
if (storedEmail === null) {
setShow(true);
}
}, [storedEmail]);
const [email, setEmail] = useState(storedEmail);
const [validEmail, setValidEmail] = useState(false);
// const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const handleEmailChange = (e) => {
const email = e.target.value;
setValidEmail(/^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email));
setEmail(email);
};
const handleSubmit = (e) => {
e.preventDefault();
const storedEmail = localStorage.getItem('email')
if (validEmail) {
localStorage.setItem('email', email);
console.log(storedEmail)
setShow(false);
}
};
return (
<>
<Button variant="dark" onClick={handleShow}>
{email}
</Button>
{/* <Modal show={show} onHide={handleClose}> */}
{/* No onHide so that the user cannot close the popup without submitting an email */}
<Modal show={show}>
<Modal.Header>
<Modal.Title>Please Enter Email</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group className="mb-3" controlId="emailAddress">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
placeholder="name@example.com"
onChange={handleEmailChange}
autoFocus
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={handleSubmit}>
Submit
</Button>
</Modal.Footer>
</Modal>
</>
);
}
export function FeedbackModal({showFeedbackModal, onClose}) {
const [show, setShow] = useState(showFeedbackModal);
const [feedback, setFeedback] = useState('');
const [submitToast, setSubmitToast] = useState(false);
const handleClose = () => {
setShow(false);
onClose();
};
const handleClear = () => setFeedback('')
const handleFeedbackChange = (event) => {
setFeedback(event.target.value);
}
const handleSubmit = () => {
// do something with the feedback
if (feedback === '') {
setFeedback("Please do not send empty feedback. Please click 'Clear' and write you feedback");
return
}
const storedEmail = localStorage.getItem('email')
const timestamp = new Date();
const options = { timeZone: 'Asia/Shanghai' };
const date = timestamp.toLocaleDateString('en-US', options); // Get date in format mm/dd/yy
const time = timestamp.toLocaleTimeString('en-US', options); // Get time in format hh:mm:ss
const dateTime = `${date} ${time} UTC+8`; // Combine date and time into one string
const feedbackData = {
email: storedEmail,
time: dateTime,
feedback:feedback,
range: "Feedback"
};
console.log(feedbackData)
fetch("https://strk-ai-support.ngrok.app/v1/ai-support/feedbacks", {
// fetch("https://13313306f1aa.ngrok.app/v1/ai-support/feedbacks", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(feedbackData)
})
.then((response) => {
if (response.ok) {
return response.json();
} else {
throw "some error text";
}
})
.then((data) => {
console.log(data)
setSubmitToast(true)
})
.catch((error) => {
setFeedback("Error. Try again later. If the error persists, please contact the developer.");
console.error("Request failed:", error);
})
// handleClose();
}
function AutohideSubmitToast() {
return (
<Row>
<Col xs={12} className="mb-2">
<Button variant="secondary" onClick={handleClear} className="mr-2">
Clear
</Button>
<Button variant="primary" onClick={handleSubmit} className="ms-2">
Submit
</Button>
</Col>
<Col xs={12}>
<Toast onClose={() => setSubmitToast(false)} show={submitToast} delay={1500} autohide>
<Toast.Body>Feedback sent successfully</Toast.Body>
</Toast>
</Col>
</Row>
);
}
return (
<>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Feedback</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group
className="mb-3"
controlId="exampleForm.ControlTextarea1"
>
<Form.Label>Note: The feedback will be sent directly to Kodi devs.</Form.Label>
<Form.Control as="textarea" rows={8} value={feedback} onChange={handleFeedbackChange}/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer className="d-flex justify-content-start align-items-end">
<AutohideSubmitToast/>
</Modal.Footer>
</Modal>
</>
);
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
#message-box {
float: left;
width: 90%;
margin-right: 5%;
margin-left: 5%;
}
\ No newline at end of file
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from "react-router-dom";
import App from './App';
import './index.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment