|
@@ -1,342 +1,61 @@
|
|
|
import './App.css';
|
|
|
import React, { useState, useEffect, ReactDOM } from 'react';
|
|
|
-const App = ({ seconds }) => {
|
|
|
- const [time, setTime] = useState(seconds);
|
|
|
- const [paused, setPaused] = useState(false);
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- let interval = null;
|
|
|
- if (!paused && time > 0) {
|
|
|
- interval = setInterval(() => {
|
|
|
- setTime((time) => time - 1);
|
|
|
- }, 1000);
|
|
|
- }
|
|
|
- return () => clearInterval(interval);
|
|
|
- }, [paused, time]);
|
|
|
-
|
|
|
- const handlePause = () => {
|
|
|
- setPaused(true);
|
|
|
- };
|
|
|
-
|
|
|
- const formatTime = (time) => {
|
|
|
- const hours = Math.floor(time / 3600);
|
|
|
- const minutes = Math.floor((time - hours * 3600) / 60);
|
|
|
- const seconds = time - hours * 3600 - minutes * 60;
|
|
|
- return (
|
|
|
- (hours > 0 ? hours + ':' : '') +
|
|
|
- (hours > 0 && minutes < 10 ? '0' : '') +
|
|
|
- minutes +
|
|
|
- ':' +
|
|
|
- (seconds < 10 ? '0' : '') +
|
|
|
- seconds
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
+import { Spoiler } from './copmonents/Spoiler';
|
|
|
+import { RangeInput } from './copmonents/RengeInput';
|
|
|
+import { LoginForm } from './copmonents/LoginForm';
|
|
|
+import { PasswordConfirm } from './copmonents/PasswordConfirm';
|
|
|
+import { Timer } from './copmonents/FormatTime';
|
|
|
+import { TimerControl } from './copmonents/TimerControl';
|
|
|
+import { TimerControl2 } from './copmonents/TimerControl2';
|
|
|
+import { TimerContainer } from './copmonents/TimerContainer';
|
|
|
+import { LCD } from './copmonents/LCD';
|
|
|
+import { Watch } from './copmonents/Watch/Watch';
|
|
|
+
|
|
|
+const App = () => {
|
|
|
return (
|
|
|
<div>
|
|
|
- <h1>{formatTime(time)}</h1>
|
|
|
- <button onClick={handlePause}>Pause</button>
|
|
|
- </div>
|
|
|
- );
|
|
|
-};
|
|
|
-
|
|
|
-{
|
|
|
- const Spoiler = ({ header = '+', open = true, children }) => {
|
|
|
- // создаем состояние isContentVisible и функцию setIsContentVisible для изменения состояния.
|
|
|
- const [isContentVisible, setIsContentVisible] = useState(open);
|
|
|
-
|
|
|
- // создаем функцию для обработки клика на заголовке
|
|
|
- const handleHeaderClick = () => {
|
|
|
- setIsContentVisible(!isContentVisible);
|
|
|
- };
|
|
|
-
|
|
|
- // возвращаем JSX-разметку, в которой обрабатываем состояние isContentVisible
|
|
|
- return (
|
|
|
- <div>
|
|
|
- {/* выводим заголовок и при клике на него вызываем функцию handleHeaderClick */}
|
|
|
- <div onClick={handleHeaderClick}>
|
|
|
- {header}
|
|
|
- {isContentVisible ? '-' : '+'}
|
|
|
- </div>
|
|
|
- {/* если isContentVisible равно true, то выводим children, иначе - ничего не выводим */}
|
|
|
- {isContentVisible ? children : null}
|
|
|
- </div>
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
- // примеры использования компонента Spoiler
|
|
|
-
|
|
|
- <div>
|
|
|
- <Spoiler header={<h1>Заголовок</h1>} open>
|
|
|
- Контент 1<p>лорем ипсум траливали и тп.</p>
|
|
|
- </Spoiler>
|
|
|
-
|
|
|
- <Spoiler>
|
|
|
- <h2>Контент 2</h2>
|
|
|
- <p>лорем ипсум траливали и тп.</p>
|
|
|
- </Spoiler>
|
|
|
- </div>;
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- const RangeInput = ({ min, max }) => {
|
|
|
- // создаем состояние inputText, которое отслеживает значение инпута
|
|
|
- const [inputText, setInputText] = useState('');
|
|
|
-
|
|
|
- // создаем функцию-обработчик для изменения значения inputText
|
|
|
- const handleInputChange = (event) => {
|
|
|
- setInputText(event.target.value);
|
|
|
- };
|
|
|
-
|
|
|
- // создаем переменные для стилей инпута, которые зависят от его длины
|
|
|
- const inputStyle =
|
|
|
- inputText.length < min || inputText.length > max ? { border: '1px solid red' } : {};
|
|
|
-
|
|
|
- // возвращаем JSX-разметку, в которой выводим инпут и применяем стили
|
|
|
- return <input type="text" value={inputText} onChange={handleInputChange} style={inputStyle} />;
|
|
|
- };
|
|
|
-
|
|
|
- // пример использования компонента RangeInput
|
|
|
- <RangeInput min={2} max={10} />;
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- const LoginForm = ({ onLogin }) => {
|
|
|
- const [login, setLogin] = useState('');
|
|
|
- const [password, setPassword] = useState('');
|
|
|
-
|
|
|
- const handleLoginChange = (event) => {
|
|
|
- setLogin(event.target.value);
|
|
|
- };
|
|
|
-
|
|
|
- const handlePasswordChange = (event) => {
|
|
|
- setPassword(event.target.value);
|
|
|
- };
|
|
|
-
|
|
|
- const handleSubmit = (event) => {
|
|
|
- event.preventDefault();
|
|
|
- onLogin(login, password);
|
|
|
- };
|
|
|
-
|
|
|
- const isFormValid = login.trim().length > 0 && password.trim().length > 0;
|
|
|
-
|
|
|
- return (
|
|
|
- <form onSubmit={handleSubmit}>
|
|
|
- <div>
|
|
|
- <label htmlFor="login-input">Login:</label>
|
|
|
- <input type="text" id="login-input" value={login} onChange={handleLoginChange} />
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <label htmlFor="password-input">Password:</label>
|
|
|
- <input
|
|
|
- type="password"
|
|
|
- id="password-input"
|
|
|
- value={password}
|
|
|
- onChange={handlePasswordChange}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <button type="submit" disabled={!isFormValid}>
|
|
|
- Login
|
|
|
- </button>
|
|
|
- </form>
|
|
|
- );
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- const PasswordConfirm = ({ min }) => {
|
|
|
- const [password, setPassword] = useState('');
|
|
|
- const [confirmPassword, setConfirmPassword] = useState('');
|
|
|
- const [valid, setValid] = useState(false);
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- setValid(password.length >= min && password === confirmPassword);
|
|
|
- }, [password, confirmPassword, min]);
|
|
|
-
|
|
|
- const handleChangePassword = (event) => {
|
|
|
- setPassword(event.target.value);
|
|
|
- };
|
|
|
-
|
|
|
- const handleChangeConfirmPassword = (event) => {
|
|
|
- setConfirmPassword(event.target.value);
|
|
|
- };
|
|
|
-
|
|
|
- return (
|
|
|
- <div>
|
|
|
- <label>Password:</label>
|
|
|
- <input type="password" value={password} onChange={handleChangePassword} />
|
|
|
- <br />
|
|
|
- <label>Confirm password:</label>
|
|
|
- <input type="password" value={confirmPassword} onChange={handleChangeConfirmPassword} />
|
|
|
- <br />
|
|
|
- <button disabled={!valid}>Submit</button>
|
|
|
- </div>
|
|
|
- );
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- const TimerControl = ({ onStart }) => {
|
|
|
- const [hours, setHours] = useState(0);
|
|
|
- const [minutes, setMinutes] = useState(0);
|
|
|
- const [seconds, setSeconds] = useState(0);
|
|
|
-
|
|
|
- const handleStartClick = () => {
|
|
|
- const totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
|
|
- onStart(totalSeconds);
|
|
|
- };
|
|
|
-
|
|
|
- return (
|
|
|
+ <h3>Task 1: Spoiler </h3>
|
|
|
<div>
|
|
|
- <input
|
|
|
- type="number"
|
|
|
- value={hours}
|
|
|
- min={0}
|
|
|
- max={23}
|
|
|
- onChange={(e) => setHours(parseInt(e.target.value))}
|
|
|
- />
|
|
|
- <input
|
|
|
- type="number"
|
|
|
- value={minutes}
|
|
|
- min={0}
|
|
|
- max={59}
|
|
|
- onChange={(e) => setMinutes(parseInt(e.target.value))}
|
|
|
- />
|
|
|
- <input
|
|
|
- type="number"
|
|
|
- value={seconds}
|
|
|
- min={0}
|
|
|
- max={59}
|
|
|
- onChange={(e) => setSeconds(parseInt(e.target.value))}
|
|
|
- />
|
|
|
- <button onClick={handleStartClick}>Start</button>
|
|
|
+ <Spoiler header={<h1>Заголовок</h1>}>
|
|
|
+ Контент 1<p>лорем ипсум траливали и тп.</p>
|
|
|
+ </Spoiler>
|
|
|
+
|
|
|
+ <Spoiler>
|
|
|
+ <h2>Контент 2</h2>
|
|
|
+ <p>лорем ипсум траливали и тп.</p>
|
|
|
+ </Spoiler>
|
|
|
</div>
|
|
|
- );
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- const TimerContainer = ({ seconds, refresh, render: TimerComponent }) => {
|
|
|
- const [time, setTime] = useState(seconds);
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- const intervalId = setInterval(() => {
|
|
|
- setTime((prevTime) => {
|
|
|
- const newTime = prevTime - refresh / 1000;
|
|
|
- return newTime < 0 ? 0 : newTime;
|
|
|
- });
|
|
|
- }, refresh);
|
|
|
-
|
|
|
- return () => clearInterval(intervalId);
|
|
|
- }, [refresh]);
|
|
|
-
|
|
|
- const hours = Math.floor(time / 3600);
|
|
|
- const minutes = Math.floor((time % 3600) / 60);
|
|
|
- const secondsRemaining = Math.floor(time % 60);
|
|
|
-
|
|
|
- return <TimerComponent hours={hours} minutes={minutes} seconds={secondsRemaining} />;
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- const LCD = ({ hours, minutes, seconds }) => (
|
|
|
- <div>
|
|
|
- <span>{hours < 10 ? `0${hours}` : hours}</span>:
|
|
|
- <span>{minutes < 10 ? `0${minutes}` : minutes}</span>:
|
|
|
- <span>{seconds < 10 ? `0${seconds}` : seconds}</span>
|
|
|
+ <hr />
|
|
|
+ <h3>Task 2: RangeInput </h3>
|
|
|
+ <RangeInput min={2} max={10} />;
|
|
|
+ <hr />
|
|
|
+ <h3>Task 3: LoginForm </h3>
|
|
|
+ <LoginForm onLogin={console.log} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 4: PasswordConfirm </h3>
|
|
|
+ <PasswordConfirm min={3} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 5: Timer </h3>
|
|
|
+ <Timer seconds={3600} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 6: TimerControl </h3>
|
|
|
+ <TimerControl render={Timer} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 7: TimerContainer </h3>
|
|
|
+ <TimerContainer seconds={1800} refresh={1000} render={SecondsTimer} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 8: LCD </h3>
|
|
|
+ <TimerContainer seconds={1800} refresh={1000} render={LCD} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 9: Watch </h3>
|
|
|
+ <Watch seconds={40} minutes={15} hours={4} />
|
|
|
+ <hr />
|
|
|
+ <h3>Task 10: TimerControl + TimerContainer </h3>
|
|
|
+ <TimerControl2 />
|
|
|
+ <hr />
|
|
|
</div>
|
|
|
);
|
|
|
-
|
|
|
- const TimerContainer = ({ seconds, refresh, render }) => {
|
|
|
- const [time, setTime] = React.useState(seconds);
|
|
|
-
|
|
|
- React.useEffect(() => {
|
|
|
- const interval = setInterval(() => {
|
|
|
- setTime((prevTime) => prevTime - 1);
|
|
|
- }, refresh);
|
|
|
-
|
|
|
- return () => clearInterval(interval);
|
|
|
- }, [refresh]);
|
|
|
-
|
|
|
- const hours = Math.floor(time / 3600);
|
|
|
- const minutes = Math.floor((time % 3600) / 60);
|
|
|
- const secondsLeft = time % 60;
|
|
|
-
|
|
|
- return <div>{render({ hours, minutes, seconds: secondsLeft })}</div>;
|
|
|
- };
|
|
|
-
|
|
|
- // const App = () => (
|
|
|
- // <div>
|
|
|
- // <TimerContainer seconds={1800} refresh={1000} render={LCD} />
|
|
|
- // </div>
|
|
|
- // );
|
|
|
-
|
|
|
- // ReactDOM.render(<App />, document.getElementById('root'));
|
|
|
-}
|
|
|
-
|
|
|
-{
|
|
|
- // import './Watch.css';
|
|
|
-
|
|
|
- const Watch = ({ hours, minutes, seconds }) => {
|
|
|
- const hourDegrees = (hours / 12) * 360 + (minutes / 60) * 30;
|
|
|
- const minuteDegrees = (minutes / 60) * 360 + (seconds / 60) * 6;
|
|
|
- const secondDegrees = (seconds / 60) * 360;
|
|
|
-
|
|
|
- return (
|
|
|
- <div className="watch-container">
|
|
|
- <div className="watch-face">
|
|
|
- <div className="watch-hour-hand" style={{ transform: `rotate(${hourDegrees}deg)` }}></div>
|
|
|
- <div
|
|
|
- className="watch-minute-hand"
|
|
|
- style={{ transform: `rotate(${minuteDegrees}deg)` }}></div>
|
|
|
- <div
|
|
|
- className="watch-second-hand"
|
|
|
- style={{ transform: `rotate(${secondDegrees}deg)` }}></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- );
|
|
|
- };
|
|
|
- // export default Watch;
|
|
|
-}
|
|
|
-
|
|
|
-// {
|
|
|
-// // import TimerContainer from './TimerContainer';
|
|
|
-
|
|
|
-// function TimerControl() {
|
|
|
-// const [hours, setHours] = useState(0);
|
|
|
-// const [minutes, setMinutes] = useState(0);
|
|
|
-// const [seconds, setSeconds] = useState(0);
|
|
|
-
|
|
|
-// const startTimer = () => {
|
|
|
-// const totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
|
|
-// ReactDOM.render(
|
|
|
-// <TimerContainer seconds={totalSeconds} refresh={1000} render={Timer} />,
|
|
|
-// document.getElementById('timer-container'),
|
|
|
-// );
|
|
|
-// };
|
|
|
-
|
|
|
-// return (
|
|
|
-// <div>
|
|
|
-// <div>
|
|
|
-// <label>Hours:</label>
|
|
|
-// <input type="number" value={hours} onChange={(e) => setHours(e.target.value)} />
|
|
|
-// </div>
|
|
|
-// <div>
|
|
|
-// <label>Minutes:</label>
|
|
|
-// <input type="number" value={minutes} onChange={(e) => setMinutes(e.target.value)} />
|
|
|
-// </div>
|
|
|
-// <div>
|
|
|
-// <label>Seconds:</label>
|
|
|
-// <input type="number" value={seconds} onChange={(e) => setSeconds(e.target.value)} />
|
|
|
-// </div>
|
|
|
-// <button onClick={startTimer}>Start</button>
|
|
|
-// <div id="timer-container"></div>
|
|
|
-// </div>
|
|
|
-// );
|
|
|
-// }
|
|
|
-// }
|
|
|
+};
|
|
|
+const SecondsTimer = ({ seconds }) => <h2>{seconds}</h2>;
|
|
|
|
|
|
export default App;
|