|
@@ -0,0 +1,231 @@
|
|
|
|
+import './App.css';
|
|
|
|
+import {useState, useEffect} from "react";
|
|
|
|
+import React from "react";
|
|
|
|
+
|
|
|
|
+import clockFace from "./img/clockFace.png";
|
|
|
|
+import clockHour from "./img/clockFace_Hour.png";
|
|
|
|
+import clockMin from "./img/clockFace_Min.png";
|
|
|
|
+import clockSec from "./img/clockFace_Sec.png"
|
|
|
|
+
|
|
|
|
+const Spoiler = ({header = "+", open = true, children, setIsOpen}) => {
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ <div className={"btn"} onClick={() => setIsOpen(!open)}>
|
|
|
|
+ {header}
|
|
|
|
+ </div>
|
|
|
|
+ {open && children}
|
|
|
|
+ </>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const RangeInput = ({min, max}) => {
|
|
|
|
+ const [isValid, setIsValid] = useState(false)
|
|
|
|
+ const color = isValid ? "" : "red";
|
|
|
|
+
|
|
|
|
+ const inputHandler = (e) => {
|
|
|
|
+ if (min < e.target.value.length && e.target.value.length < max) {
|
|
|
|
+ setIsValid(true)
|
|
|
|
+ } else {
|
|
|
|
+ setIsValid(false)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ <input style={{color: color}} onChange={inputHandler}/>
|
|
|
|
+ </>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+const PasswordConfirm = ({min}) => {
|
|
|
|
+ const [isValid2, setIsValid2] = useState(false)
|
|
|
|
+ const color = isValid2 ? "" : "red";
|
|
|
|
+
|
|
|
|
+ const [value1, setStateInput1] = useState("");
|
|
|
|
+ const [value2, setStateInput2] = useState("");
|
|
|
|
+
|
|
|
|
+ const inputHandler1 = (e) => {
|
|
|
|
+ const value = e.target.value
|
|
|
|
+ setStateInput1(e.target.value)
|
|
|
|
+
|
|
|
|
+ if ((value.length > min && value2.length > min) && (value === value2)) {
|
|
|
|
+ setIsValid2(true)
|
|
|
|
+ } else {
|
|
|
|
+ setIsValid2(false)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ const inputHandler2 = (e) => {
|
|
|
|
+ const value = e.target.value
|
|
|
|
+ console.log(value)
|
|
|
|
+ setStateInput2(e.target.value)
|
|
|
|
+ if ((value.length > min && value1.length > min) && (value === value1)) {
|
|
|
|
+ setIsValid2(true)
|
|
|
|
+ } else {
|
|
|
|
+ setIsValid2(false)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return (
|
|
|
|
+ <div className="passwordWrapper">
|
|
|
|
+
|
|
|
|
+ <input style={{color: color}} type='password' onChange={inputHandler1} placeholder={"password"}/>
|
|
|
|
+ <input style={{color: color}} type='password' onChange={inputHandler2} placeholder={"repeat password"}/>
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const Timer = ({sec = 30}) => {
|
|
|
|
+
|
|
|
|
+ const [time, setTime] = useState(sec);
|
|
|
|
+ const [allowTimer, setAllowTimer] = useState(false)
|
|
|
|
+ let hours = Math.floor(time / 60 / 60)
|
|
|
|
+ let minutes = Math.floor(time / 60 % 60)
|
|
|
|
+ let seconds = time % 60
|
|
|
|
+
|
|
|
|
+ const buttonHandler = () => {
|
|
|
|
+ setAllowTimer(!allowTimer)
|
|
|
|
+ }
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ if (allowTimer && time > 0) {
|
|
|
|
+ const idTimer = setInterval(() => setTime(+time - 1), 1000)
|
|
|
|
+ return () => clearInterval(idTimer)
|
|
|
|
+ }
|
|
|
|
+ }, [time, allowTimer])
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ <div>
|
|
|
|
+ <button onClick={buttonHandler}>{!allowTimer ? "run" : "stop"}</button>
|
|
|
|
+ </div>
|
|
|
|
+ <div>{hours < 10 ? "0" + hours : hours} : {minutes < 10 ? "0" + minutes : minutes} : {seconds < 10 ? "0" + seconds : seconds}</div>
|
|
|
|
+ </>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+const TimerControl = () => {
|
|
|
|
+ const [hoursValue, setHoursValue] = useState(0)
|
|
|
|
+ const [minutesValue, setMinutesValue] = useState(0)
|
|
|
|
+ const [secondsValue, setSecondValue] = useState(0)
|
|
|
|
+ const [isTimerStarted, setTimerStarted] = useState(false)
|
|
|
|
+
|
|
|
|
+ const changeValue = (e) => {
|
|
|
|
+ const value = +e.target.value
|
|
|
|
+ if (!isNaN(value) && value < 60 && value > 0) {
|
|
|
|
+
|
|
|
|
+ switch (e.target.id) {
|
|
|
|
+
|
|
|
|
+ case "hours" :
|
|
|
|
+ setHoursValue(value)
|
|
|
|
+ break
|
|
|
|
+ case "minute" :
|
|
|
|
+ setMinutesValue(value)
|
|
|
|
+ break
|
|
|
|
+ case "seconds" :
|
|
|
|
+ setSecondValue(value)
|
|
|
|
+ break
|
|
|
|
+ default :
|
|
|
|
+ (console.log("Упс"))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const buttonHandler = () => {
|
|
|
|
+ setTimerStarted(!isTimerStarted)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ <input id="hours" onChange={changeValue} value={hoursValue}/>
|
|
|
|
+ <input id="minute" onChange={changeValue} value={minutesValue}/>
|
|
|
|
+ <input id="seconds" onChange={changeValue} value={secondsValue}/>
|
|
|
|
+ <button onClick={buttonHandler}>{isTimerStarted ? "Delete timer" : "Creat timer"}</button>
|
|
|
|
+ {isTimerStarted && <Timer sec={hoursValue * 60 * 60 + minutesValue * 60 + secondsValue}/>}
|
|
|
|
+ </>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const SecondsTimer = ({seconds}) => <h2>{seconds} seconds</h2>
|
|
|
|
+
|
|
|
|
+const TimerContainer = ({seconds, refresh, render}) => {
|
|
|
|
+ const [currentTime, setCurrentTime] = useState(performance.now())
|
|
|
|
+
|
|
|
|
+ const [time, setTime] = useState(seconds)
|
|
|
|
+ const Render = render;
|
|
|
|
+ let hours = Math.floor(time / 60 / 60)
|
|
|
|
+ let minutes = Math.floor(time / 60 % 60)
|
|
|
|
+ let sec = Math.round(time) % 60
|
|
|
|
+
|
|
|
|
+ const intervalFunc = () => {
|
|
|
|
+ const currentTimeAfterSecond = performance.now()
|
|
|
|
+ const realTimeInterval = currentTimeAfterSecond - currentTime
|
|
|
|
+
|
|
|
|
+ setTime(+time - (realTimeInterval / 1000))
|
|
|
|
+ setCurrentTime(currentTimeAfterSecond)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+
|
|
|
|
+ if (time > 0) {
|
|
|
|
+ const idTimer = setInterval(intervalFunc, refresh)
|
|
|
|
+ return () => clearInterval(idTimer)
|
|
|
|
+ }
|
|
|
|
+ }, [currentTime])
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ <div>{hours < 10 ? "0" + hours : hours} : {minutes < 10 ? "0" + minutes : minutes} : {sec < 10 ? "0" + sec : sec}</div>
|
|
|
|
+ <Render seconds={seconds}/>
|
|
|
|
+ <TimerPresentation hour={hours} min={minutes} sec={sec}/>
|
|
|
|
+ </>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+const TimerPresentation = ({hour, min, sec}) => {
|
|
|
|
+ return (
|
|
|
|
+ <div className="clockBlock">
|
|
|
|
+ <img src={clockFace} className="clockFace"/>
|
|
|
|
+ <img style={{transform: `rotate(${hour * 6}deg)`}} src={clockHour} className="clockHour"/>
|
|
|
|
+ <img style={{transform: `rotate(${min * 6}deg)`}} src={clockMin} className="clockMin"/>
|
|
|
|
+ <img style={{transform: `rotate(${sec * 6}deg)`}} src={clockSec} className="clockSec"/>
|
|
|
|
+
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function App() {
|
|
|
|
+ const [isOpen, setIsOpen] = useState(true)
|
|
|
|
+ const [isOpen2, setIsOpen2] = useState(true)
|
|
|
|
+ return (
|
|
|
|
+ <div className="App">
|
|
|
|
+
|
|
|
|
+ <h4>Task: Spoiler: </h4>
|
|
|
|
+ <Spoiler header={"<h1>Заголовок</h1>"} open={isOpen} setIsOpen={setIsOpen}>
|
|
|
|
+ Контент 1
|
|
|
|
+ <p>
|
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
|
+ </p>
|
|
|
|
+ </Spoiler>
|
|
|
|
+ <Spoiler open={isOpen2} setIsOpen={setIsOpen2}>
|
|
|
|
+ <h2>Контент 2</h2>
|
|
|
|
+ <p>
|
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
|
+ </p>
|
|
|
|
+ </Spoiler>
|
|
|
|
+
|
|
|
|
+ <h4>Task: RangeInput:</h4>
|
|
|
|
+ <RangeInput min={2} max={10}/>
|
|
|
|
+
|
|
|
|
+ <h4>Task PasswordConfirm:</h4>
|
|
|
|
+ <PasswordConfirm min={2}/>
|
|
|
|
+
|
|
|
|
+ <h4>Task: Timer</h4>
|
|
|
|
+ <Timer sec={5000}/>
|
|
|
|
+
|
|
|
|
+ <h4>Task: TimerControl</h4>
|
|
|
|
+ <TimerControl/>
|
|
|
|
+
|
|
|
|
+ <h4>Task: TimerContainer</h4>
|
|
|
|
+ <TimerContainer seconds={1810} refresh={1000} render={SecondsTimer}/>
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export default App;
|