123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- import React, {useState, useEffect, useRef} from 'react'
- import './App.scss';
- import clockFace from './img/ClockFace.png';
- import clockH from './img/ClockFace_H.png';
- import clockM from './img/ClockFace_M.png';
- import clockS from './img/ClockFace_S.png';
- const Spoiler = ({header="+", open=true, children}) => {
- const [isOpen, setOpen] = useState(open)
- return (
- <div>
- <div onClick = {e => setOpen(!isOpen)}>{header}</div>
- {isOpen && children}
- </div>
- )
- }
- const RangeInput = ({min, max}) => {
- const [text, setText] = useState('')
- return (
- <input style={ {backgroundColor: (text.length >= min && text.length <= max) ? '#fff' : '#f00'} }
- value={text} onChange={(e) => setText(e.target.value)}/>
- )
- }
- const PasswordConfirm = ({min, char=false, bigChar=false, number=false}) => {
- const [pass, setPass] = useState('')
- const [pass2, setPass2] = useState('')
- const checkPass = (password) => {
- if ( password.length >= min &&
- (char ? password.match(/[a-zA-ZА-ЯЁа-яё]/) : true) &&
- (bigChar ? password.match(/[A-ZА-ЯЁ]/) : true) &&
- (number ? password.match(/[\d]/) : true) ) {
- return true
- } else {
- return false
- }
- }
- const printPassReq = (password) => {
- let str = ''
- if (!checkPass(password)) {
- str += 'Пароль должен содержать: '
- } else {
- str += 'Пароль подходит '
- }
- if (password.length < min) {
- str += ` минимум ${min} символ${((min === 1) ? '' : (min > 1 && min < 5) ? 'а' : 'ов')},`
- }
- if (!(char ? password.match(/[a-zA-ZА-ЯЁа-яё]/) : true)) {
- str += ' буквы,'
- }
- if (!(bigChar ? password.match(/[A-ZА-ЯЁ]/) : true)) {
- str += ' прописные буквы,'
- }
- if (!(number ? password.match(/[\d]/) : true)) {
- str += ' цифры,'
- }
- return str.slice(0, -1)
- }
- return (
- <div>
- <p>
- <input type='password' className="p1" value={pass} onChange={(e) => setPass(e.target.value)}
- style={ {backgroundColor: ( checkPass(pass) && pass === pass2) ? '#fff' : '#f00'} }/>
- <label>
- {printPassReq(pass)}
- </label>
- </p>
- <p>
- <input type='password' className="p2" value={pass2} onChange={(e) => setPass2(e.target.value)}
- style={ {backgroundColor: ( checkPass(pass2) && pass === pass2) ? '#fff' : '#f00'} }/>
- <label>
- {printPassReq(pass2)}
- </label>
- </p>
- <div>{(pass === pass2 ? '' : 'пароли не совпадают')}</div>
- </div>
- )
- }
- const Timer = ({seconds}) => {
- const [counter, setCounter] = useState(seconds.s)
- const [paused, setPause] = useState(false)
- useEffect(() => {
- setCounter(seconds.s)
- }, [seconds])
-
- useEffect(() => {
- const interval = setInterval(() => {
- if (counter > 0 && !paused) {
- setCounter(counter => counter - 1)
- } else {
- clearInterval(interval)
- }
- }, 1000);
- return () => {
- clearInterval(interval)
- }
- }, [paused, counter])
- let h = Math.floor(counter / 3600)
- let m = Math.floor(counter % 3600 / 60)
- let s = counter % 60
- return (
- <div>
- <h2>{h >= 10 ? h : '0'+h}:{m >= 10 ? m : '0'+m}:{s >= 10 ? s : '0'+s}</h2>
- <button onClick={() => setPause(!paused)}>{paused ? 'Го' : 'Пауза'}</button>
- </div>
- )
- }
- const TimerControl = ({setSeconds}) => {
- const [s, setS] = useState(0)
- const [m, setM] = useState(0)
- const [h, setH] = useState(0)
- return (
- <div>
- <input value={h} min="0" max="none" type="number" onChange={(e) => setH(e.target.value)}/>
- <input value={m} min="0" max="60" type="number" onChange={(e) => setM(e.target.value)}/>
- <input value={s} min="0" max="60" type="number" onChange={(e) => setS(e.target.value)}/>
- <button onClick={() => setSeconds({s: +h*3600 + +m*60 + +s}) }>Start</button>
- </div>
- )
- }
- const SecondsTimer = ({seconds}) => (
- <h2>{parseInt(seconds)}</h2>
- )
- const TimerContainer = ({seconds={s:100}, refresh=100, render}) => {
- const [paused, setPause] = useState(false)
- const [time, setTime] = useState(seconds.s)
- const t0 = useRef(performance.now())
- const pausedAt = useRef(0)
- useEffect(() => {
- t0.current = performance.now()
- setTime(seconds.s)
- console.log('mount1')
- }, [seconds])
- useEffect(() => {
- console.log('mount2')
- let interval
- if (paused) {
- pausedAt.current = performance.now()
- clearInterval(interval)
- } else {
- // console.log('pause-', pausedAt.current, performance.now())
- if (pausedAt.current !== 0) {
- t0.current += (performance.now() - pausedAt.current)
- }
- interval = setInterval(() => {
- let t1 = performance.now()
- let delta = (t1-t0.current)/1000
-
- if (seconds.s >= delta) {
- // console.log('timeset', time, seconds, delta)
- setTime(seconds.s - delta)
- } else {
- console.log('0')
- setTime(0)
- clearInterval(interval)
- }
- }, refresh)
- }
-
- return () => {
- console.log('unMount')
- pausedAt.current = 0
- setTime(0)
- clearInterval(interval)
- }
- }, [paused, seconds, refresh])
- const DisplayEl = render
- return (
- <>
- <DisplayEl seconds={time} setPause={() => setPause(!paused)} paused={paused}/>
- </>
- )
- }
- const LCD = ({seconds, setPause, paused}) => {
- let h = (Math.floor(seconds / 3600))
- let m = (Math.floor(seconds % 3600 / 60))
- let s = parseInt(seconds % 60)
- return (
- <div>
- <h2>{h >= 10 ? h : '0'+h}:{m >= 10 ? m : '0'+m}:{s >= 10 ? s : '0'+s}</h2>
- <button onClick={setPause}>{paused ? 'Го' : 'Пауза'}</button>
- </div>
- )
- }
- const Watch = ({seconds, setPause, paused}) => {
- let hDeg = Math.floor(seconds / 720) * 6
- let mDeg = Math.floor(seconds % 3600 / 60) * 6
- let sDeg = parseInt(seconds % 60) * 6
- return (
- <div className="staticCont">
- <div className="watchContainer">
- <img className="watch" src={clockFace} />
- <img className="hours" style={{transform: `rotate(${hDeg}deg)`}} src={clockH} />
- <img className="minutes" style={{transform: `rotate(${mDeg}deg)`}} src={clockM} />
- <img className="seconds" style={{transform: `rotate(${sDeg}deg)`}} src={clockS} />
- </div>
- <button className="watchBtn" onClick={setPause}>{paused ? 'Го' : 'Пауза'}</button>
- </div>
- )
- }
- const Control = () => {
- const [seconds, setSeconds] = useState({s: 200})
- return (
- <div className="controlContainerComb">
- <Timer seconds={seconds} />
- <TimerControl setSeconds={setSeconds}/>
- </div>
- )
- }
- const ControlContainer = () => {
- const [secondsCont, setSecondsCont] = useState({s: 200})
- return (
- <div className="controlContainerComb">
- <TimerContainer seconds={secondsCont} refresh={500} render={LCD}/>
- <TimerControl setSeconds={setSecondsCont}/>
- </div>
- )
- }
- function App() {
-
- return (
- <>
- <Spoiler header={<h1>Заголовок</h1>} open={false}>
- Контент 1
- <p>
- лорем ипсум траливали и тп.
- </p>
- </Spoiler>
-
- <RangeInput min={2} max={10} />
- <PasswordConfirm min={3} char={true} bigChar={true} number={true}/>
- <Control />
- <TimerContainer seconds={{s:10}} refresh={2000} render={SecondsTimer}/>
- <TimerContainer seconds={{s:65}} refresh={100} render={LCD}/>
- <TimerContainer seconds={{s:3660}} refresh={1} render={Watch}/>
- <ControlContainer />
- </>
- );
- }
- export default App;
|