diff --git a/package-lock.json b/package-lock.json index aa8c665..6de3ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,9 +18,11 @@ "matchmedia": "^0.1.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", "react-swipeable": "^7.0.1", "react-tinder-card": "^1.6.2", + "sass": "^1.66.1", "web-vitals": "^2.1.4", "workbox-background-sync": "^6.6.0", "workbox-broadcast-update": "^6.6.0", @@ -34,8 +36,7 @@ "workbox-routing": "^6.6.0", "workbox-strategies": "^6.6.0", "workbox-streams": "^6.6.0" - }, - "devDependencies": {} + } }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", @@ -3409,6 +3410,14 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "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", @@ -9450,6 +9459,11 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -14924,6 +14938,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", @@ -15505,6 +15549,22 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "node_modules/sass": { + "version": "1.66.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz", + "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", diff --git a/package.json b/package.json index af319c1..0b8066a 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,11 @@ "matchmedia": "^0.1.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", "react-swipeable": "^7.0.1", "react-tinder-card": "^1.6.2", + "sass": "^1.66.1", "web-vitals": "^2.1.4", "workbox-background-sync": "^6.6.0", "workbox-broadcast-update": "^6.6.0", @@ -53,6 +55,10 @@ "last 1 safari version" ] }, + "devDependencies": { + "react-scripts": "^5.0.1", + "sass": "^1.38.0" + }, "main": "index.js", "keywords": [], "author": "", diff --git a/src/App.css b/src/components/App/App.css similarity index 100% rename from src/App.css rename to src/components/App/App.css diff --git a/src/App.js b/src/components/App/App.js similarity index 56% rename from src/App.js rename to src/components/App/App.js index 5014984..3cb0900 100644 --- a/src/App.js +++ b/src/components/App/App.js @@ -1,9 +1,10 @@ import React, { useState, useEffect } from 'react'; -import Start from './components/Start/Start'; -import Second from './components/Second/Second'; -import Tinder from './components/Tinder/Tinder'; -import Main from './components/Main/Main'; -import City from './components/City/City'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import Start from '../Start/Start'; +import Second from '../Second/Second'; +import Tinder from '../Tinder/Tinder'; +import Main from '../Main/Main'; +import City from '../City/City'; import axios from 'axios'; import './App.css'; @@ -48,30 +49,17 @@ function App() { console.log(userData); }, [userData]); - let content = null; - switch (buttonValue) { - case '/second': - content = - break; - case '/tinder': - content = - break; - case '/main': - content =
- break; - case '/city': - content = - break; - default: - content = - } - - const arrayLength = userData.unique ? userData.unique.length : 0; return ( -
- {arrayLength !== 0 ?
: content} -
+ + + }/> + } /> + } /> + } /> + } /> + + ); } diff --git a/src/components/Main/Card.js b/src/components/Card/Card.js similarity index 100% rename from src/components/Main/Card.js rename to src/components/Card/Card.js diff --git a/src/setupTests.js b/src/components/Card/card.scss similarity index 100% rename from src/setupTests.js rename to src/components/Card/card.scss diff --git a/src/components/City/City.css b/src/components/City/City.css deleted file mode 100644 index c4215df..0000000 --- a/src/components/City/City.css +++ /dev/null @@ -1,46 +0,0 @@ -/* .button-container { - display: flex; - flex-direction: column; - gap: 10px; - opacity: 0; - transform: translateY(20px); - transition: opacity 0.5s ease, transform 0.5s ease; -} */ - -.animated-button { - width: 304px; - height: 54px; - font-size: 20px; - border-radius: 27px; - border: none; - background-color: #46A2E3; - font-family: 'Raleway'; - color: #FFFFFF; - font-weight: 97px; -} - -.animated-button:hover { - background-color: #398ac5; -} - -.ab { - width: 304px; - height: 54px; - font-size: 20px; - border-radius: 27px; - border: none; - background-color: white; - font-family: 'Raleway'; - color: #398ac5; - font-weight: 97px; -} - -.ab:hover { - background-color: #f8f8f8; -} - -/* -.button-container.visible { - opacity: 1; - transform: translateY(0); -} */ \ No newline at end of file diff --git a/src/components/City/City.js b/src/components/City/City.js index 2594065..8760b90 100644 --- a/src/components/City/City.js +++ b/src/components/City/City.js @@ -1,10 +1,13 @@ import React, { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; + import axios from "axios"; -import './City.css' +import './City.scss' const City = (props) => { const route = props.getValue; const setUserData = props.setUserData + const second = useNavigate(); const [cityOptions, setCityOptions] = useState([]); const [filteredCityOptions, setFilteredCityOptions] = useState([]); @@ -51,48 +54,13 @@ const City = (props) => { }, [selectedCity, cityOptions]); return ( -
-
-
- # +
+
+
+ #
- - cityHandler(e)} placeholder="Выберите город..." value={selectedCity} id="city" name="city" className="city__choise"> + {filteredCityOptions.map(option => (
{buttonsVisible ? ( -
+
diff --git a/src/components/City/City.scss b/src/components/City/City.scss new file mode 100644 index 0000000..13a21ad --- /dev/null +++ b/src/components/City/City.scss @@ -0,0 +1,96 @@ +.button-container { + display: flex; + flex-direction: column; + position: fixed; + bottom: 50px; + gap: 10px; +} + +.animated-button { + width: 304px; + height: 54px; + font-size: 20px; + border-radius: 27px; + border: none; + background-color: #46A2E3; + font-family: 'Raleway'; + color: #FFFFFF; + font-weight: 97px; + &:hover { + background-color: #398ac5; + } +} +.city__ticket { + width: 304px; + height: 54px; + font-size: 20px; + border-radius: 27px; + border: none; + background-color: white; + font-family: 'Raleway'; + color: #398ac5; + font-weight: 97px; + display: flex; + justify-content: center; + align-items: center; + height: 42px; + border: none; + &_img { + font-size: 20px; + width: 30px; + height: 30px; + margin-right: 10px; + } + &:hover { + background-color: #f8f8f8; + } +} + + +/* +.button-container.visible { + opacity: 1; + transform: translateY(0); +} */ + +.container { + display: flex; + flex-direction: column; + height: 95vh; + + align-items: center; + background: linear-gradient(180deg, #7EAFE7 0.27%, rgba(41, 134, 242, 0.38) 27.08%, rgba(41, 134, 242, 0.35) 31.77%, rgba(152, 198, 253, 0.28) 46.35%, rgba(41, 134, 242, 0.00) 100%); + &_space_around { + justify-content: space-around; + } +} +.city { + height: 400px; + position: fixed; + top: 100px; + display: flex; + align-items: center; + flex-direction: column; + justify-content: space-between; + gap: 80px; + &__plannet { + display: flex; + justify-content: center; + width: 304px; + &_img { + width: 282px; + height: 282px; + } + } + &__choise { + height: 40px; + width: 304px; + border-radius: 20px; + border: none; + padding: 5px; + + &_option { + max-width: 200px; + } + } +} diff --git a/src/components/Main/Footer.js b/src/components/Footer/Footer.js similarity index 100% rename from src/components/Main/Footer.js rename to src/components/Footer/Footer.js diff --git a/src/components/Footer/footer.scss b/src/components/Footer/footer.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js new file mode 100644 index 0000000..76c0cbb --- /dev/null +++ b/src/components/Header/Header.js @@ -0,0 +1,87 @@ +import './header.scss'; +import { useEffect } from 'react'; + + +const Header = () => { + useEffect(() => { + const humburger = document.querySelector('.hamburger'); + const header = document.querySelector('.header__navigation'); + console.log(humburger); + + humburger.addEventListener('click', (e) => { + e.currentTarget.classList.toggle('hamburger_active'); + header.classList.toggle('hide'); + }); + + + + + + return () => { + humburger.removeEventListener('click', (e) => { + e.currentTarget.classList.toggle('hamburger_active'); + header.classList.toggle('hide'); + }); + + }; + }, []) + + return ( +
+
+
+ # + Путешествия

Просто!

+
+ +
+ + + +
+
+ +
+ + ); +} + +export default Header; \ No newline at end of file diff --git a/src/components/Header/header.scss b/src/components/Header/header.scss new file mode 100644 index 0000000..b5e181c --- /dev/null +++ b/src/components/Header/header.scss @@ -0,0 +1,78 @@ +.hamburger { + display: block; + position: fixed; + right: 10px; + top: 28px; + transform: translateX(-50%); + height: 30px; + width: 30px; + span { + + display: block; + height: 3px; + width: 100%; + background-color: #000; + margin-top: 5px; + &:nth-child(1) { + margin-top: 0px; + } + } + &_active { + margin-top: 6px; + span { + transition: ease 0.5s; + &:nth-child(1) { + margin-top: -2px; + transform: translateY(4px) rotate(-45deg); + } + &:nth-child(2) { + display: none; + } + &:nth-child(3) { + margin-top: -3px; + transform: translateY(4px) rotate(45deg); + } + } + } +} + +.header { + + + &__navigation { + transition:ease 0.6s; + transform: translateX(0%); + height: 200%; + position: fixed; + left: 0px; + width: 60%; + background-color: rgba( 0, 0, 0, 0.5 ); + display: flex; + flex-direction: column; + justify-content: center; + align-items: left; + padding-left: 30px; + padding-top: 100px; + + &_link { + margin-top: 6px; + z-index: 1; + color: #FFF; + font-family: Montserrat; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-decoration: none; + } + } + &__container { + + width: 100%; + top: 0px; + position: fixed; + } +} +.hide { + transform: translateX(-100%); +} \ No newline at end of file diff --git a/src/components/Main/Header.js b/src/components/Main/Header.js deleted file mode 100644 index 3520118..0000000 --- a/src/components/Main/Header.js +++ /dev/null @@ -1,57 +0,0 @@ - -const Header = () => { - - return ( -
-
-
- # - Путешествия

Просто!

-
- - -
-
- - ); -} - -export default Header; \ No newline at end of file diff --git a/src/components/Main/Main.js b/src/components/Main/Main.js index fdd3a82..a2fa88d 100644 --- a/src/components/Main/Main.js +++ b/src/components/Main/Main.js @@ -1,8 +1,8 @@ import React, { useEffect, useState } from "react"; import axios from "axios"; -import Header from "./Header"; -import Card from "./Card"; -import Footer from "./Footer"; +import Header from "../Header/Header"; +import Card from "../Card/Card"; +import Footer from "../Footer/Footer"; const Main = ({ userData }) => { @@ -50,7 +50,7 @@ const Main = ({ userData }) => { }, []); return ( -
+
{ const route = props.getValue; - + const tinder = useNavigate(); + const main = useNavigate(); return ( -
+
# -
-

Давайте
знакомиться!

-

Пройдите небольшой тест,
чтобы мы подобрали интересные
+

+

Давайте
знакомиться!

+

Пройдите небольшой тест,
чтобы мы подобрали интересные
для вас мероприятия

-
- - +
+ +
) diff --git a/src/components/Second/second.scss b/src/components/Second/second.scss new file mode 100644 index 0000000..7c99fd2 --- /dev/null +++ b/src/components/Second/second.scss @@ -0,0 +1,77 @@ +@font-face { + font-family: "Raleway"; + src: url("../Second/fonts/Raleway.ttf"); + } + + + + +.container { + display: flex; + flex-direction: column; + align-content: center; + flex-wrap: wrap; + justify-content: space-between; + height: 100%; + background: linear-gradient(180deg, #7EAFE7 0.27%, rgba(41, 134, 242, 0.38) 27.08%, rgba(41, 134, 242, 0.35) 31.77%, rgba(152, 198, 253, 0.28) 46.35%, rgba(41, 134, 242, 0.00) 100%); + filter: blur(2); + padding-bottom: 10px; + overflow: hidden; + + &__description { + display: flex; + flex-direction: column; + gap: 20px; + align-items: center; + } + &__main_text{ + font-size: 45px; + text-align: center; + font-family: "Raleway"; + p { + font-size: 18px; + color: #6C6C6C; + text-align: center; + width: 332px; + font-family: "Raleway"; + } + + } +} + +.btn__container { + display: flex; + flex-direction: column; + gap: 15px; + align-items: center; +} +.btn_first{ + width: 231px; + height: 61px; + background: #46A2E3; + color: #fff; + font-size: 24px; + border: none; + text-align: center; + border-radius: 53px; + font-weight: bold; +} + +.btn_first:hover { + background-color: #398ac5; +} + +.btn_second{ + width: 169px; + height: 49px; + background: #7dc5f8; + border: #0094FF; + color: #ffffff; + font-size: 15px; + text-align: center; + border-radius: 53px; +} + +.btn_second:hover { + background-color: #398ac5; +} \ No newline at end of file diff --git a/src/components/Second/style.css b/src/components/Second/style.css deleted file mode 100644 index ef966da..0000000 --- a/src/components/Second/style.css +++ /dev/null @@ -1,50 +0,0 @@ -@font-face { - font-family: "Raleway"; - src: url("../Second/fonts/Raleway.ttf"); - } - - - -.main_text{ - font-size: 45px; - text-align: center; - font-family: "Raleway"; - -} -.text{ - font-size: 18px; - color: #6C6C6C; - text-align: center; - width: 332px; - font-family: "Raleway"; -} -.btn_first{ - width: 231px; - height: 61px; - background: #46A2E3; - color: #fff; - font-size: 24px; - border: none; - text-align: center; - border-radius: 53px; - font-weight: bold; -} - -.btn_first:hover { - background-color: #398ac5; -} - -.btn_second{ - width: 169px; - height: 49px; - background: #7dc5f8; - border: #0094FF; - color: #ffffff; - font-size: 15px; - text-align: center; - border-radius: 53px; -} - -.btn_second:hover { - background-color: #398ac5; -} \ No newline at end of file diff --git a/src/serviceWorkerRegistration.js b/src/components/ServiceWorkerRegistration/serviceWorkerRegistration.js similarity index 100% rename from src/serviceWorkerRegistration.js rename to src/components/ServiceWorkerRegistration/serviceWorkerRegistration.js diff --git a/src/components/SetupTests/setupTests.js b/src/components/SetupTests/setupTests.js new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Start/Start.js b/src/components/Start/Start.js index c5c8aa6..23f3f2d 100644 --- a/src/components/Start/Start.js +++ b/src/components/Start/Start.js @@ -1,69 +1,50 @@ import React, { useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import './start.scss'; + const Start = (props) => { + const history = useNavigate(); + const kek = './circle.html'; - const route = props.getValue; - const kek = './circle.html' + function hideAddressBar() { + if (document.documentElement.scrollHeight < window.outerHeight / window.devicePixelRatio) + document.documentElement.style.height = (window.outerHeight / window.devicePixelRatio) + 'px'; + setTimeout(window.scrollTo(1, 1), 0); + } - function hideAddressBar(){ - if(document.documentElement.scrollHeight { - const handler = (ev: MessageEvent<{ type: string }>) => { - if (typeof ev.data !== 'object') return - if (!ev.data.type) return - if (ev.data.type !== 'button-click') return - - route('/city') - } - - window.addEventListener('message', handler) - - // Don't forget to remove addEventListener - return () => window.removeEventListener('message', handler) - }, []) + const handleButtonClick = () => { + history('/city'); + }; - return ( -
-
- logo - Путешествия

Просто!

-
- - -
- ) + useEffect(() => { + const frame = document.querySelector("#start"); + frame.addEventListener('load', () => { + frame.contentWindow.addEventListener('click', () => { + handleButtonClick(); + }); + }); + + return () => { + frame.removeEventListener('load', () => { + frame.contentWindow.removeEventListener('click', () => { + }); + }); + }; + }, []); + + return ( +
+
+ logo + Путешествия

Просто!

+
+ +
+ ) }; -export default Start; +export default Start; \ No newline at end of file diff --git a/src/components/Start/start.scss b/src/components/Start/start.scss new file mode 100644 index 0000000..85b1043 --- /dev/null +++ b/src/components/Start/start.scss @@ -0,0 +1,37 @@ +.container { + display: flex; + flex-direction: column; + align-content: center; + align-items: center; + flex-wrap: wrap; + justify-content: space-evenly; + height: 95vh; + overflow: hidden; +} +.header { + display: flex; + flex-direction: column; + align-items: center; + &__logo { + width: 181px; + height: 181px; + } + &__text { + color: #F68C43; + display: flex; + flex-direction: column; + align-items: start; + font-weight: 700; + font-family: 'Raleway'; + font-size: 40px; + p { + color: #4EB0F2; + } + } +} +.content__btn { + overflow: hidden; + border: none; + width: 440px; + height: 440px; +} \ No newline at end of file diff --git a/src/components/Tinder/Tinder.js b/src/components/Tinder/Tinder.js index 34ddbab..8c9b92e 100644 --- a/src/components/Tinder/Tinder.js +++ b/src/components/Tinder/Tinder.js @@ -1,12 +1,14 @@ import React, { useState } from 'react'; +import { useNavigate } from "react-router-dom"; import TinderCard from 'react-tinder-card'; -import './Tinder.css'; +import './Tinder.scss'; const Tinder = (props) => { const route = props.getValue; const cardInfo = props.cardInfo; const setUserData = props.setUserData; + const main = useNavigate(); const [lastDirection, setLastDirection] = useState(); const [cardId, setCardId] = useState([]); @@ -32,14 +34,7 @@ const Tinder = (props) => { }; return ( -
+
{cardInfo.map((card) => ( @@ -51,74 +46,33 @@ const Tinder = (props) => { var unique = [...new Set(cardId)] var uniqueIds = [...new Set(allIds)]; if(uniqueIds.length === cardInfo.length) { - route('/main'); + main('/main'); setUserData(prevUserData => ({ ...prevUserData, unique: unique })); - console.log(unique); - console.log(props.userData); } }} >
-
+
-
+

{card.question}

-
+
diff --git a/src/components/Tinder/Tinder.css b/src/components/Tinder/Tinder.scss similarity index 68% rename from src/components/Tinder/Tinder.css rename to src/components/Tinder/Tinder.scss index 510f82a..dff9e77 100644 --- a/src/components/Tinder/Tinder.css +++ b/src/components/Tinder/Tinder.scss @@ -80,6 +80,24 @@ flex-wrap: wrap; box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1); background-color: #fff; + &__choise_img { + height: 100%; + width: 100%; + } + &__img { + height: 300px; + width: 245px; + border-radius: 10px; + background-repeat: no-repeat; + background-position: center; + } + &__description_container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + height: 150px; + } } .card-content { @@ -90,8 +108,34 @@ width: 300px; height: 500px; background-color: rgba(255, 255, 255, 0.8); + display: flex; + flex-direction: column; + padding-top: 10px; } .infoText { margin-top: 16px; - } \ No newline at end of file + } +.tinder__flex { + display: flex; + flex-direction: column; + height: 100vh; + justify-content: space-around; + align-items: center; + background: linear-gradient(180deg, #7EAFE7 0.27%, rgba(41, 134, 242, 0.38) 27.08%, rgba(41, 134, 242, 0.35) 31.77%, rgba(152, 198, 253, 0.28) 46.35%, rgba(41, 134, 242, 0.00) 100%); + +} +.btn__container_tinder { + width: 150px; + display: flex; + flex-direction: row; + justify-content: space-between; + margin: 0 14px; + margin-bottom: 10px; +} +.btn__tinder { + height: 69px; + width: 69px; + background-color: #fff; + border: none; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index 6d5f43c..b522533 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,9 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; -import App from './App'; -import * as serviceWorkerRegistration from './serviceWorkerRegistration'; -import reportWebVitals from './reportWebVitals'; +import App from './components/App/App'; +import * as serviceWorkerRegistration from './components/ServiceWorkerRegistration/serviceWorkerRegistration'; +import reportWebVitals from './components/ReportWebVitals/reportWebVitals'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(