mirror of
https://github.com/IgnatZakalinsky/home-works.git
synced 2025-12-16 20:39:24 +00:00
add prettier and reformat all files
This commit is contained in:
7
.prettierrc.js
Normal file
7
.prettierrc.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
trailingComma: 'es5',
|
||||||
|
tabWidth: 4,
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
endOfLine: 'auto',
|
||||||
|
}
|
||||||
109
package.json
109
package.json
@@ -1,56 +1,57 @@
|
|||||||
{
|
{
|
||||||
"name": "home-works",
|
"name": "home-works",
|
||||||
"homepage": "https://IgnatZakalinsky.github.io/home-works",
|
"homepage": "https://IgnatZakalinsky.github.io/home-works",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.9.3",
|
"@emotion/react": "^11.9.3",
|
||||||
"@emotion/styled": "^11.9.3",
|
"@emotion/styled": "^11.9.3",
|
||||||
"@mui/material": "^5.8.4",
|
"@mui/material": "^5.8.4",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^13.0.0",
|
"@testing-library/react": "^13.0.0",
|
||||||
"@testing-library/user-event": "^13.2.1",
|
"@testing-library/user-event": "^13.2.1",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.1",
|
||||||
"@types/node": "^16.7.13",
|
"@types/node": "^16.7.13",
|
||||||
"@types/react": "^18.0.0",
|
"@types/react": "^18.0.0",
|
||||||
"@types/react-dom": "^18.0.0",
|
"@types/react-dom": "^18.0.0",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"gh-pages": "^4.0.0",
|
"gh-pages": "^4.0.0",
|
||||||
"react": "^18.1.0",
|
"prettier": "^2.7.1",
|
||||||
"react-dom": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-redux": "^8.0.2",
|
"react-dom": "^18.1.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-redux": "^8.0.2",
|
||||||
"react-scripts": "5.0.1",
|
"react-router-dom": "^6.3.0",
|
||||||
"redux": "^4.2.0",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "^4.4.2",
|
"redux": "^4.2.0",
|
||||||
"uuid": "^8.3.2",
|
"typescript": "^4.4.2",
|
||||||
"web-vitals": "^2.1.0"
|
"uuid": "^8.3.2",
|
||||||
},
|
"web-vitals": "^2.1.0"
|
||||||
"scripts": {
|
},
|
||||||
"start": "react-scripts start",
|
"scripts": {
|
||||||
"build": "react-scripts build",
|
"start": "react-scripts start",
|
||||||
"test": "react-scripts test",
|
"build": "react-scripts build",
|
||||||
"eject": "react-scripts eject",
|
"test": "react-scripts test",
|
||||||
"predeploy": "npm run build",
|
"eject": "react-scripts eject",
|
||||||
"deploy": "gh-pages -d build"
|
"predeploy": "npm run build",
|
||||||
},
|
"deploy": "gh-pages -d build"
|
||||||
"eslintConfig": {
|
},
|
||||||
"extends": [
|
"eslintConfig": {
|
||||||
"react-app",
|
"extends": [
|
||||||
"react-app/jest"
|
"react-app",
|
||||||
]
|
"react-app/jest"
|
||||||
},
|
]
|
||||||
"browserslist": {
|
},
|
||||||
"production": [
|
"browserslist": {
|
||||||
">0.2%",
|
"production": [
|
||||||
"not dead",
|
">0.2%",
|
||||||
"not op_mini all"
|
"not dead",
|
||||||
],
|
"not op_mini all"
|
||||||
"development": [
|
],
|
||||||
"last 1 chrome version",
|
"development": [
|
||||||
"last 1 firefox version",
|
"last 1 chrome version",
|
||||||
"last 1 safari version"
|
"last 1 firefox version",
|
||||||
]
|
"last 1 safari version"
|
||||||
}
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" data-theme="1">
|
<html lang="en" data-theme="1">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="Web site created using create-react-app"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
@@ -24,12 +24,12 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>React App</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
If you open it directly in the browser, you will see an empty page.
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
@@ -38,6 +38,5 @@
|
|||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
--></body>
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
{
|
{
|
||||||
"short_name": "React App",
|
"short_name": "React App",
|
||||||
"name": "Create React App Sample",
|
"name": "Create React App Sample",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
"type": "image/x-icon"
|
"type": "image/x-icon"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "logo192.png",
|
"src": "logo192.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "192x192"
|
"sizes": "192x192"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "logo512.png",
|
"src": "logo512.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"theme_color": "#000000",
|
"theme_color": "#000000",
|
||||||
"background_color": "#ffffff"
|
"background_color": "#ffffff"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,16 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
|
||||||
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
|
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
|
||||||
'Helvetica Neue', sans-serif;
|
'Helvetica Neue', sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme='1'] {
|
[data-theme='1'] {
|
||||||
@@ -68,7 +67,6 @@ code {
|
|||||||
--success: #16a34a;
|
--success: #16a34a;
|
||||||
--warning: #d97706;
|
--warning: #d97706;
|
||||||
--error: #dc2626;
|
--error: #dc2626;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
|||||||
@@ -3,16 +3,14 @@ import ReactDOM from 'react-dom/client'
|
|||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './s1-main/App'
|
import App from './s1-main/App'
|
||||||
import reportWebVitals from './reportWebVitals'
|
import reportWebVitals from './reportWebVitals'
|
||||||
import {Provider} from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import store from './s2-homeworks/hw10/bll/store'
|
import store from './s2-homeworks/hw10/bll/store'
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
|
||||||
document.getElementById('root') as HTMLElement
|
|
||||||
)
|
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App/>
|
<App />
|
||||||
</Provider>
|
</Provider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { ReportHandler } from 'web-vitals';
|
import { ReportHandler } from 'web-vitals'
|
||||||
|
|
||||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
import('web-vitals').then(
|
||||||
getCLS(onPerfEntry);
|
({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||||
getFID(onPerfEntry);
|
getCLS(onPerfEntry)
|
||||||
getFCP(onPerfEntry);
|
getFID(onPerfEntry)
|
||||||
getLCP(onPerfEntry);
|
getFCP(onPerfEntry)
|
||||||
getTTFB(onPerfEntry);
|
getLCP(onPerfEntry)
|
||||||
});
|
getTTFB(onPerfEntry)
|
||||||
}
|
}
|
||||||
};
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default reportWebVitals;
|
export default reportWebVitals
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hw {
|
.hw {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hwTitle {
|
.hwTitle {
|
||||||
@@ -25,5 +24,5 @@
|
|||||||
|
|
||||||
hr {
|
hr {
|
||||||
border-top: 1px solid #d9d9d9;
|
border-top: 1px solid #d9d9d9;
|
||||||
margin: 0
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const App = () => {
|
|||||||
{/*<HW3/>*/}
|
{/*<HW3/>*/}
|
||||||
{/*<HW4/>*/}
|
{/*<HW4/>*/}
|
||||||
|
|
||||||
<HW5/>
|
<HW5 />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,38 +4,48 @@ import s from './Message.module.css'
|
|||||||
// создать тип вместо any и отобразить приходящие данные
|
// создать тип вместо any и отобразить приходящие данные
|
||||||
const FriendMessage = (props: any) => {
|
const FriendMessage = (props: any) => {
|
||||||
return (
|
return (
|
||||||
<div id={'hw1-friend-message-' + props.message.id} className={s.friendMessage}>
|
<div
|
||||||
|
id={'hw1-friend-message-' + props.message.id}
|
||||||
|
className={s.friendMessage}
|
||||||
|
>
|
||||||
<div className={s.friendImageAndMessage}>
|
<div className={s.friendImageAndMessage}>
|
||||||
<img
|
<img
|
||||||
id={'hw1-friend-avatar-' + props.message.id}
|
id={'hw1-friend-avatar-' + props.message.id}
|
||||||
|
|
||||||
// создаёт студент
|
// создаёт студент
|
||||||
src={props.message.user.avatar}
|
src={props.message.user.avatar}
|
||||||
width={'50px'} height={'50px'}
|
width={'50px'}
|
||||||
|
height={'50px'}
|
||||||
alt={'avatar'}
|
alt={'avatar'}
|
||||||
//
|
//
|
||||||
/>
|
/>
|
||||||
<div className={s.friendMessageText}>
|
<div className={s.friendMessageText}>
|
||||||
<div id={'hw1-friend-name-' + props.message.id} className={s.friendName}>
|
<div
|
||||||
|
id={'hw1-friend-name-' + props.message.id}
|
||||||
|
className={s.friendName}
|
||||||
|
>
|
||||||
{/*создаёт студент*/}
|
{/*создаёт студент*/}
|
||||||
{props.message.user.name}
|
{props.message.user.name}
|
||||||
{/**/}
|
{/**/}
|
||||||
</div>
|
</div>
|
||||||
<div id={'hw1-friend-text-' + props.message.id} className={s.friendText}>
|
<div
|
||||||
|
id={'hw1-friend-text-' + props.message.id}
|
||||||
|
className={s.friendText}
|
||||||
|
>
|
||||||
{/*создаёт студент*/}
|
{/*создаёт студент*/}
|
||||||
{props.message.message.text}
|
{props.message.message.text}
|
||||||
{/**/}
|
{/**/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id={'hw1-friend-time-' + props.message.id} className={s.friendTime}>
|
<div
|
||||||
|
id={'hw1-friend-time-' + props.message.id}
|
||||||
|
className={s.friendTime}
|
||||||
|
>
|
||||||
{/*создаёт студент*/}
|
{/*создаёт студент*/}
|
||||||
{props.message.message.time}
|
{props.message.message.time}
|
||||||
{/**/}
|
{/**/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ export const friendMessage0: MessageType = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const HW1 = () => {
|
const HW1 = () => {
|
||||||
return (
|
return (
|
||||||
<div id={'hw1'} className={s2.hw}>
|
<div id={'hw1'} className={s2.hw}>
|
||||||
@@ -40,21 +39,20 @@ const HW1 = () => {
|
|||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>Homework #1</div>
|
<div className={s2.hwTitle}>Homework #1</div>
|
||||||
<hr/>
|
<hr />
|
||||||
<div className={s2.hwContainer}>
|
<div className={s2.hwContainer}>
|
||||||
{/*проверка отображения (не менять)*/}
|
{/*проверка отображения (не менять)*/}
|
||||||
<div>
|
<div>
|
||||||
<Message message={message0}/>
|
<Message message={message0} />
|
||||||
|
|
||||||
{/*не обязательно*/}
|
{/*не обязательно*/}
|
||||||
<FriendMessage message={friendMessage0}/>
|
<FriendMessage message={friendMessage0} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/*для автоматической проверки дз (не менять)*/}
|
{/*для автоматической проверки дз (не менять)*/}
|
||||||
<MessageSender M={Message}/>
|
<MessageSender M={Message} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/*<hr/>*/}
|
{/*<hr/>*/}
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
@@ -63,7 +63,8 @@
|
|||||||
max-width: 70%;
|
max-width: 70%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #06c;
|
background-color: #06c;
|
||||||
box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03), 0 1px 2px rgba(29, 33, 38, 0.1);
|
box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03),
|
||||||
|
0 1px 2px rgba(29, 33, 38, 0.1);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
@@ -119,7 +120,8 @@
|
|||||||
.textarea {
|
.textarea {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: #f5f7fb;
|
background: #f5f7fb;
|
||||||
box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03), 0 1px 2px rgba(29, 33, 38, 0.1);
|
box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03),
|
||||||
|
0 1px 2px rgba(29, 33, 38, 0.1);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -173,4 +175,3 @@ img {
|
|||||||
width: 48px;
|
width: 48px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const Message = (props: MessagePropsType) => {
|
|||||||
<div className={s.imageAndMessage}>
|
<div className={s.imageAndMessage}>
|
||||||
<img
|
<img
|
||||||
id={'hw1-avatar-' + props.message.id}
|
id={'hw1-avatar-' + props.message.id}
|
||||||
|
|
||||||
// создаёт студент
|
// создаёт студент
|
||||||
src={props.message.user.avatar}
|
src={props.message.user.avatar}
|
||||||
alt={'avatar'}
|
alt={'avatar'}
|
||||||
@@ -36,7 +35,6 @@ const Message = (props: MessagePropsType) => {
|
|||||||
{/**/}
|
{/**/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,33 +9,44 @@ const MessageSender = (props: any) => {
|
|||||||
const [text, setText] = useState<any>('')
|
const [text, setText] = useState<any>('')
|
||||||
|
|
||||||
const addMessage = () => {
|
const addMessage = () => {
|
||||||
setMessages([...messages, {
|
setMessages([
|
||||||
id: messages.length ? messages.length + 1 : 1,
|
...messages,
|
||||||
user: message0.user,
|
{
|
||||||
message: {
|
id: messages.length ? messages.length + 1 : 1,
|
||||||
text,
|
user: message0.user,
|
||||||
time: new Date().toTimeString().slice(0, 5),
|
message: {
|
||||||
|
text,
|
||||||
|
time: new Date().toTimeString().slice(0, 5),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}])
|
])
|
||||||
setTimeout(() => setText(''), 4)
|
setTimeout(() => setText(''), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{messages.map(m => <M key={'message' + m.id} message={m}/>)}
|
{messages.map((m) => (
|
||||||
|
<M key={'message' + m.id} message={m} />
|
||||||
|
))}
|
||||||
|
|
||||||
<div id={'hw1-send-message-form'} className={s.sendForm}>
|
<div id={'hw1-send-message-form'} className={s.sendForm}>
|
||||||
<textarea
|
<textarea
|
||||||
id={'hw1-textarea'}
|
id={'hw1-textarea'}
|
||||||
value={text}
|
value={text}
|
||||||
onChange={e => setText(e.currentTarget.value)}
|
onChange={(e) => setText(e.currentTarget.value)}
|
||||||
placeholder={'Type your message'}
|
placeholder={'Type your message'}
|
||||||
onKeyDown={e => e.key === 'Enter' && e.shiftKey && addMessage()}
|
onKeyDown={(e) =>
|
||||||
|
e.key === 'Enter' && e.shiftKey && addMessage()
|
||||||
|
}
|
||||||
title={'Shift+Enter for send'}
|
title={'Shift+Enter for send'}
|
||||||
className={s.textarea}
|
className={s.textarea}
|
||||||
rows={1}
|
rows={1}
|
||||||
/>
|
/>
|
||||||
<button id={'hw1-button'} onClick={addMessage} className={s.button}>
|
<button
|
||||||
|
id={'hw1-button'}
|
||||||
|
onClick={addMessage}
|
||||||
|
className={s.button}
|
||||||
|
>
|
||||||
{/*текст кнопки могут изменить студенты*/}
|
{/*текст кнопки могут изменить студенты*/}
|
||||||
Send
|
Send
|
||||||
{/**/}
|
{/**/}
|
||||||
|
|||||||
@@ -9,12 +9,17 @@ type AffairPropsType = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Affair(props: AffairPropsType) {
|
function Affair(props: AffairPropsType) {
|
||||||
const deleteCallback = () => {props.deleteAffairCallback(props.affair._id)} // need to fix // создаёт студент
|
const deleteCallback = () => {
|
||||||
|
props.deleteAffairCallback(props.affair._id)
|
||||||
|
} // need to fix // создаёт студент
|
||||||
|
|
||||||
const priorityClass = s.item + ' ' + s[props.affair.priority]
|
const priorityClass = s.item + ' ' + s[props.affair.priority]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw2-affair-' + props.affair._id} className={s.affair + ' ' + s[props.affair.priority]}>
|
<div
|
||||||
|
id={'hw2-affair-' + props.affair._id}
|
||||||
|
className={s.affair + ' ' + s[props.affair.priority]}
|
||||||
|
>
|
||||||
<div id={'hw2-name-' + props.affair._id} className={priorityClass}>
|
<div id={'hw2-name-' + props.affair._id} className={priorityClass}>
|
||||||
{/*создаёт студент*/}
|
{/*создаёт студент*/}
|
||||||
{props.affair.name}
|
{props.affair.name}
|
||||||
@@ -33,9 +38,7 @@ function Affair(props: AffairPropsType) {
|
|||||||
onClick={deleteCallback} // создаёт студент
|
onClick={deleteCallback} // создаёт студент
|
||||||
className={priorityClass + ' ' + s.closeButton}
|
className={priorityClass + ' ' + s.closeButton}
|
||||||
>
|
>
|
||||||
{/*текст кнопки могут изменить студенты*/}
|
{/*текст кнопки могут изменить студенты*/}X{/**/}
|
||||||
X
|
|
||||||
{/**/}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -69,7 +69,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeButton {
|
.closeButton {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import Affair from './Affair'
|
|||||||
import { AffairType, FilterType } from './HW2'
|
import { AffairType, FilterType } from './HW2'
|
||||||
import s from './Affairs.module.css'
|
import s from './Affairs.module.css'
|
||||||
|
|
||||||
type AffairsPropsType = { // need to fix any
|
type AffairsPropsType = {
|
||||||
|
// need to fix any
|
||||||
data: any // AffairType[]
|
data: any // AffairType[]
|
||||||
setFilter: any // (filter: FilterType) => void
|
setFilter: any // (filter: FilterType) => void
|
||||||
// setFilter: Dispatch<SetStateAction<FilterType>>
|
// setFilter: Dispatch<SetStateAction<FilterType>>
|
||||||
@@ -36,10 +37,22 @@ function Affairs(props: AffairsPropsType) {
|
|||||||
// props.setFilter(e.currentTarget.value as FilterType)
|
// props.setFilter(e.currentTarget.value as FilterType)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const cnAll = s.button + ' ' + s.all + ' ' + (props.filter === 'all' ? s.active : '')
|
const cnAll =
|
||||||
const cnHigh = s.button + ' ' + s.high + ' ' + (props.filter === 'high' ? s.active : '')
|
s.button + ' ' + s.all + ' ' + (props.filter === 'all' ? s.active : '')
|
||||||
const cnMiddle = s.button + ' ' + s.middle + ' ' + (props.filter === 'middle' ? s.active : '')
|
const cnHigh =
|
||||||
const cnLow = s.button + ' ' + s.low + ' ' + (props.filter === 'low' ? s.active : '')
|
s.button +
|
||||||
|
' ' +
|
||||||
|
s.high +
|
||||||
|
' ' +
|
||||||
|
(props.filter === 'high' ? s.active : '')
|
||||||
|
const cnMiddle =
|
||||||
|
s.button +
|
||||||
|
' ' +
|
||||||
|
s.middle +
|
||||||
|
' ' +
|
||||||
|
(props.filter === 'middle' ? s.active : '')
|
||||||
|
const cnLow =
|
||||||
|
s.button + ' ' + s.low + ' ' + (props.filter === 'low' ? s.active : '')
|
||||||
// const setClass = (filter: FilterType) => {
|
// const setClass = (filter: FilterType) => {
|
||||||
// return s.button + (props.filter === filter ? ' ' + s.active : '')
|
// return s.button + (props.filter === filter ? ' ' + s.active : '')
|
||||||
// }
|
// }
|
||||||
@@ -47,14 +60,36 @@ function Affairs(props: AffairsPropsType) {
|
|||||||
return (
|
return (
|
||||||
<div className={s.container}>
|
<div className={s.container}>
|
||||||
<div className={s.buttonContainer}>
|
<div className={s.buttonContainer}>
|
||||||
<button id={'hw2-button-all'} onClick={setAll} className={cnAll}>All</button>
|
<button
|
||||||
<button id={'hw2-button-high'} onClick={setHigh} className={cnHigh}>High</button>
|
id={'hw2-button-all'}
|
||||||
<button id={'hw2-button-middle'} onClick={setMiddle} className={cnMiddle}>Middle</button>
|
onClick={setAll}
|
||||||
<button id={'hw2-button-low'} onClick={setLow} className={cnLow}>Low</button>
|
className={cnAll}
|
||||||
</div>
|
>
|
||||||
<div className={s.affairs}>
|
All
|
||||||
{mappedAffairs}
|
</button>
|
||||||
|
<button
|
||||||
|
id={'hw2-button-high'}
|
||||||
|
onClick={setHigh}
|
||||||
|
className={cnHigh}
|
||||||
|
>
|
||||||
|
High
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id={'hw2-button-middle'}
|
||||||
|
onClick={setMiddle}
|
||||||
|
className={cnMiddle}
|
||||||
|
>
|
||||||
|
Middle
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id={'hw2-button-low'}
|
||||||
|
onClick={setLow}
|
||||||
|
className={cnLow}
|
||||||
|
>
|
||||||
|
Low
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={s.affairs}>{mappedAffairs}</div>
|
||||||
{/*<button onClick={set} className={setClass('all')} value={'all'}>All</button>*/}
|
{/*<button onClick={set} className={setClass('all')} value={'all'}>All</button>*/}
|
||||||
{/*<button onClick={set} className={setClass('high')} value={'high'}>High</button>*/}
|
{/*<button onClick={set} className={setClass('high')} value={'high'}>High</button>*/}
|
||||||
{/*<button onClick={set} className={setClass('middle')} value={'middle'}>Middle</button>*/}
|
{/*<button onClick={set} className={setClass('middle')} value={'middle'}>Middle</button>*/}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
function AlternativeAffairs() {
|
function AlternativeAffairs() {
|
||||||
return (
|
return <div></div>
|
||||||
<div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AlternativeAffairs
|
export default AlternativeAffairs
|
||||||
|
|||||||
@@ -13,26 +13,29 @@ export type AffairType = {
|
|||||||
export type FilterType = 'all' | AffairPriorityType
|
export type FilterType = 'all' | AffairPriorityType
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
const defaultAffairs: any = [ // need to fix any // AffairType[]
|
const defaultAffairs: any = [
|
||||||
{_id: 1, name: 'React', priority: 'high'}, // студенты могут изменить содержимое name и количество элементов в массиве, ...priority не менять!
|
// need to fix any // AffairType[]
|
||||||
{_id: 2, name: 'anime', priority: 'low'},
|
{ _id: 1, name: 'React', priority: 'high' }, // студенты могут изменить содержимое name и количество элементов в массиве, ...priority не менять!
|
||||||
{_id: 3, name: 'games', priority: 'low'},
|
{ _id: 2, name: 'anime', priority: 'low' },
|
||||||
{_id: 4, name: 'work', priority: 'high'},
|
{ _id: 3, name: 'games', priority: 'low' },
|
||||||
{_id: 5, name: 'html & css', priority: 'middle'},
|
{ _id: 4, name: 'work', priority: 'high' },
|
||||||
|
{ _id: 5, name: 'html & css', priority: 'middle' },
|
||||||
]
|
]
|
||||||
|
|
||||||
// pure helper functions
|
// pure helper functions
|
||||||
export const filterAffairs = (affairs: any, filter: any): any => { // need to fix any // (affairs: AffairType[], filter: FilterType): AffairType[]
|
export const filterAffairs = (affairs: any, filter: any): any => {
|
||||||
|
// need to fix any // (affairs: AffairType[], filter: FilterType): AffairType[]
|
||||||
if (filter === 'all') return affairs // создаёт студент
|
if (filter === 'all') return affairs // создаёт студент
|
||||||
// else if (filter === 'low') return affairs.filter(a => a.priority === 'low')
|
// else if (filter === 'low') return affairs.filter(a => a.priority === 'low')
|
||||||
// else if (filter === 'middle') return affairs.filter(a => a.priority === 'middle')
|
// else if (filter === 'middle') return affairs.filter(a => a.priority === 'middle')
|
||||||
// else if (filter === 'high') return affairs.filter(a => a.priority === 'high')
|
// else if (filter === 'high') return affairs.filter(a => a.priority === 'high')
|
||||||
// else {
|
// else {
|
||||||
// }
|
// }
|
||||||
// return []
|
// return []
|
||||||
else return affairs.filter((a: any) => a.priority === filter) // need to fix // создаёт студент
|
else return affairs.filter((a: any) => a.priority === filter) // need to fix // создаёт студент
|
||||||
}
|
}
|
||||||
export const deleteAffair = (affairs: any, _id: any): any => { // need to fix any // (affairs: AffairType[], _id: number): AffairType[]
|
export const deleteAffair = (affairs: any, _id: any): any => {
|
||||||
|
// need to fix any // (affairs: AffairType[], _id: number): AffairType[]
|
||||||
return affairs.filter((a: any) => a._id !== _id) // need to fix // создаёт студент
|
return affairs.filter((a: any) => a._id !== _id) // need to fix // создаёт студент
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,15 +44,16 @@ function HW2() {
|
|||||||
const [filter, setFilter] = useState<any>('all') // need to fix any // FilterType
|
const [filter, setFilter] = useState<any>('all') // need to fix any // FilterType
|
||||||
|
|
||||||
const filteredAffairs = filterAffairs(affairs, filter)
|
const filteredAffairs = filterAffairs(affairs, filter)
|
||||||
const deleteAffairCallback = (_id: any) => setAffairs(deleteAffair(affairs, _id)) // need to fix any // number
|
const deleteAffairCallback = (_id: any) =>
|
||||||
|
setAffairs(deleteAffair(affairs, _id)) // need to fix any // number
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw2'} className={s2.hw} style={{marginTop: '39px'}}>
|
<div id={'hw2'} className={s2.hw} style={{ marginTop: '39px' }}>
|
||||||
{/*<hr/>*/}
|
{/*<hr/>*/}
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>Homework #2</div>
|
<div className={s2.hwTitle}>Homework #2</div>
|
||||||
<hr/>
|
<hr />
|
||||||
|
|
||||||
{/*не менять*/}
|
{/*не менять*/}
|
||||||
<Affairs
|
<Affairs
|
||||||
@@ -61,7 +65,7 @@ function HW2() {
|
|||||||
|
|
||||||
{/*<hr/>*/}
|
{/*<hr/>*/}
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {AffairType, deleteAffair} from '../HW2'
|
import { AffairType, deleteAffair } from '../HW2'
|
||||||
|
|
||||||
let initialState: AffairType[]
|
let initialState: AffairType[]
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialState = [
|
initialState = [
|
||||||
{_id: 1, name: 'React', priority: 'high'},
|
{ _id: 1, name: 'React', priority: 'high' },
|
||||||
{_id: 2, name: 'anime', priority: 'low'},
|
{ _id: 2, name: 'anime', priority: 'low' },
|
||||||
{_id: 3, name: 'games', priority: 'low'},
|
{ _id: 3, name: 'games', priority: 'low' },
|
||||||
{_id: 4, name: 'work', priority: 'high'},
|
{ _id: 4, name: 'work', priority: 'high' },
|
||||||
{_id: 5, name: 'html & css', priority: 'middle'},
|
{ _id: 5, name: 'html & css', priority: 'middle' },
|
||||||
{_id: 6, name: 'porn', priority: 'low'},
|
{ _id: 6, name: 'porn', priority: 'low' },
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {AffairType, filterAffairs} from '../HW2'
|
import { AffairType, filterAffairs } from '../HW2'
|
||||||
|
|
||||||
let initialState: AffairType[]
|
let initialState: AffairType[]
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialState = [
|
initialState = [
|
||||||
{_id: 1, name: 'React', priority: 'high'},
|
{ _id: 1, name: 'React', priority: 'high' },
|
||||||
{_id: 2, name: 'anime', priority: 'low'},
|
{ _id: 2, name: 'anime', priority: 'low' },
|
||||||
{_id: 3, name: 'games', priority: 'low'},
|
{ _id: 3, name: 'games', priority: 'low' },
|
||||||
{_id: 4, name: 'work', priority: 'high'},
|
{ _id: 4, name: 'work', priority: 'high' },
|
||||||
{_id: 5, name: 'html & css', priority: 'middle'},
|
{ _id: 5, name: 'html & css', priority: 'middle' },
|
||||||
{_id: 6, name: 'porn', priority: 'low'},
|
{ _id: 6, name: 'porn', priority: 'low' },
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,61 +1,61 @@
|
|||||||
.greetingForm {
|
.greetingForm {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 31px 0 0 70px;
|
padding: 31px 0 0 70px;
|
||||||
height: 336px;
|
height: 336px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputAndButtonContainer {
|
.inputAndButtonContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
margin-bottom: 22px;
|
margin-bottom: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
margin-top: 7px;
|
margin-top: 7px;
|
||||||
color: #cc0000;
|
color: #cc0000;
|
||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 17px;
|
line-height: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
border: 1px solid #d1d1d1;
|
border: 1px solid #d1d1d1;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
width: 370px;
|
width: 370px;
|
||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 8px 0 8px 12px;
|
padding: 8px 0 8px 12px;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input:focus {
|
.input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border: 1px solid #06c;
|
border: 1px solid #06c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.errorInput {
|
.errorInput {
|
||||||
border: 1px solid #cc0000;
|
border: 1px solid #cc0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
background: #06c;
|
background: #06c;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
outline: none;
|
outline: none;
|
||||||
padding: 8px 24px;
|
padding: 8px 24px;
|
||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:focus {
|
.button:focus {
|
||||||
@@ -65,16 +65,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button:disabled {
|
.button:disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.count {
|
.count {
|
||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 17px;
|
line-height: 17px;
|
||||||
margin-bottom: 9px;
|
margin-bottom: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.greeting {
|
.greeting {
|
||||||
|
|||||||
@@ -14,13 +14,24 @@ type GreetingPropsType = {
|
|||||||
|
|
||||||
// презентационная компонента (для верстальщика)
|
// презентационная компонента (для верстальщика)
|
||||||
const Greeting: React.FC<GreetingPropsType> = (
|
const Greeting: React.FC<GreetingPropsType> = (
|
||||||
{name, setNameCallback, addUser, onEnter, error, totalUsers, lastUser, onBlur} // деструктуризация пропсов
|
{
|
||||||
|
name,
|
||||||
|
setNameCallback,
|
||||||
|
addUser,
|
||||||
|
onEnter,
|
||||||
|
error,
|
||||||
|
totalUsers,
|
||||||
|
lastUser,
|
||||||
|
onBlur,
|
||||||
|
} // деструктуризация пропсов
|
||||||
) => {
|
) => {
|
||||||
const inputClass = error ? `${s.input} ${s.errorInput}` : s.input // need to fix with (?:)
|
const inputClass = error ? `${s.input} ${s.errorInput}` : s.input // need to fix with (?:)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw3-form'} className={s.greetingForm}>
|
<div id={'hw3-form'} className={s.greetingForm}>
|
||||||
<div id={'hw3-users-total'} className={s.count}>{totalUsers}</div>
|
<div id={'hw3-users-total'} className={s.count}>
|
||||||
|
{totalUsers}
|
||||||
|
</div>
|
||||||
<div className={s.inputAndButtonContainer}>
|
<div className={s.inputAndButtonContainer}>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
@@ -31,18 +42,24 @@ const Greeting: React.FC<GreetingPropsType> = (
|
|||||||
onKeyDown={onEnter}
|
onKeyDown={onEnter}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
/>
|
/>
|
||||||
<div id={'hw3-error'} className={s.error}>{error}</div>
|
<div id={'hw3-error'} className={s.error}>
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id={'hw3-button'} onClick={addUser} className={s.button} disabled={!name}>add</button>
|
<button
|
||||||
|
id={'hw3-button'}
|
||||||
|
onClick={addUser}
|
||||||
|
className={s.button}
|
||||||
|
disabled={!name}
|
||||||
|
>
|
||||||
|
add
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{lastUser && (
|
{lastUser && (
|
||||||
<div className={s.greeting}>
|
<div className={s.greeting}>
|
||||||
hello{' '}
|
hello <span id={'hw3-last-user'}>{lastUser}</span>!
|
||||||
<span id={'hw3-last-user'}>{lastUser}</span>
|
|
||||||
!
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,11 +11,16 @@ type GreetingContainerPropsType = {
|
|||||||
// function GreetingContainer(props: GreetingPropsType) {
|
// function GreetingContainer(props: GreetingPropsType) {
|
||||||
|
|
||||||
// более современный и удобный для про :)
|
// более современный и удобный для про :)
|
||||||
const GreetingContainer: React.FC<GreetingContainerPropsType> = ({users, addUserCallback}) => { // деструктуризация пропсов
|
const GreetingContainer: React.FC<GreetingContainerPropsType> = ({
|
||||||
|
users,
|
||||||
|
addUserCallback,
|
||||||
|
}) => {
|
||||||
|
// деструктуризация пропсов
|
||||||
const [name, setName] = useState<string>('') // need to fix any
|
const [name, setName] = useState<string>('') // need to fix any
|
||||||
const [error, setError] = useState<string>('') // need to fix any
|
const [error, setError] = useState<string>('') // need to fix any
|
||||||
|
|
||||||
const setNameCallback = (e: ChangeEvent<HTMLInputElement>) => { // need to fix any // нельзя пробелы перед и после имени, можно в середине
|
const setNameCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
// need to fix any // нельзя пробелы перед и после имени, можно в середине
|
||||||
setName(e.currentTarget.value) // need to fix
|
setName(e.currentTarget.value) // need to fix
|
||||||
error && setError('')
|
error && setError('')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ import GreetingContainer from './GreetingContainer'
|
|||||||
|
|
||||||
// types
|
// types
|
||||||
export type UserType = {
|
export type UserType = {
|
||||||
_id: string// need to fix any
|
_id: string // need to fix any
|
||||||
name: string // need to fix any
|
name: string // need to fix any
|
||||||
}
|
}
|
||||||
|
|
||||||
const HW3 = () => {
|
const HW3 = () => {
|
||||||
const [users, setUsers] = useState<UserType[]>([]) // need to fix any
|
const [users, setUsers] = useState<UserType[]>([]) // need to fix any
|
||||||
|
|
||||||
const addUserCallback = (name: string) => { // need to fix any
|
const addUserCallback = (name: string) => {
|
||||||
|
// need to fix any
|
||||||
const user = {
|
const user = {
|
||||||
_id: v1(),
|
_id: v1(),
|
||||||
name,
|
name,
|
||||||
@@ -30,11 +31,13 @@ const HW3 = () => {
|
|||||||
|
|
||||||
{/*для автоматической проверки дз (не менять)*/}
|
{/*для автоматической проверки дз (не менять)*/}
|
||||||
|
|
||||||
|
<hr />
|
||||||
<hr/>
|
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<GreetingContainer users={users} addUserCallback={addUserCallback}/>
|
<GreetingContainer
|
||||||
<hr/>
|
users={users}
|
||||||
|
addUserCallback={addUserCallback}
|
||||||
|
/>
|
||||||
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ const HW4 = () => {
|
|||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>Homework #4</div>
|
<div className={s2.hwTitle}>Homework #4</div>
|
||||||
<hr/>
|
<hr />
|
||||||
{/*проверка отображения*/}
|
{/*проверка отображения*/}
|
||||||
{/*демонстрация возможностей компонент:*/}
|
{/*демонстрация возможностей компонент:*/}
|
||||||
<Stand/>
|
<Stand />
|
||||||
|
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
{/*<hr/>*/}
|
{/*<hr/>*/}
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|||||||
@@ -22,4 +22,4 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 36px;
|
gap: 36px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, {useState} from 'react'
|
import React, { useState } from 'react'
|
||||||
import s from './Stand.module.css'
|
import s from './Stand.module.css'
|
||||||
import SuperInputText from './common/c1-SuperInputText/SuperInputText'
|
import SuperInputText from './common/c1-SuperInputText/SuperInputText'
|
||||||
import SuperCheckbox from './common/c3-SuperCheckbox/SuperCheckbox'
|
import SuperCheckbox from './common/c3-SuperCheckbox/SuperCheckbox'
|
||||||
import SuperButton from "./common/c2-SuperButton/SuperButton";
|
import SuperButton from './common/c2-SuperButton/SuperButton'
|
||||||
|
|
||||||
const Stand = () => {
|
const Stand = () => {
|
||||||
const [stateForAllInputs, setValue] = useState('')
|
const [stateForAllInputs, setValue] = useState('')
|
||||||
@@ -21,7 +21,11 @@ const Stand = () => {
|
|||||||
onChangeText={setValue}
|
onChangeText={setValue}
|
||||||
error={error}
|
error={error}
|
||||||
onEnter={() => {
|
onEnter={() => {
|
||||||
setError(stateForAllInputs.trim() ? undefined : 'some error')
|
setError(
|
||||||
|
stateForAllInputs.trim()
|
||||||
|
? undefined
|
||||||
|
: 'some error'
|
||||||
|
)
|
||||||
setValue('')
|
setValue('')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -31,7 +35,7 @@ const Stand = () => {
|
|||||||
<SuperInputText
|
<SuperInputText
|
||||||
id={'hw4-super-input-like-old'}
|
id={'hw4-super-input-like-old'}
|
||||||
value={stateForAllInputs}
|
value={stateForAllInputs}
|
||||||
onChange={e => setValue(e.currentTarget.value)}
|
onChange={(e) => setValue(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,17 +43,26 @@ const Stand = () => {
|
|||||||
<div className={s.buttons}>
|
<div className={s.buttons}>
|
||||||
{/*обычная кнопка:*/}
|
{/*обычная кнопка:*/}
|
||||||
<div>
|
<div>
|
||||||
<SuperButton id={'hw4-super-button-default'}>default</SuperButton>
|
<SuperButton id={'hw4-super-button-default'}>
|
||||||
|
default
|
||||||
|
</SuperButton>
|
||||||
</div>
|
</div>
|
||||||
{/*красная кнопка:*/}
|
{/*красная кнопка:*/}
|
||||||
<div>
|
<div>
|
||||||
<SuperButton id={'hw4-super-button-red'} xType={'red'}>red</SuperButton>
|
<SuperButton id={'hw4-super-button-red'} xType={'red'}>
|
||||||
|
red
|
||||||
|
</SuperButton>
|
||||||
</div>
|
</div>
|
||||||
{/*задизэйбленная кнопка:*/}
|
{/*задизэйбленная кнопка:*/}
|
||||||
<div>
|
<div>
|
||||||
<SuperButton id={'hw4-super-button-disabled'} xType={'red'} disabled>disabled</SuperButton>
|
<SuperButton
|
||||||
|
id={'hw4-super-button-disabled'}
|
||||||
|
xType={'red'}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
disabled
|
||||||
|
</SuperButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={s.checkboxes}>
|
<div className={s.checkboxes}>
|
||||||
@@ -68,7 +81,7 @@ const Stand = () => {
|
|||||||
<SuperCheckbox
|
<SuperCheckbox
|
||||||
id={'hw4-super-checkbox-like-old'}
|
id={'hw4-super-checkbox-like-old'}
|
||||||
checked={stateForAllCheckboxes}
|
checked={stateForAllCheckboxes}
|
||||||
onChange={e => setChecked(e.currentTarget.checked)}
|
onChange={(e) => setChecked(e.currentTarget.checked)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
import React, { ChangeEvent, DetailedHTMLProps, InputHTMLAttributes, KeyboardEvent, ReactNode } from 'react'
|
import React, {
|
||||||
|
ChangeEvent,
|
||||||
|
DetailedHTMLProps,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
KeyboardEvent,
|
||||||
|
ReactNode,
|
||||||
|
} from 'react'
|
||||||
import s from './SuperInputText.module.css'
|
import s from './SuperInputText.module.css'
|
||||||
|
|
||||||
// тип пропсов обычного инпута
|
// тип пропсов обычного инпута
|
||||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
type DefaultInputPropsType = DetailedHTMLProps<
|
||||||
|
InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement
|
||||||
|
>
|
||||||
|
|
||||||
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
||||||
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
||||||
type SuperInputTextPropsType = Omit<DefaultInputPropsType, 'type'> & { // и + ещё пропсы которых нет в стандартном инпуте
|
type SuperInputTextPropsType = Omit<DefaultInputPropsType, 'type'> & {
|
||||||
|
// и + ещё пропсы которых нет в стандартном инпуте
|
||||||
onChangeText?: (value: string) => void
|
onChangeText?: (value: string) => void
|
||||||
onEnter?: () => void
|
onEnter?: () => void
|
||||||
error?: ReactNode
|
error?: ReactNode
|
||||||
spanClassName?: string
|
spanClassName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperInputText: React.FC<SuperInputTextPropsType> = (
|
const SuperInputText: React.FC<SuperInputTextPropsType> = ({
|
||||||
{
|
onChange,
|
||||||
onChange, onChangeText,
|
onChangeText,
|
||||||
onKeyPress, onEnter,
|
onKeyPress,
|
||||||
error,
|
onEnter,
|
||||||
className, spanClassName,
|
error,
|
||||||
id,
|
className,
|
||||||
|
spanClassName,
|
||||||
|
id,
|
||||||
|
|
||||||
...restProps// все остальные пропсы попадут в объект restProps
|
...restProps // все остальные пропсы попадут в объект restProps
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange?.(e) // если есть пропс onChange, то передать ему е (поскольку onChange не обязателен)
|
onChange?.(e) // если есть пропс onChange, то передать ему е (поскольку onChange не обязателен)
|
||||||
|
|
||||||
@@ -32,13 +43,17 @@ const SuperInputText: React.FC<SuperInputTextPropsType> = (
|
|||||||
const onKeyPressCallback = (e: KeyboardEvent<HTMLInputElement>) => {
|
const onKeyPressCallback = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
onKeyPress?.(e)
|
onKeyPress?.(e)
|
||||||
|
|
||||||
onEnter // если есть пропс onEnter
|
onEnter && // если есть пропс onEnter
|
||||||
&& e.key === 'Enter' // и если нажата кнопка Enter
|
e.key === 'Enter' && // и если нажата кнопка Enter
|
||||||
&& onEnter() // то вызвать его
|
onEnter() // то вызвать его
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalSpanClassName = `${s.error} ${spanClassName ? spanClassName : ''}`
|
const finalSpanClassName = `${s.error} ${
|
||||||
const finalInputClassName = `${s.input} ${error ? s.errorInput : s.superInput} ${className}` // задача на смешивание классов
|
spanClassName ? spanClassName : ''
|
||||||
|
}`
|
||||||
|
const finalInputClassName = `${s.input} ${
|
||||||
|
error ? s.errorInput : s.superInput
|
||||||
|
} ${className}` // задача на смешивание классов
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.inputWrapper}>
|
<div className={s.inputWrapper}>
|
||||||
@@ -48,10 +63,14 @@ const SuperInputText: React.FC<SuperInputTextPropsType> = (
|
|||||||
onChange={onChangeCallback}
|
onChange={onChangeCallback}
|
||||||
onKeyPress={onKeyPressCallback}
|
onKeyPress={onKeyPressCallback}
|
||||||
className={finalInputClassName}
|
className={finalInputClassName}
|
||||||
|
|
||||||
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
||||||
/>
|
/>
|
||||||
<span id={id ? id + '-span' : undefined} className={finalSpanClassName}>{error}</span>
|
<span
|
||||||
|
id={id ? id + '-span' : undefined}
|
||||||
|
className={finalSpanClassName}
|
||||||
|
>
|
||||||
|
{error}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
import React, {ButtonHTMLAttributes, DetailedHTMLProps} from 'react'
|
import React, { ButtonHTMLAttributes, DetailedHTMLProps } from 'react'
|
||||||
import s from './SuperButton.module.css'
|
import s from './SuperButton.module.css'
|
||||||
|
|
||||||
// тип пропсов обычной кнопки, children в котором храниться название кнопки там уже описан
|
// тип пропсов обычной кнопки, children в котором храниться название кнопки там уже описан
|
||||||
type DefaultButtonPropsType = DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
|
type DefaultButtonPropsType = DetailedHTMLProps<
|
||||||
|
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
|
HTMLButtonElement
|
||||||
|
>
|
||||||
|
|
||||||
type SuperButtonPropsType = DefaultButtonPropsType & {
|
type SuperButtonPropsType = DefaultButtonPropsType & {
|
||||||
xType?: string
|
xType?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperButton: React.FC<SuperButtonPropsType> = (
|
const SuperButton: React.FC<SuperButtonPropsType> = ({
|
||||||
{
|
xType,
|
||||||
xType, className,
|
className,
|
||||||
disabled,
|
disabled,
|
||||||
...restProps// все остальные пропсы попадут в объект restProps, там же будет children
|
...restProps // все остальные пропсы попадут в объект restProps, там же будет children
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
const finalClassName = `${s.button} ${
|
const finalClassName = `${s.button} ${
|
||||||
disabled
|
disabled ? s.disabled : xType === 'red' ? s.red : s.default
|
||||||
? s.disabled
|
|
||||||
: xType === 'red'
|
|
||||||
? s.red
|
|
||||||
: s.default
|
|
||||||
} ${className}` // задачка на смешивание классов
|
} ${className}` // задачка на смешивание классов
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
.checkbox:checked {
|
.checkbox:checked {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
|
||||||
background-image: url("checked.svg");
|
background-image: url('checked.svg');
|
||||||
/*background: #99ff99;*/
|
/*background: #99ff99;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,4 +41,4 @@
|
|||||||
.spanClassName {
|
.spanClassName {
|
||||||
font-family: 'Montserrat', sans-serif;
|
font-family: 'Montserrat', sans-serif;
|
||||||
color: #06c;
|
color: #06c;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,33 @@
|
|||||||
import React, {ChangeEvent, DetailedHTMLProps, InputHTMLAttributes} from 'react'
|
import React, {
|
||||||
|
ChangeEvent,
|
||||||
|
DetailedHTMLProps,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
} from 'react'
|
||||||
import s from './SuperCheckbox.module.css'
|
import s from './SuperCheckbox.module.css'
|
||||||
|
|
||||||
// тип пропсов обычного инпута
|
// тип пропсов обычного инпута
|
||||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
type DefaultInputPropsType = DetailedHTMLProps<
|
||||||
|
InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement
|
||||||
|
>
|
||||||
|
|
||||||
type SuperCheckboxPropsType = Omit<DefaultInputPropsType, 'type'> & {
|
type SuperCheckboxPropsType = Omit<DefaultInputPropsType, 'type'> & {
|
||||||
onChangeChecked?: (checked: boolean) => void
|
onChangeChecked?: (checked: boolean) => void
|
||||||
spanClassName?: string
|
spanClassName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperCheckbox: React.FC<SuperCheckboxPropsType> = (
|
const SuperCheckbox: React.FC<SuperCheckboxPropsType> = ({
|
||||||
{
|
onChange,
|
||||||
onChange, onChangeChecked,
|
onChangeChecked,
|
||||||
className, spanClassName,
|
className,
|
||||||
children, // в эту переменную попадёт текст, типизировать не нужно так как он затипизирован в React.FC
|
spanClassName,
|
||||||
id,
|
children, // в эту переменную попадёт текст, типизировать не нужно так как он затипизирован в React.FC
|
||||||
|
id,
|
||||||
|
|
||||||
...restProps// все остальные пропсы попадут в объект restProps
|
...restProps // все остальные пропсы попадут в объект restProps
|
||||||
}
|
}) => {
|
||||||
) => {
|
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => { // задачка на написание онченджа
|
// задачка на написание онченджа
|
||||||
onChange?.(e)
|
onChange?.(e)
|
||||||
|
|
||||||
onChangeChecked?.(e.currentTarget.checked)
|
onChangeChecked?.(e.currentTarget.checked)
|
||||||
@@ -34,10 +42,16 @@ const SuperCheckbox: React.FC<SuperCheckboxPropsType> = (
|
|||||||
type={'checkbox'}
|
type={'checkbox'}
|
||||||
onChange={onChangeCallback}
|
onChange={onChangeCallback}
|
||||||
className={finalInputClassName}
|
className={finalInputClassName}
|
||||||
|
|
||||||
{...restProps} // отдаём инпуту остальные пропсы если они есть (checked например там внутри)
|
{...restProps} // отдаём инпуту остальные пропсы если они есть (checked например там внутри)
|
||||||
/>
|
/>
|
||||||
{children && <span id={id ? id + '-span' : undefined} className={s.spanClassName}>{children}</span>}
|
{children && (
|
||||||
|
<span
|
||||||
|
id={id ? id + '-span' : undefined}
|
||||||
|
className={s.spanClassName}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</label> // благодаря label нажатие на спан передастся в инпут
|
</label> // благодаря label нажатие на спан передастся в инпут
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function HW5() {
|
|||||||
<HashRouter>
|
<HashRouter>
|
||||||
{/*в gh-pages лучше работает HashRouter*/}
|
{/*в gh-pages лучше работает HashRouter*/}
|
||||||
<Layout>
|
<Layout>
|
||||||
<Pages/>
|
<Pages />
|
||||||
</Layout>
|
</Layout>
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Routes, Route, Navigate} from 'react-router-dom'
|
import { Routes, Route, Navigate } from 'react-router-dom'
|
||||||
import Error404 from './pages/Error404'
|
import Error404 from './pages/Error404'
|
||||||
import PreJunior from './pages/PreJunior'
|
import PreJunior from './pages/PreJunior'
|
||||||
import Junior from './pages/Junior'
|
import Junior from './pages/Junior'
|
||||||
@@ -16,18 +16,16 @@ function Pages() {
|
|||||||
<div>
|
<div>
|
||||||
{/*Routes выбирает первый подходящий роут*/}
|
{/*Routes выбирает первый подходящий роут*/}
|
||||||
<Routes>
|
<Routes>
|
||||||
|
|
||||||
{/*роутинг будут писать студенты*/}
|
{/*роутинг будут писать студенты*/}
|
||||||
{/*в начале мы попадаем на страницу '/' и переходим сразу на страницу PRE_JUNIOR*/}
|
{/*в начале мы попадаем на страницу '/' и переходим сразу на страницу PRE_JUNIOR*/}
|
||||||
<Route path={'/'} element={<Navigate to={PATH.PRE_JUNIOR}/>}/>
|
<Route path={'/'} element={<Navigate to={PATH.PRE_JUNIOR} />} />
|
||||||
|
|
||||||
<Route path={PATH.PRE_JUNIOR} element={<PreJunior/>}/>
|
<Route path={PATH.PRE_JUNIOR} element={<PreJunior />} />
|
||||||
<Route path={PATH.JUNIOR} element={<Junior/>}/>
|
<Route path={PATH.JUNIOR} element={<Junior />} />
|
||||||
<Route path={PATH.JUNIOR_PLUS} element={<JuniorPlus/>}/>
|
<Route path={PATH.JUNIOR_PLUS} element={<JuniorPlus />} />
|
||||||
|
|
||||||
{/*он отрисуется если пользователь захочет попасть на несуществующую страницу*/}
|
{/*он отрисуется если пользователь захочет попасть на несуществующую страницу*/}
|
||||||
<Route path={'/*'} element={<Error404/>}/>
|
<Route path={'/*'} element={<Error404 />} />
|
||||||
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,21 +7,19 @@ type PropsType = {
|
|||||||
handleOpen: () => void
|
handleOpen: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Header: FC<PropsType> = ({open, handleOpen}) => {
|
export const Header: FC<PropsType> = ({ open, handleOpen }) => {
|
||||||
|
|
||||||
// hw5-menu изначально отсутствует, при нажатии на бургер - появляется, при повторном нажатии исчезает
|
// hw5-menu изначально отсутствует, при нажатии на бургер - появляется, при повторном нажатии исчезает
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id={'hw5-header'} className={s.header}>
|
<div id={'hw5-header'} className={s.header}>
|
||||||
<img src={burgerIcon}
|
<img
|
||||||
id={'hw5-burger-menu'}
|
src={burgerIcon}
|
||||||
className={s.burgerMenuIcon}
|
id={'hw5-burger-menu'}
|
||||||
onClick={handleOpen}
|
className={s.burgerMenuIcon}
|
||||||
alt={'open menu'}/>
|
onClick={handleOpen}
|
||||||
|
alt={'open menu'}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ type PropsType = {
|
|||||||
children: ReactNode
|
children: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Layout: FC<PropsType> = ({children}) => {
|
export const Layout: FC<PropsType> = ({ children }) => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const handleClose = () => setOpen(false)
|
const handleClose = () => setOpen(false)
|
||||||
const handleOpen = () => setOpen(true)
|
const handleOpen = () => setOpen(true)
|
||||||
@@ -17,11 +17,9 @@ export const Layout: FC<PropsType> = ({children}) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Sidebar open={open} handleClose={handleClose}/>
|
<Sidebar open={open} handleClose={handleClose} />
|
||||||
<Header open={open} handleOpen={handleOpen}/>
|
<Header open={open} handleOpen={handleOpen} />
|
||||||
{children}
|
{children}
|
||||||
</>
|
</>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,4 +11,4 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
height: calc(100vh - var(--header_height));
|
height: calc(100vh - var(--header_height));
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ function Junior() {
|
|||||||
return (
|
return (
|
||||||
<div id={'hw5-page-junior'}>
|
<div id={'hw5-page-junior'}>
|
||||||
junior page
|
junior page
|
||||||
<HW6/>
|
<HW6 />
|
||||||
<HW7/>
|
<HW7 />
|
||||||
<HW8/>
|
<HW8 />
|
||||||
<HW9/>
|
<HW9 />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Junior
|
export default Junior
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ function JuniorPlus() {
|
|||||||
return (
|
return (
|
||||||
<div id={'hw5-page-junior-plus'}>
|
<div id={'hw5-page-junior-plus'}>
|
||||||
junior plus page
|
junior plus page
|
||||||
<HW10/>
|
<HW10 />
|
||||||
<HW11/>
|
<HW11 />
|
||||||
<HW12/>
|
<HW12 />
|
||||||
<HW13/>
|
<HW13 />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default JuniorPlus
|
export default JuniorPlus
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ function PreJunior() {
|
|||||||
return (
|
return (
|
||||||
<div id={'hw5-page-pre-junior'}>
|
<div id={'hw5-page-pre-junior'}>
|
||||||
{/*pre junior page*/}
|
{/*pre junior page*/}
|
||||||
<HW1/>
|
<HW1 />
|
||||||
<HW2/>
|
<HW2 />
|
||||||
<HW3/>
|
<HW3 />
|
||||||
<HW4/>
|
<HW4 />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PreJunior
|
export default PreJunior
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.open {
|
.sidebar.open {
|
||||||
box-shadow: 0 10px 40px rgba(29, 33, 38, 0.13), 0 1px 2px rgba(29, 33, 38, 0.1);
|
box-shadow: 0 10px 40px rgba(29, 33, 38, 0.13),
|
||||||
|
0 1px 2px rgba(29, 33, 38, 0.1);
|
||||||
left: 0;
|
left: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
transition: 0.2s ease-out;
|
transition: 0.2s ease-out;
|
||||||
@@ -69,4 +70,4 @@
|
|||||||
.close img {
|
.close img {
|
||||||
height: 24px;
|
height: 24px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,28 +9,27 @@ type PropsType = {
|
|||||||
handleClose: () => void
|
handleClose: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sidebar: FC<PropsType> = ({open, handleClose}) => {
|
export const Sidebar: FC<PropsType> = ({ open, handleClose }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/*бэкграунд справа от открытого меню*/}
|
{/*бэкграунд справа от открытого меню*/}
|
||||||
{open && <div className={s.background} onClick={handleClose}/>}
|
{open && <div className={s.background} onClick={handleClose} />}
|
||||||
|
|
||||||
<aside className={`${s.sidebar} ${open ? s.open : ''}`}>
|
<aside className={`${s.sidebar} ${open ? s.open : ''}`}>
|
||||||
<button className={s.close} onClick={handleClose}>
|
<button className={s.close} onClick={handleClose}>
|
||||||
<img
|
<img
|
||||||
src={closeIcon}
|
src={closeIcon}
|
||||||
alt='close sidebar'
|
alt="close sidebar"
|
||||||
id={'hw5-menu-close'}
|
id={'hw5-menu-close'}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<nav id={'hw5-menu'} className={s.nav}>
|
<nav id={'hw5-menu'} className={s.nav}>
|
||||||
|
|
||||||
<NavLink
|
<NavLink
|
||||||
id={'hw5-pre-junior-link'}
|
id={'hw5-pre-junior-link'}
|
||||||
to={PATH.PRE_JUNIOR}
|
to={PATH.PRE_JUNIOR}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
className={({isActive}) => isActive ? s.active : ''} // делает студент
|
className={({ isActive }) => (isActive ? s.active : '')} // делает студент
|
||||||
>
|
>
|
||||||
Pre-junior
|
Pre-junior
|
||||||
</NavLink>
|
</NavLink>
|
||||||
@@ -38,7 +37,7 @@ export const Sidebar: FC<PropsType> = ({open, handleClose}) => {
|
|||||||
id={'hw5-junior-link'}
|
id={'hw5-junior-link'}
|
||||||
to={PATH.JUNIOR}
|
to={PATH.JUNIOR}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
className={({isActive}) => isActive ? s.active : ''} // делает студент
|
className={({ isActive }) => (isActive ? s.active : '')} // делает студент
|
||||||
>
|
>
|
||||||
Junior
|
Junior
|
||||||
</NavLink>
|
</NavLink>
|
||||||
@@ -46,14 +45,12 @@ export const Sidebar: FC<PropsType> = ({open, handleClose}) => {
|
|||||||
id={'hw5-junior-plus-link'}
|
id={'hw5-junior-plus-link'}
|
||||||
to={PATH.JUNIOR_PLUS}
|
to={PATH.JUNIOR_PLUS}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
className={({isActive}) => isActive ? s.active : ''} // делает студент
|
className={({ isActive }) => (isActive ? s.active : '')} // делает студент
|
||||||
>
|
>
|
||||||
Junior+
|
Junior+
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, {useState} from 'react'
|
import React, { useState } from 'react'
|
||||||
import SuperEditableSpan from './common/c4-SuperEditableSpan/SuperEditableSpan'
|
import SuperEditableSpan from './common/c4-SuperEditableSpan/SuperEditableSpan'
|
||||||
import {restoreState, saveState} from './localStorage/localStorage'
|
import { restoreState, saveState } from './localStorage/localStorage'
|
||||||
import s2 from '../../s1-main/App.module.css'
|
import s2 from '../../s1-main/App.module.css'
|
||||||
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
||||||
|
|
||||||
@@ -10,13 +10,14 @@ const HW6 = () => {
|
|||||||
const save = () => {
|
const save = () => {
|
||||||
saveState<string>('hw6-editable-span-value', value)
|
saveState<string>('hw6-editable-span-value', value)
|
||||||
}
|
}
|
||||||
const restore = () => { // делают студенты
|
const restore = () => {
|
||||||
|
// делают студенты
|
||||||
setValue(restoreState<string>('hw6-editable-span-value', ''))
|
setValue(restoreState<string>('hw6-editable-span-value', ''))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw6'} className={s2.hw}>
|
<div id={'hw6'} className={s2.hw}>
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 6</div>
|
<div className={s2.hwTitle}>homeworks 6</div>
|
||||||
@@ -27,15 +28,22 @@ const HW6 = () => {
|
|||||||
id={'hw6-spanable-input'}
|
id={'hw6-spanable-input'}
|
||||||
value={value}
|
value={value}
|
||||||
onChangeText={setValue}
|
onChangeText={setValue}
|
||||||
spanProps={{children: value ? undefined : 'enter text...', id: 'hw6-editable-span'}}
|
spanProps={{
|
||||||
|
children: value ? undefined : 'enter text...',
|
||||||
|
id: 'hw6-editable-span',
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SuperButton id={'hw6-save'} onClick={save}>save to ls</SuperButton>
|
<SuperButton id={'hw6-save'} onClick={save}>
|
||||||
<SuperButton id={'hw6-restore'} onClick={restore}>get from ls</SuperButton>
|
save to ls
|
||||||
|
</SuperButton>
|
||||||
|
<SuperButton id={'hw6-restore'} onClick={restore}>
|
||||||
|
get from ls
|
||||||
|
</SuperButton>
|
||||||
|
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,4 +6,4 @@
|
|||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #77aaff;
|
color: #77aaff;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,27 @@
|
|||||||
import React, {DetailedHTMLProps, InputHTMLAttributes, HTMLAttributes, useState} from 'react'
|
import React, {
|
||||||
|
DetailedHTMLProps,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
HTMLAttributes,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
import s from './SuperEditableSpan.module.css'
|
import s from './SuperEditableSpan.module.css'
|
||||||
import SuperInputText from '../../../hw04/common/c1-SuperInputText/SuperInputText'
|
import SuperInputText from '../../../hw04/common/c1-SuperInputText/SuperInputText'
|
||||||
|
|
||||||
// тип пропсов обычного инпута
|
// тип пропсов обычного инпута
|
||||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
type DefaultInputPropsType = DetailedHTMLProps<
|
||||||
|
InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement
|
||||||
|
>
|
||||||
// тип пропсов обычного спана
|
// тип пропсов обычного спана
|
||||||
type DefaultSpanPropsType = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
|
type DefaultSpanPropsType = DetailedHTMLProps<
|
||||||
|
HTMLAttributes<HTMLSpanElement>,
|
||||||
|
HTMLSpanElement
|
||||||
|
>
|
||||||
|
|
||||||
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
||||||
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
||||||
type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & { // и + ещё пропсы которых нет в стандартном инпуте
|
type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & {
|
||||||
|
// и + ещё пропсы которых нет в стандартном инпуте
|
||||||
onChangeText?: (value: string) => void
|
onChangeText?: (value: string) => void
|
||||||
onEnter?: () => void
|
onEnter?: () => void
|
||||||
error?: string
|
error?: string
|
||||||
@@ -17,18 +29,17 @@ type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & { // и + е
|
|||||||
spanProps?: DefaultSpanPropsType // пропсы для спана
|
spanProps?: DefaultSpanPropsType // пропсы для спана
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperEditableSpan: React.FC<SuperEditableSpanType> = (
|
const SuperEditableSpan: React.FC<SuperEditableSpanType> = ({
|
||||||
{
|
autoFocus,
|
||||||
autoFocus,
|
onBlur,
|
||||||
onBlur,
|
onEnter,
|
||||||
onEnter,
|
spanProps,
|
||||||
spanProps,
|
|
||||||
|
|
||||||
...restProps// все остальные пропсы попадут в объект restProps
|
...restProps // все остальные пропсы попадут в объект restProps
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
const [editMode, setEditMode] = useState<boolean>(false)
|
const [editMode, setEditMode] = useState<boolean>(false)
|
||||||
const {children, onDoubleClick, className, ...restSpanProps} = spanProps || {}
|
const { children, onDoubleClick, className, ...restSpanProps } =
|
||||||
|
spanProps || {}
|
||||||
|
|
||||||
const onEnterCallback = () => {
|
const onEnterCallback = () => {
|
||||||
setEditMode(false) // выключить editMode при нажатии Enter // делают студенты
|
setEditMode(false) // выключить editMode при нажатии Enter // делают студенты
|
||||||
@@ -40,7 +51,9 @@ const SuperEditableSpan: React.FC<SuperEditableSpanType> = (
|
|||||||
|
|
||||||
onBlur?.(e)
|
onBlur?.(e)
|
||||||
}
|
}
|
||||||
const onDoubleClickCallBack = (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
|
const onDoubleClickCallBack = (
|
||||||
|
e: React.MouseEvent<HTMLSpanElement, MouseEvent>
|
||||||
|
) => {
|
||||||
setEditMode(true) // включить editMode при двойном клике // делают студенты
|
setEditMode(true) // включить editMode при двойном клике // делают студенты
|
||||||
|
|
||||||
onDoubleClick?.(e)
|
onDoubleClick?.(e)
|
||||||
@@ -50,27 +63,23 @@ const SuperEditableSpan: React.FC<SuperEditableSpanType> = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{editMode
|
{editMode ? (
|
||||||
? (
|
<SuperInputText
|
||||||
<SuperInputText
|
autoFocus={autoFocus || true}
|
||||||
autoFocus={autoFocus || true}
|
onBlur={onBlurCallback}
|
||||||
onBlur={onBlurCallback}
|
onEnter={onEnterCallback}
|
||||||
onEnter={onEnterCallback}
|
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
||||||
|
/>
|
||||||
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
) : (
|
||||||
/>
|
<span
|
||||||
) : (
|
onDoubleClick={onDoubleClickCallBack}
|
||||||
<span
|
className={spanClassName}
|
||||||
onDoubleClick={onDoubleClickCallBack}
|
{...restSpanProps}
|
||||||
className={spanClassName}
|
>
|
||||||
|
{/*если нет захардкодженного текста для спана, то значение инпута*/}
|
||||||
{...restSpanProps}
|
✎ {children || restProps.value}
|
||||||
>
|
</span>
|
||||||
{/*если нет захардкодженного текста для спана, то значение инпута*/}
|
)}
|
||||||
✎ {children || restProps.value}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type StateType = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// сохраняем объект типа StateType в ячейке 'test'
|
// сохраняем объект типа StateType в ячейке 'test'
|
||||||
saveState<StateType>('test', {x: 'A', y: 1})
|
saveState<StateType>('test', { x: 'A', y: 1 })
|
||||||
|
|
||||||
// получем в переменную state объект из ячейки 'test' или дэфолтный объект если ячейка пуста
|
// получем в переменную state объект из ячейки 'test' или дэфолтный объект если ячейка пуста
|
||||||
const state: StateType = restoreState<StateType>('test', {x: '', y: 0})
|
const state: StateType = restoreState<StateType>('test', { x: '', y: 0 })
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import React, {useState} from 'react'
|
import React, { useState } from 'react'
|
||||||
import SuperSelect from './common/c5-SuperSelect/SuperSelect'
|
import SuperSelect from './common/c5-SuperSelect/SuperSelect'
|
||||||
import SuperRadio from './common/c6-SuperRadio/SuperRadio'
|
import SuperRadio from './common/c6-SuperRadio/SuperRadio'
|
||||||
import s2 from '../../s1-main/App.module.css'
|
import s2 from '../../s1-main/App.module.css'
|
||||||
|
|
||||||
const arr = [{id: 1, value: 'x'}, {id: 2, value: 'y'}, {id: 3, value: 'z'}] // value может быть изменено
|
const arr = [
|
||||||
|
{ id: 1, value: 'x' },
|
||||||
|
{ id: 2, value: 'y' },
|
||||||
|
{ id: 3, value: 'z' },
|
||||||
|
] // value может быть изменено
|
||||||
|
|
||||||
const HW7 = () => {
|
const HW7 = () => {
|
||||||
const [value, onChangeOption] = useState(1) // селект и радио должны работать синхронно
|
const [value, onChangeOption] = useState(1) // селект и радио должны работать синхронно
|
||||||
@@ -11,7 +15,7 @@ const HW7 = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw7'} className={s2.hw}>
|
<div id={'hw7'} className={s2.hw}>
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 7</div>
|
<div className={s2.hwTitle}>homeworks 7</div>
|
||||||
@@ -35,9 +39,9 @@ const HW7 = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
.select {
|
.select {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
|
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
|
||||||
linear-gradient(135deg, currentColor 50%, transparent 50%);
|
linear-gradient(135deg, currentColor 50%, transparent 50%);
|
||||||
background-position: calc(100% - 20px) calc(1px + 50%),
|
background-position: calc(100% - 20px) calc(1px + 50%),
|
||||||
calc(100% - 16px) calc(1px + 50%);
|
calc(100% - 16px) calc(1px + 50%);
|
||||||
background-size: 4px 4px, 4px 4px;
|
background-size: 4px 4px, 4px 4px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border: 2px solid var(--primary);
|
border: 2px solid var(--primary);
|
||||||
color: var(--primary-content);
|
color: var(--primary-content);
|
||||||
}
|
}
|
||||||
|
|
||||||
.select:focus {
|
.select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
/*padding: 30px;*/
|
/*padding: 30px;*/
|
||||||
color: var(--primary-content);
|
color: var(--primary-content);
|
||||||
background: var(--primary);
|
background: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.option:checked {
|
.option:checked {
|
||||||
color: var(--secondary-content);
|
color: var(--secondary-content);
|
||||||
background: var(--primary);
|
background: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.option:hover {
|
.option:hover {
|
||||||
box-shadow: 0 0 10px 100px #fed20f inset;
|
box-shadow: 0 0 10px 100px #fed20f inset;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
background: red;
|
background: red;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,54 @@
|
|||||||
import React, {SelectHTMLAttributes, DetailedHTMLProps, ChangeEvent} from 'react'
|
import React, {
|
||||||
|
SelectHTMLAttributes,
|
||||||
|
DetailedHTMLProps,
|
||||||
|
ChangeEvent,
|
||||||
|
} from 'react'
|
||||||
import s from './SuperSelect.module.css'
|
import s from './SuperSelect.module.css'
|
||||||
|
|
||||||
type DefaultSelectPropsType = DetailedHTMLProps<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
|
type DefaultSelectPropsType = DetailedHTMLProps<
|
||||||
|
SelectHTMLAttributes<HTMLSelectElement>,
|
||||||
|
HTMLSelectElement
|
||||||
|
>
|
||||||
|
|
||||||
type SuperSelectPropsType = DefaultSelectPropsType & {
|
type SuperSelectPropsType = DefaultSelectPropsType & {
|
||||||
options?: any[]
|
options?: any[]
|
||||||
onChangeOption?: (option: any) => void
|
onChangeOption?: (option: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperSelect: React.FC<SuperSelectPropsType> = (
|
const SuperSelect: React.FC<SuperSelectPropsType> = ({
|
||||||
{
|
options,
|
||||||
options, className,
|
className,
|
||||||
onChange, onChangeOption,
|
onChange,
|
||||||
...restProps
|
onChangeOption,
|
||||||
}
|
...restProps
|
||||||
) => {
|
}) => {
|
||||||
const mappedOptions: any[] = options ? options.map(o => (
|
const mappedOptions: any[] = options
|
||||||
<option id={'hw7-option-' + o.id} className={s.option} key={o.id} value={o.id}>{o.value}</option>
|
? options.map((o) => (
|
||||||
)) : [] // map options with key
|
<option
|
||||||
|
id={'hw7-option-' + o.id}
|
||||||
|
className={s.option}
|
||||||
|
key={o.id}
|
||||||
|
value={o.id}
|
||||||
|
>
|
||||||
|
{o.value}
|
||||||
|
</option>
|
||||||
|
))
|
||||||
|
: [] // map options with key
|
||||||
|
|
||||||
const onChangeCallback = (e: ChangeEvent<HTMLSelectElement>) => { // делают студенты
|
const onChangeCallback = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
// делают студенты
|
||||||
onChange?.(e)
|
onChange?.(e)
|
||||||
onChangeOption?.(+e.currentTarget.value)
|
onChangeOption?.(+e.currentTarget.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalSelectClassName = s.select + (
|
const finalSelectClassName = s.select + (className ? ' ' + className : '')
|
||||||
className
|
|
||||||
? ' ' + className
|
|
||||||
: ''
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<select className={finalSelectClassName} onChange={onChangeCallback} {...restProps}>
|
<select
|
||||||
|
className={finalSelectClassName}
|
||||||
|
onChange={onChangeCallback}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
{mappedOptions}
|
{mappedOptions}
|
||||||
</select>
|
</select>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,4 +23,4 @@
|
|||||||
|
|
||||||
.label {
|
.label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
import React, {ChangeEvent, InputHTMLAttributes, DetailedHTMLProps, HTMLAttributes} from 'react'
|
import React, {
|
||||||
|
ChangeEvent,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
DetailedHTMLProps,
|
||||||
|
HTMLAttributes,
|
||||||
|
} from 'react'
|
||||||
import s from './SuperRadio.module.css'
|
import s from './SuperRadio.module.css'
|
||||||
|
|
||||||
type DefaultRadioPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
type DefaultRadioPropsType = DetailedHTMLProps<
|
||||||
|
InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement
|
||||||
|
>
|
||||||
// тип пропсов обычного спана
|
// тип пропсов обычного спана
|
||||||
type DefaultSpanPropsType = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
|
type DefaultSpanPropsType = DetailedHTMLProps<
|
||||||
|
HTMLAttributes<HTMLSpanElement>,
|
||||||
|
HTMLSpanElement
|
||||||
|
>
|
||||||
|
|
||||||
type SuperRadioPropsType = Omit<DefaultRadioPropsType, 'type'> & {
|
type SuperRadioPropsType = Omit<DefaultRadioPropsType, 'type'> & {
|
||||||
options?: any[]
|
options?: any[]
|
||||||
@@ -12,54 +23,53 @@ type SuperRadioPropsType = Omit<DefaultRadioPropsType, 'type'> & {
|
|||||||
spanProps?: DefaultSpanPropsType // пропсы для спана
|
spanProps?: DefaultSpanPropsType // пропсы для спана
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperRadio: React.FC<SuperRadioPropsType> = (
|
const SuperRadio: React.FC<SuperRadioPropsType> = ({
|
||||||
{
|
id,
|
||||||
id,
|
name,
|
||||||
name, className,
|
className,
|
||||||
options, value,
|
options,
|
||||||
onChange, onChangeOption,
|
value,
|
||||||
spanProps,
|
onChange,
|
||||||
...restProps
|
onChangeOption,
|
||||||
}
|
spanProps,
|
||||||
) => {
|
...restProps
|
||||||
|
}) => {
|
||||||
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange?.(e)
|
onChange?.(e)
|
||||||
onChangeOption?.(+e.currentTarget.value)
|
onChangeOption?.(+e.currentTarget.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalRadioClassName = `${s.radio} ${className ? className : ''}`
|
const finalRadioClassName = `${s.radio} ${className ? className : ''}`
|
||||||
const spanClassName = `${s.span} ${spanProps?.className ? spanProps.className : ''}`
|
const spanClassName = `${s.span} ${
|
||||||
|
spanProps?.className ? spanProps.className : ''
|
||||||
|
}`
|
||||||
|
|
||||||
const mappedOptions: any[] = options ? options.map(o => (
|
const mappedOptions: any[] = options
|
||||||
<label key={name + '-' + o.id} className={s.label}>
|
? options.map((o) => (
|
||||||
<input
|
<label key={name + '-' + o.id} className={s.label}>
|
||||||
id={id + '-input-' + o.id}
|
<input
|
||||||
className={finalRadioClassName}
|
id={id + '-input-' + o.id}
|
||||||
type={'radio'}
|
className={finalRadioClassName}
|
||||||
|
type={'radio'}
|
||||||
|
// name, checked, value делают студенты
|
||||||
|
name={name}
|
||||||
|
checked={o.id === value}
|
||||||
|
value={o.id}
|
||||||
|
onChange={onChangeCallback}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
id={id + '-span-' + o.id}
|
||||||
|
{...spanProps}
|
||||||
|
className={spanClassName}
|
||||||
|
>
|
||||||
|
{o.value}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
))
|
||||||
|
: []
|
||||||
|
|
||||||
// name, checked, value делают студенты
|
return <>{mappedOptions}</>
|
||||||
name={name}
|
|
||||||
checked={o.id === value}
|
|
||||||
value={o.id}
|
|
||||||
|
|
||||||
onChange={onChangeCallback}
|
|
||||||
{...restProps}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
id={id + '-span-' + o.id}
|
|
||||||
{...spanProps}
|
|
||||||
className={spanClassName}
|
|
||||||
>
|
|
||||||
{o.value}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
)) : []
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{mappedOptions}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SuperRadio
|
export default SuperRadio
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
width: 200px;
|
width: 200px;
|
||||||
|
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,70 @@
|
|||||||
import React, {useState} from 'react'
|
import React, { useState } from 'react'
|
||||||
import {homeWorkReducer} from './bll/homeWorkReducer'
|
import { homeWorkReducer } from './bll/homeWorkReducer'
|
||||||
import s from './HW8.module.css'
|
import s from './HW8.module.css'
|
||||||
import s2 from '../../s1-main/App.module.css'
|
import s2 from '../../s1-main/App.module.css'
|
||||||
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
||||||
import User from './User'
|
import User from './User'
|
||||||
|
|
||||||
export type UserType = { // need to fix any
|
export type UserType = {
|
||||||
|
// need to fix any
|
||||||
_id: number
|
_id: number
|
||||||
name: string
|
name: string
|
||||||
age: number
|
age: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialPeople: UserType[] = [ // студенты могут поменять имя/возраст/количество объектов, _id должны быть целочисленные
|
const initialPeople: UserType[] = [
|
||||||
{_id: 0, name: 'Кот', age: 3},
|
// студенты могут поменять имя/возраст/количество объектов, _id должны быть целочисленные
|
||||||
{_id: 1, name: 'Александр', age: 66},
|
{ _id: 0, name: 'Кот', age: 3 },
|
||||||
{_id: 2, name: 'Коля', age: 16},
|
{ _id: 1, name: 'Александр', age: 66 },
|
||||||
{_id: 3, name: 'Виктор', age: 44},
|
{ _id: 2, name: 'Коля', age: 16 },
|
||||||
{_id: 4, name: 'Дмитрий', age: 40},
|
{ _id: 3, name: 'Виктор', age: 44 },
|
||||||
{_id: 5, name: 'Ирина', age: 55},
|
{ _id: 4, name: 'Дмитрий', age: 40 },
|
||||||
|
{ _id: 5, name: 'Ирина', age: 55 },
|
||||||
]
|
]
|
||||||
|
|
||||||
const HW8 = () => {
|
const HW8 = () => {
|
||||||
const [people, setPeople] = useState<UserType[]>(initialPeople) // need to fix any
|
const [people, setPeople] = useState<UserType[]>(initialPeople) // need to fix any
|
||||||
|
|
||||||
// need to fix any
|
// need to fix any
|
||||||
const finalPeople = people.map((u: UserType) => <User key={u._id} u={u}/>)
|
const finalPeople = people.map((u: UserType) => <User key={u._id} u={u} />)
|
||||||
|
|
||||||
const sortUp = () => setPeople(homeWorkReducer(initialPeople, {type: 'sort', payload: 'up'})) // в алфавитном порядке a.name > b.name
|
const sortUp = () =>
|
||||||
const sortDown = () => setPeople(homeWorkReducer(initialPeople, {type: 'sort', payload: 'down'})) // в обратном порядке a.name < b.name
|
setPeople(
|
||||||
const check18 = () => setPeople(homeWorkReducer(initialPeople, {type: 'check', payload: 18})) // совершеннолетние
|
homeWorkReducer(initialPeople, { type: 'sort', payload: 'up' })
|
||||||
|
) // в алфавитном порядке a.name > b.name
|
||||||
|
const sortDown = () =>
|
||||||
|
setPeople(
|
||||||
|
homeWorkReducer(initialPeople, { type: 'sort', payload: 'down' })
|
||||||
|
) // в обратном порядке a.name < b.name
|
||||||
|
const check18 = () =>
|
||||||
|
setPeople(
|
||||||
|
homeWorkReducer(initialPeople, { type: 'check', payload: 18 })
|
||||||
|
) // совершеннолетние
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw3'} className={s2.hw}>
|
<div id={'hw3'} className={s2.hw}>
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 8</div>
|
<div className={s2.hwTitle}>homeworks 8</div>
|
||||||
|
|
||||||
<div id={'hw8-users'}>
|
<div id={'hw8-users'}>{finalPeople}</div>
|
||||||
{finalPeople}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<SuperButton id={'hw8-button-up'} onClick={sortUp}>sort up</SuperButton>
|
<SuperButton id={'hw8-button-up'} onClick={sortUp}>
|
||||||
<SuperButton id={'hw8-button-down'} onClick={sortDown}>sort down</SuperButton>
|
sort up
|
||||||
<SuperButton id={'hw8-button-18'} onClick={check18}>check 18</SuperButton>
|
</SuperButton>
|
||||||
|
<SuperButton id={'hw8-button-down'} onClick={sortDown}>
|
||||||
|
sort down
|
||||||
|
</SuperButton>
|
||||||
|
<SuperButton id={'hw8-button-18'} onClick={check18}>
|
||||||
|
check 18
|
||||||
|
</SuperButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {UserType} from './HW8'
|
import { UserType } from './HW8'
|
||||||
import s from './HW8.module.css'
|
import s from './HW8.module.css'
|
||||||
|
|
||||||
// types
|
// types
|
||||||
@@ -7,8 +7,7 @@ type UserPropsType = {
|
|||||||
u: UserType
|
u: UserType
|
||||||
}
|
}
|
||||||
|
|
||||||
const User: React.FC<UserPropsType> = ({u}) => {
|
const User: React.FC<UserPropsType> = ({ u }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw8-user-' + u._id + '-' + u.age} className={s.item}>
|
<div id={'hw8-user-' + u._id + '-' + u.age} className={s.item}>
|
||||||
<span id={'hw8-user-name-' + u._id}>{u.name}</span>
|
<span id={'hw8-user-name-' + u._id}>{u.name}</span>
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import {UserType} from '../HW8'
|
import { UserType } from '../HW8'
|
||||||
|
|
||||||
type ActionType = {type: 'sort', payload: 'up' | 'down'} | {type: 'check', payload: number}
|
type ActionType =
|
||||||
|
| { type: 'sort'; payload: 'up' | 'down' }
|
||||||
|
| { type: 'check'; payload: number }
|
||||||
|
|
||||||
export const homeWorkReducer = (state: UserType[], action: ActionType): UserType[] => { // need to fix any
|
export const homeWorkReducer = (
|
||||||
switch (action.type) { // делают студенты
|
state: UserType[],
|
||||||
|
action: ActionType
|
||||||
|
): UserType[] => {
|
||||||
|
// need to fix any
|
||||||
|
switch (
|
||||||
|
action.type // делают студенты
|
||||||
|
) {
|
||||||
case 'sort': {
|
case 'sort': {
|
||||||
const newState = [...state].sort((a, b) => {
|
const newState = [...state].sort((a, b) => {
|
||||||
if (a.name > b.name) return 1
|
if (a.name > b.name) return 1
|
||||||
@@ -14,8 +22,9 @@ export const homeWorkReducer = (state: UserType[], action: ActionType): UserType
|
|||||||
return action.payload === 'up' ? newState : newState.reverse()
|
return action.payload === 'up' ? newState : newState.reverse()
|
||||||
}
|
}
|
||||||
case 'check': {
|
case 'check': {
|
||||||
return state.filter(a => a.age >= action.payload)
|
return state.filter((a) => a.age >= action.payload)
|
||||||
}
|
}
|
||||||
default: return state
|
default:
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,41 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {homeWorkReducer} from '../homeWorkReducer'
|
import { homeWorkReducer } from '../homeWorkReducer'
|
||||||
import {UserType} from '../../HW8'
|
import { UserType } from '../../HW8'
|
||||||
|
|
||||||
let initialState: UserType[] // need to fix any
|
let initialState: UserType[] // need to fix any
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialState = [
|
initialState = [
|
||||||
{_id: 0, name: 'Кот', age: 3},
|
{ _id: 0, name: 'Кот', age: 3 },
|
||||||
{_id: 1, name: 'Александр', age: 66},
|
{ _id: 1, name: 'Александр', age: 66 },
|
||||||
{_id: 2, name: 'Коля', age: 16},
|
{ _id: 2, name: 'Коля', age: 16 },
|
||||||
{_id: 3, name: 'Виктор', age: 44},
|
{ _id: 3, name: 'Виктор', age: 44 },
|
||||||
{_id: 4, name: 'Дмитрий', age: 40},
|
{ _id: 4, name: 'Дмитрий', age: 40 },
|
||||||
{_id: 5, name: 'Ирина', age: 55},
|
{ _id: 5, name: 'Ирина', age: 55 },
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
test('sort name up', () => {
|
test('sort name up', () => {
|
||||||
const newState = homeWorkReducer(initialState, {type: 'sort', payload: 'up'})
|
const newState = homeWorkReducer(initialState, {
|
||||||
|
type: 'sort',
|
||||||
|
payload: 'up',
|
||||||
|
})
|
||||||
|
|
||||||
expect(newState[0]._id).toBe(1)
|
expect(newState[0]._id).toBe(1)
|
||||||
})
|
})
|
||||||
test('sort name down', () => {
|
test('sort name down', () => {
|
||||||
const newState = homeWorkReducer(initialState, {type: 'sort', payload: 'down'})
|
const newState = homeWorkReducer(initialState, {
|
||||||
|
type: 'sort',
|
||||||
|
payload: 'down',
|
||||||
|
})
|
||||||
|
|
||||||
expect(newState[0]._id).toBe(0)
|
expect(newState[0]._id).toBe(0)
|
||||||
})
|
})
|
||||||
test('check age 18', () => {
|
test('check age 18', () => {
|
||||||
const newState = homeWorkReducer(initialState, {type: 'check', payload: 18})
|
const newState = homeWorkReducer(initialState, {
|
||||||
|
type: 'check',
|
||||||
|
payload: 18,
|
||||||
|
})
|
||||||
|
|
||||||
expect(newState.length).toBe(4)
|
expect(newState.length).toBe(4)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
import React, {useState} from 'react'
|
import React, { useState } from 'react'
|
||||||
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
||||||
import {restoreState} from '../hw06/localStorage/localStorage'
|
import { restoreState } from '../hw06/localStorage/localStorage'
|
||||||
|
|
||||||
function Clock() {
|
function Clock() {
|
||||||
const [timerId, setTimerId] = useState<number | undefined>(undefined)
|
const [timerId, setTimerId] = useState<number | undefined>(undefined)
|
||||||
const [date, setDate] = useState<Date>(new Date(restoreState('hw9-date', 0))) // for autotests
|
const [date, setDate] = useState<Date>(
|
||||||
|
new Date(restoreState('hw9-date', 0))
|
||||||
|
) // for autotests
|
||||||
const [show, setShow] = useState<boolean>(false)
|
const [show, setShow] = useState<boolean>(false)
|
||||||
|
|
||||||
const stop = () => { // пишут студенты
|
const stop = () => {
|
||||||
|
// пишут студенты
|
||||||
if (timerId) {
|
if (timerId) {
|
||||||
clearInterval(timerId)
|
clearInterval(timerId)
|
||||||
setTimerId(undefined)
|
setTimerId(undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const start = () => { // пишут студенты
|
const start = () => {
|
||||||
|
// пишут студенты
|
||||||
const id: number = +setInterval(() => {
|
const id: number = +setInterval(() => {
|
||||||
setDate(new Date())
|
setDate(new Date())
|
||||||
}, 1000)
|
}, 1000)
|
||||||
@@ -28,11 +32,11 @@ function Clock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// логику напишет Андрей :) // |v| видел такое в реальных часах |v|
|
// логику напишет Андрей :) // |v| видел такое в реальных часах |v|
|
||||||
const stringTime = date?.toLocaleTimeString() || <br/> // часы24:минуты:секунды (01:02:03)/(23:02:03)/(24:00:00)/(00:00:01) // пишут студенты
|
const stringTime = date?.toLocaleTimeString() || <br /> // часы24:минуты:секунды (01:02:03)/(23:02:03)/(24:00:00)/(00:00:01) // пишут студенты
|
||||||
const stringDate = date?.toLocaleDateString() || <br/> // день.месяц.год (01.02.2022) // пишут студенты, варианты 01.02.0123/01.02.-123/01.02.12345 не рассматриваем
|
const stringDate = date?.toLocaleDateString() || <br /> // день.месяц.год (01.02.2022) // пишут студенты, варианты 01.02.0123/01.02.-123/01.02.12345 не рассматриваем
|
||||||
// день недели на английском, месяц на английском
|
// день недели на английском, месяц на английском
|
||||||
const stringDay = 'Monday' || <br/> // пишут студенты
|
const stringDay = 'Monday' || <br /> // пишут студенты
|
||||||
const stringMonth = 'May' || <br/> // пишут студенты
|
const stringMonth = 'May' || <br /> // пишут студенты
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -53,13 +57,12 @@ function Clock() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<br/>
|
<br />
|
||||||
<br/>
|
<br />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<SuperButton
|
<SuperButton
|
||||||
id={'hw9-button-start'}
|
id={'hw9-button-start'}
|
||||||
disabled={!!timerId} // пишут студенты
|
disabled={!!timerId} // пишут студенты
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ import s2 from '../../s1-main/App.module.css'
|
|||||||
const HW9 = () => {
|
const HW9 = () => {
|
||||||
return (
|
return (
|
||||||
<div id={'hw9'} className={s2.hw}>
|
<div id={'hw9'} className={s2.hw}>
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 9</div>
|
<div className={s2.hwTitle}>homeworks 9</div>
|
||||||
|
|
||||||
{/*should work (должно работать)*/}
|
{/*should work (должно работать)*/}
|
||||||
<Clock/>
|
<Clock />
|
||||||
|
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {useDispatch, useSelector} from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import {AppStoreType} from './bll/store'
|
import { AppStoreType } from './bll/store'
|
||||||
import {loadingAC} from './bll/loadingReducer'
|
import { loadingAC } from './bll/loadingReducer'
|
||||||
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
||||||
import s2 from '../../s1-main/App.module.css'
|
import s2 from '../../s1-main/App.module.css'
|
||||||
|
|
||||||
const HW10 = () => {
|
const HW10 = () => {
|
||||||
// useSelector, useDispatch
|
// useSelector, useDispatch
|
||||||
const isLoading = useSelector<AppStoreType, boolean>((state: any) => state.loading.isLoading)
|
const isLoading = useSelector<AppStoreType, boolean>(
|
||||||
|
(state: any) => state.loading.isLoading
|
||||||
|
)
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const setLoading = () => {
|
const setLoading = () => {
|
||||||
@@ -23,25 +25,28 @@ const HW10 = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw10'} className={s2.hw}>
|
<div id={'hw10'} className={s2.hw}>
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 10</div>
|
<div className={s2.hwTitle}>homeworks 10</div>
|
||||||
|
|
||||||
{/*should work (должно работать)*/}
|
{/*should work (должно работать)*/}
|
||||||
{isLoading
|
{isLoading ? (
|
||||||
? (
|
<div id={'hw10-loading'}>крутилка...</div>
|
||||||
<div id={'hw10-loading'}>крутилка...</div>
|
) : (
|
||||||
) : (
|
<div>
|
||||||
<div>
|
<SuperButton
|
||||||
<SuperButton id={'hw10-button-start-loading'} onClick={setLoading}>set loading...</SuperButton>
|
id={'hw10-button-start-loading'}
|
||||||
</div>
|
onClick={setLoading}
|
||||||
)
|
>
|
||||||
}
|
set loading...
|
||||||
|
</SuperButton>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr/>
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
const initState = {
|
const initState = {
|
||||||
isLoading: false
|
isLoading: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadingReducer = (state = initState, action: LoadingActionType): typeof initState=> { // fix any
|
export const loadingReducer = (
|
||||||
|
state = initState,
|
||||||
|
action: LoadingActionType
|
||||||
|
): typeof initState => {
|
||||||
|
// fix any
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'CHANGE_LOADING': {
|
case 'CHANGE_LOADING': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isLoading: action.isLoading
|
isLoading: action.isLoading,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: return state
|
default:
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,4 +24,7 @@ type LoadingActionType = {
|
|||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadingAC = (isLoading: boolean): LoadingActionType => ({type: 'CHANGE_LOADING', isLoading}) // fix any
|
export const loadingAC = (isLoading: boolean): LoadingActionType => ({
|
||||||
|
type: 'CHANGE_LOADING',
|
||||||
|
isLoading,
|
||||||
|
}) // fix any
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {loadingReducer} from './loadingReducer'
|
import { loadingReducer } from './loadingReducer'
|
||||||
import {combineReducers, legacy_createStore} from 'redux'
|
import { combineReducers, legacy_createStore } from 'redux'
|
||||||
import {themeReducer} from '../../hw12/bll/themeReducer'
|
import { themeReducer } from '../../hw12/bll/themeReducer'
|
||||||
|
|
||||||
const reducers = combineReducers({
|
const reducers = combineReducers({
|
||||||
loading: loadingReducer, // hw10
|
loading: loadingReducer, // hw10
|
||||||
|
|||||||
@@ -6,69 +6,69 @@ import { restoreState } from '../hw06/localStorage/localStorage'
|
|||||||
import { Slider } from '@mui/material'
|
import { Slider } from '@mui/material'
|
||||||
|
|
||||||
function HW11() {
|
function HW11() {
|
||||||
const [value1, setValue1] = useState(restoreState<number>('hw11-value1', 0))
|
const [value1, setValue1] = useState(restoreState<number>('hw11-value1', 0))
|
||||||
const [value2, setValue2] = useState(
|
const [value2, setValue2] = useState(
|
||||||
restoreState<number>('hw11-value2', 100)
|
restoreState<number>('hw11-value2', 100)
|
||||||
)
|
)
|
||||||
|
|
||||||
const change = (event: Event, newValue: number | number[]) => {
|
const change = (event: Event, newValue: number | number[]) => {
|
||||||
if (Array.isArray(newValue)) {
|
if (Array.isArray(newValue)) {
|
||||||
setValue1(newValue[0])
|
setValue1(newValue[0])
|
||||||
setValue2(newValue[1])
|
setValue2(newValue[1])
|
||||||
} else {
|
} else {
|
||||||
setValue1(newValue)
|
setValue1(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw11'} className={s2.hw}>
|
<div id={'hw11'} className={s2.hw}>
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 11</div>
|
<div className={s2.hwTitle}>homeworks 11</div>
|
||||||
|
|
||||||
{/*should work (должно работать)*/}
|
{/*should work (должно работать)*/}
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
id={'hw11-value'}
|
id={'hw11-value'}
|
||||||
style={{ display: 'inline-block', width: 32 }}
|
style={{ display: 'inline-block', width: 32 }}
|
||||||
>
|
>
|
||||||
{value1}
|
{value1}
|
||||||
</span>
|
</span>
|
||||||
<Slider
|
<Slider
|
||||||
// сделать так чтоб value1 изменялось
|
// сделать так чтоб value1 изменялось
|
||||||
value={value1}
|
value={value1}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
sx={{ width: '160px' }}
|
sx={{ width: '160px' }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
id={'hw11-value-1'}
|
id={'hw11-value-1'}
|
||||||
style={{ display: 'inline-block', width: 32 }}
|
style={{ display: 'inline-block', width: 32 }}
|
||||||
>
|
>
|
||||||
{value1}
|
{value1}
|
||||||
</span>
|
</span>
|
||||||
<Slider
|
<Slider
|
||||||
value={[value1, value2]}
|
value={[value1, value2]}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
sx={{ width: '160px' }}
|
sx={{ width: '160px' }}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
id={'hw11-value-2'}
|
id={'hw11-value-2'}
|
||||||
style={{ display: 'inline-block', width: 32 }}
|
style={{ display: 'inline-block', width: 32 }}
|
||||||
>
|
>
|
||||||
{value2}
|
{value2}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HW11
|
export default HW11
|
||||||
|
|||||||
@@ -18,4 +18,4 @@
|
|||||||
background: red;
|
background: red;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,31 @@
|
|||||||
import React, {ChangeEvent, DetailedHTMLProps, InputHTMLAttributes} from 'react'
|
import React, {
|
||||||
|
ChangeEvent,
|
||||||
|
DetailedHTMLProps,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
} from 'react'
|
||||||
import s from './SuperRange.module.css'
|
import s from './SuperRange.module.css'
|
||||||
|
|
||||||
// тип пропсов обычного инпута
|
// тип пропсов обычного инпута
|
||||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
type DefaultInputPropsType = DetailedHTMLProps<
|
||||||
|
InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement
|
||||||
|
>
|
||||||
|
|
||||||
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута
|
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута
|
||||||
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
||||||
type SuperRangePropsType = DefaultInputPropsType & { // и + ещё пропсы которых нет в стандартном инпуте
|
type SuperRangePropsType = DefaultInputPropsType & {
|
||||||
|
// и + ещё пропсы которых нет в стандартном инпуте
|
||||||
onChangeRange?: (value: number) => void
|
onChangeRange?: (value: number) => void
|
||||||
};
|
}
|
||||||
|
|
||||||
const SuperRange: React.FC<SuperRangePropsType> = (
|
const SuperRange: React.FC<SuperRangePropsType> = ({
|
||||||
{
|
type, // достаём и игнорируем чтоб нельзя было задать другой тип инпута
|
||||||
type, // достаём и игнорируем чтоб нельзя было задать другой тип инпута
|
onChange,
|
||||||
onChange, onChangeRange,
|
onChangeRange,
|
||||||
className,
|
className,
|
||||||
|
|
||||||
...restProps// все остальные пропсы попадут в объект restProps
|
...restProps // все остальные пропсы попадут в объект restProps
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange && onChange(e) // сохраняем старую функциональность
|
onChange && onChange(e) // сохраняем старую функциональность
|
||||||
|
|
||||||
@@ -35,7 +42,6 @@ const SuperRange: React.FC<SuperRangePropsType> = (
|
|||||||
type={'range'}
|
type={'range'}
|
||||||
onChange={onChangeCallback}
|
onChange={onChangeCallback}
|
||||||
className={finalRangeClassName}
|
className={finalRangeClassName}
|
||||||
|
|
||||||
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import React, {DetailedHTMLProps, InputHTMLAttributes} from 'react'
|
import React, { DetailedHTMLProps, InputHTMLAttributes } from 'react'
|
||||||
import SuperRange from '../c7-SuperRange/SuperRange'
|
import SuperRange from '../c7-SuperRange/SuperRange'
|
||||||
|
|
||||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
type DefaultInputPropsType = DetailedHTMLProps<
|
||||||
|
InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement
|
||||||
|
>
|
||||||
|
|
||||||
type SuperDoubleRangePropsType = Omit<DefaultInputPropsType, 'value'> & {
|
type SuperDoubleRangePropsType = Omit<DefaultInputPropsType, 'value'> & {
|
||||||
onChangeRange?: (value: [number, number]) => void
|
onChangeRange?: (value: [number, number]) => void
|
||||||
@@ -9,13 +12,12 @@ type SuperDoubleRangePropsType = Omit<DefaultInputPropsType, 'value'> & {
|
|||||||
// min, max, step, disable, ...
|
// min, max, step, disable, ...
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperDoubleRange: React.FC<SuperDoubleRangePropsType> = (
|
const SuperDoubleRange: React.FC<SuperDoubleRangePropsType> = ({
|
||||||
{
|
onChangeRange,
|
||||||
onChangeRange, value,
|
value,
|
||||||
// min, max, step, disable, ...
|
// min, max, step, disable, ...
|
||||||
...restProps
|
...restProps
|
||||||
}
|
}) => {
|
||||||
) => {
|
|
||||||
// сделать самому, можно подключать библиотеки
|
// сделать самому, можно подключать библиотеки
|
||||||
const [value1, value2] = value || [-1, -1]
|
const [value1, value2] = value || [-1, -1]
|
||||||
|
|
||||||
@@ -28,9 +30,26 @@ const SuperDoubleRange: React.FC<SuperDoubleRangePropsType> = (
|
|||||||
|
|
||||||
// взять двойной ползунок из материал-юай и повесить на него ид
|
// взять двойной ползунок из материал-юай и повесить на него ид
|
||||||
return (
|
return (
|
||||||
<div id={'hw11-double-slider'} style={{position: "relative", display: "inline-block", width: 176}}>
|
<div
|
||||||
<SuperRange style={{position: "absolute", top: -12}} value={value?.[0]} onChangeRange={change1} {...restProps}/>
|
id={'hw11-double-slider'}
|
||||||
<SuperRange style={{position: "absolute", top: -12}} value={value?.[1]} onChangeRange={change2} {...restProps}/>
|
style={{
|
||||||
|
position: 'relative',
|
||||||
|
display: 'inline-block',
|
||||||
|
width: 176,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SuperRange
|
||||||
|
style={{ position: 'absolute', top: -12 }}
|
||||||
|
value={value?.[0]}
|
||||||
|
onChangeRange={change1}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
<SuperRange
|
||||||
|
style={{ position: 'absolute', top: -12 }}
|
||||||
|
value={value?.[1]}
|
||||||
|
onChangeRange={change2}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,4 +20,4 @@
|
|||||||
|
|
||||||
.some-text {
|
.some-text {
|
||||||
color: darkslateblue;
|
color: darkslateblue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,44 +6,44 @@ import { useDispatch, useSelector } from 'react-redux'
|
|||||||
import { changeThemeId } from './bll/themeReducer'
|
import { changeThemeId } from './bll/themeReducer'
|
||||||
|
|
||||||
const themes = [
|
const themes = [
|
||||||
{ id: 1, value: 'light' },
|
{ id: 1, value: 'light' },
|
||||||
{ id: 2, value: 'dark' },
|
{ id: 2, value: 'dark' },
|
||||||
{ id: 3, value: 'retro' },
|
{ id: 3, value: 'retro' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const HW12 = () => {
|
const HW12 = () => {
|
||||||
const themeId = useSelector((state: any) => state.theme.themeId)
|
const themeId = useSelector((state: any) => state.theme.themeId)
|
||||||
const theme = themes.find((t) => t.id === themeId)!.value
|
const theme = themes.find((t) => t.id === themeId)!.value
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const change = (id: number) => {
|
const change = (id: number) => {
|
||||||
dispatch(changeThemeId(id))
|
dispatch(changeThemeId(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw12'} className={s2.hw + ' ' + s[theme]}>
|
<div id={'hw12'} className={s2.hw + ' ' + s[theme]}>
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id={'hw12-text'}
|
id={'hw12-text'}
|
||||||
className={s2.hwTitle + ' ' + s[theme + '-text']}
|
className={s2.hwTitle + ' ' + s[theme + '-text']}
|
||||||
>
|
>
|
||||||
homeworks 12
|
homeworks 12
|
||||||
</div>
|
</div>
|
||||||
<SuperSelect
|
<SuperSelect
|
||||||
id={'hw12-select-theme'}
|
id={'hw12-select-theme'}
|
||||||
value={themeId}
|
value={themeId}
|
||||||
options={themes}
|
options={themes}
|
||||||
onChangeOption={change}
|
onChangeOption={change}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HW12
|
export default HW12
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
const initState = {
|
const initState = {
|
||||||
themeId: 1
|
themeId: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const themeReducer = (state = initState, action: any): any => { // fix any
|
export const themeReducer = (state = initState, action: any): any => {
|
||||||
|
// fix any
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_THEME_ID': {
|
case 'SET_THEME_ID': {
|
||||||
return {
|
return {
|
||||||
@@ -10,8 +11,9 @@ export const themeReducer = (state = initState, action: any): any => { // fix an
|
|||||||
themeId: action.id,
|
themeId: action.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: return state
|
default:
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const changeThemeId = (id: number): any => ({type: 'SET_THEME_ID', id}) // fix any
|
export const changeThemeId = (id: number): any => ({ type: 'SET_THEME_ID', id }) // fix any
|
||||||
|
|||||||
@@ -3,86 +3,86 @@ import s2 from '../../s1-main/App.module.css'
|
|||||||
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
axios.interceptors.response.use(
|
axios.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
(error) => {
|
(error) => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
if (typeof error.response === 'undefined') {
|
if (typeof error.response === 'undefined') {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const HW13 = () => {
|
const HW13 = () => {
|
||||||
const [answer, setAnswer] = useState('')
|
const [answer, setAnswer] = useState('')
|
||||||
const [info, setInfo] = useState('')
|
const [info, setInfo] = useState('')
|
||||||
|
|
||||||
const send = (x?: boolean | null) => () => {
|
const send = (x?: boolean | null) => () => {
|
||||||
const url =
|
const url =
|
||||||
x === null
|
x === null
|
||||||
? 'https://xxxxxx.ccc'
|
? 'https://xxxxxx.ccc'
|
||||||
: 'https://neko-cafe-back.herokuapp.com/auth/test'
|
: 'https://neko-cafe-back.herokuapp.com/auth/test'
|
||||||
|
|
||||||
setAnswer('...loading')
|
setAnswer('...loading')
|
||||||
setInfo('...loading')
|
setInfo('...loading')
|
||||||
axios
|
axios
|
||||||
.post(url, { success: x })
|
.post(url, { success: x })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setAnswer(res.data.errorText)
|
setAnswer(res.data.errorText)
|
||||||
setInfo(res.data.info)
|
setInfo(res.data.info)
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
setAnswer(e.response?.data?.errorText || e.message)
|
setAnswer(e.response?.data?.errorText || e.message)
|
||||||
setInfo(e.response?.data?.info || e.name)
|
setInfo(e.response?.data?.info || e.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={'hw13'} className={s2.hw}>
|
<div id={'hw13'} className={s2.hw}>
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
<div className={s2.hwTitle}>homeworks 13</div>
|
<div className={s2.hwTitle}>homeworks 13</div>
|
||||||
|
|
||||||
{/*для автоматической проверки дз (не менять)*/}
|
{/*для автоматической проверки дз (не менять)*/}
|
||||||
<SuperButton
|
<SuperButton
|
||||||
id={'hw13-send-true'}
|
id={'hw13-send-true'}
|
||||||
onClick={send(true)}
|
onClick={send(true)}
|
||||||
disabled={answer === '...loading'}
|
disabled={answer === '...loading'}
|
||||||
>
|
>
|
||||||
send true
|
send true
|
||||||
</SuperButton>
|
</SuperButton>
|
||||||
<SuperButton
|
<SuperButton
|
||||||
id={'hw13-send-false'}
|
id={'hw13-send-false'}
|
||||||
onClick={send(false)}
|
onClick={send(false)}
|
||||||
disabled={answer === '...loading'}
|
disabled={answer === '...loading'}
|
||||||
>
|
>
|
||||||
send false
|
send false
|
||||||
</SuperButton>
|
</SuperButton>
|
||||||
<SuperButton
|
<SuperButton
|
||||||
id={'hw13-send-undefined'}
|
id={'hw13-send-undefined'}
|
||||||
onClick={send(undefined)}
|
onClick={send(undefined)}
|
||||||
disabled={answer === '...loading'}
|
disabled={answer === '...loading'}
|
||||||
>
|
>
|
||||||
send undefined
|
send undefined
|
||||||
</SuperButton>
|
</SuperButton>
|
||||||
<SuperButton
|
<SuperButton
|
||||||
id={'hw13-send-null'}
|
id={'hw13-send-null'}
|
||||||
onClick={send(null)}
|
onClick={send(null)}
|
||||||
disabled={answer === '...loading'}
|
disabled={answer === '...loading'}
|
||||||
>
|
>
|
||||||
send null
|
send null
|
||||||
</SuperButton>
|
</SuperButton>
|
||||||
|
|
||||||
<div id={'hw13-answer'}>{answer}</div>
|
<div id={'hw13-answer'}>{answer}</div>
|
||||||
<div id={'hw13-info'}>{info}</div>
|
<div id={'hw13-info'}>{info}</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
<hr />
|
<hr />
|
||||||
{/*можно убрать этот тег*/}
|
{/*можно убрать этот тег*/}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HW13
|
export default HW13
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
// allows you to do things like:
|
// allows you to do things like:
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom'
|
||||||
|
|||||||
@@ -1,26 +1,20 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
"allowJs": true,
|
||||||
"dom.iterable",
|
"skipLibCheck": true,
|
||||||
"esnext"
|
"esModuleInterop": true,
|
||||||
],
|
"allowSyntheticDefaultImports": true,
|
||||||
"allowJs": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"esModuleInterop": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"module": "esnext",
|
||||||
"strict": true,
|
"moduleResolution": "node",
|
||||||
"forceConsistentCasingInFileNames": true,
|
"resolveJsonModule": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"isolatedModules": true,
|
||||||
"module": "esnext",
|
"noEmit": true,
|
||||||
"moduleResolution": "node",
|
"jsx": "react-jsx"
|
||||||
"resolveJsonModule": true,
|
},
|
||||||
"isolatedModules": true,
|
"include": ["src"]
|
||||||
"noEmit": true,
|
|
||||||
"jsx": "react-jsx"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7358,6 +7358,11 @@ prelude-ls@~1.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
||||||
|
|
||||||
|
prettier@^2.7.1:
|
||||||
|
version "2.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
|
||||||
|
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
|
||||||
|
|
||||||
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
|
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
|
||||||
version "5.6.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
||||||
|
|||||||
Reference in New Issue
Block a user