|
@@ -0,0 +1,257 @@
|
|
|
+import './App.css';
|
|
|
+import { clear } from '@testing-library/user-event/dist/clear';
|
|
|
+import React, {useState, useEffect} from 'react';
|
|
|
+import watch from "./img/ClockFace.png";
|
|
|
+import hourArrow from "./img/ClockFace_H.png";
|
|
|
+import minuteArrow from "./img/ClockFace_M.png";
|
|
|
+import secondArrow from "./img/ClockFace_S.png";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// Spoiler
|
|
|
+const Spoiler = ({header="+", open=true, children}) => {
|
|
|
+ const [isOpen, setOpen] = useState(open)
|
|
|
+ return <>
|
|
|
+ <button onClick={() => setOpen(!isOpen)}>{header}</button>
|
|
|
+ {!isOpen && children}
|
|
|
+ </>
|
|
|
+}
|
|
|
+
|
|
|
+// RangeInput
|
|
|
+const RangeInput = ({min, max}) => {
|
|
|
+ const [text, setText] = useState("")
|
|
|
+ return <>
|
|
|
+ <input
|
|
|
+ style={ {color: (text.length <= min || text.length > max) ? 'red' : 'black'}}
|
|
|
+ value={text}
|
|
|
+ onChange={(e) => setText(e.target.value)}>
|
|
|
+ </input>
|
|
|
+ </>
|
|
|
+}
|
|
|
+
|
|
|
+// PasswordConfirm
|
|
|
+const PasswordConfirm = ({min}) => {
|
|
|
+ const [pswd, setPswd] = useState("")
|
|
|
+ const [pswd2, setPswd2] = useState("")
|
|
|
+
|
|
|
+ return <>
|
|
|
+ <h3>password:</h3>
|
|
|
+ <input type='password'
|
|
|
+ style={ {color: pswd.length <= min ? 'red' : 'black'}}
|
|
|
+ onChange={(e) => setPswd(e.target.value)} />
|
|
|
+
|
|
|
+ <h3>repeat password:</h3>
|
|
|
+ <input type = 'password'
|
|
|
+ style={ {color: pswd !== pswd2 ? 'red' : 'black'}}
|
|
|
+ onChange={(e) => setPswd2(e.target.value)} />
|
|
|
+ </>
|
|
|
+}
|
|
|
+
|
|
|
+//Timer
|
|
|
+const Timer = ({seconds}) => {
|
|
|
+ const [sec, setSec] = useState(seconds)
|
|
|
+ let [pause, setPause] = useState(false)
|
|
|
+
|
|
|
+ let hours = Math.floor(sec / (60 * 60))
|
|
|
+ let minuts = Math.floor(sec % (60 * 60) / 60)
|
|
|
+ let second = sec % 60
|
|
|
+
|
|
|
+ let interval
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (sec <= 0) {
|
|
|
+ setPause(true)
|
|
|
+ }
|
|
|
+ if (!pause) {
|
|
|
+ interval = setInterval(() => {
|
|
|
+ setSec(sec => sec - 1)
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ return () => {
|
|
|
+ clearInterval(interval)
|
|
|
+ }
|
|
|
+ }, [pause, sec])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <h3>Timer</h3>
|
|
|
+ <span>{hours}</span> : <span>{minuts}</span> : <span>{second} </span>
|
|
|
+ <button onClick={() => { setPause(!pause) }}>{pause ? 'start' : 'stop'}</button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+//TimerControl
|
|
|
+const TimerControl = () => {
|
|
|
+ const [hours, setHours] = useState(0)
|
|
|
+ const [minutes, setMinutes] = useState(0)
|
|
|
+ const [seconds, setSeconds] = useState(0)
|
|
|
+ const [arr, setArr] = useState([])
|
|
|
+ let sec = hours * 3600 + minutes * 60 + seconds;
|
|
|
+
|
|
|
+
|
|
|
+return (
|
|
|
+ <>
|
|
|
+ <h3>Timer Control</h3>
|
|
|
+ <input placeholder='hours'type='number' min='0' value={hours} onChange={(e) => setHours(+e.target.value)} />
|
|
|
+ <input placeholder='minutes' type='number' min='0' value={minutes} onChange={(e) => setMinutes(+e.target.value)} />
|
|
|
+ <input placeholder='seconds' type='number' min='0' value={seconds} onChange={(e) => setSeconds(+e.target.value)} />
|
|
|
+
|
|
|
+ {arr.map(item=> (<Timer key={item} seconds={sec} />))}
|
|
|
+ <button onClick={()=>{setArr([Math.random()]) }}>Start</button>
|
|
|
+ </>
|
|
|
+)
|
|
|
+}
|
|
|
+
|
|
|
+//TimerContainer
|
|
|
+const SecondsTimer = ({seconds}) => <h2>{seconds}</h2>
|
|
|
+
|
|
|
+const TimerContainer = ({seconds = 1000, refresh, render:Render}) => {
|
|
|
+ const [time, setTime] = useState(seconds)
|
|
|
+ const [pause, setPause] = useState(false)
|
|
|
+
|
|
|
+ let interval
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ let timeBefore = Math.floor(performance.now())
|
|
|
+ interval = setInterval(() => {
|
|
|
+ let timeAfter = Math.floor(performance.now())
|
|
|
+ !pause && time > 0 ? setTime((seconds - (timeAfter - timeBefore) / 1000)) : setTime(time)
|
|
|
+ }, refresh)
|
|
|
+
|
|
|
+ return() => {
|
|
|
+ clearInterval(interval)
|
|
|
+ }
|
|
|
+ }, [pause, refresh, seconds])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <h3>Timer Container</h3>
|
|
|
+ <div>
|
|
|
+ <Render seconds={time} />
|
|
|
+ <button onClick={() => {setPause(!pause)}}>{!pause ? 'Stop' : 'Start'}</button>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+//LCD
|
|
|
+const LCD = ({seconds}) => {
|
|
|
+ let hours = Math.floor(seconds / 60 / 60)
|
|
|
+ let minutes = Math.floor((seconds % 3600) / 60)
|
|
|
+ let sec = seconds % 60
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <div>
|
|
|
+ <span>{hours}</span> : <span>{minutes}</span> : <span>{sec.toFixed(2)} </span>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+//Watch
|
|
|
+const Watch = ({seconds}) => {
|
|
|
+ let hours = Math.floor(seconds / 60 / 60)
|
|
|
+ let minutes = Math.floor((seconds % 3600) / 60)
|
|
|
+ let second = seconds % 60
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <h3>Watch</h3>
|
|
|
+ <div className='Watch'>
|
|
|
+ <img
|
|
|
+ className='Clock'
|
|
|
+ src={watch}
|
|
|
+ alt="Watch" />
|
|
|
+
|
|
|
+ <img
|
|
|
+ className="Arrows"
|
|
|
+ style={{ transform: `rotate(${(360 / 12) * hours}deg)` }}
|
|
|
+ src={hourArrow}
|
|
|
+ alt="Hours"
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ className="Arrows"
|
|
|
+ style={{ transform: `rotate(${(360 / 12 /5) * minutes}deg)` }}
|
|
|
+ src={minuteArrow}
|
|
|
+ alt="Minutes"
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ className="Arrows"
|
|
|
+ style={{ transform: `rotate(${(360 / 12 /5) * second}deg)` }}
|
|
|
+ src={secondArrow}
|
|
|
+ alt="Seconds"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const TimerContainerWatch = ({seconds = 1000, refresh, render:Render}) => {
|
|
|
+ const [time, setTime] = useState(seconds)
|
|
|
+ const [pause, setPause] = useState(false)
|
|
|
+
|
|
|
+ let interval
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ let timeBefore = Math.floor(performance.now())
|
|
|
+ interval = setInterval(() => {
|
|
|
+ let timeAfter = Math.floor(performance.now())
|
|
|
+ !pause && time > 0 ? setTime((seconds - (timeAfter - timeBefore) / 1000)) : setTime(time)
|
|
|
+ }, refresh)
|
|
|
+
|
|
|
+ return() => {
|
|
|
+ clearInterval(interval)
|
|
|
+ }
|
|
|
+ }, [pause, refresh, seconds])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <div>
|
|
|
+ <Render seconds={time} />
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function App() {
|
|
|
+ return (
|
|
|
+ <div className="App">
|
|
|
+ <div>Spoiler:</div>
|
|
|
+ <Spoiler header={<h1>Заголовок</h1>} open>
|
|
|
+ Контент 1
|
|
|
+ <p>
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
+ </p>
|
|
|
+ </Spoiler>
|
|
|
+ <div>Spoiler 2:</div>
|
|
|
+ <Spoiler>
|
|
|
+ <h2>Контент 2</h2>
|
|
|
+ <p>
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
+ </p>
|
|
|
+ </Spoiler>
|
|
|
+
|
|
|
+ <div>Check input length:</div>
|
|
|
+ <RangeInput min={2} max={10}/>
|
|
|
+
|
|
|
+ <PasswordConfirm min={2} />
|
|
|
+
|
|
|
+ <Timer seconds={10000} />
|
|
|
+
|
|
|
+ <TimerControl />
|
|
|
+
|
|
|
+ <TimerContainer seconds={1800} refresh={100} render={LCD} />
|
|
|
+
|
|
|
+ {/* <Watch sec={1800}/> */}
|
|
|
+
|
|
|
+ <TimerContainerWatch seconds={1800} refresh={1000} render={Watch} />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+export default App;
|