mirror of
https://github.com/IgnatZakalinsky/home-works.git
synced 2026-01-07 20:42:06 +00:00
hw4
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
.App {
|
||||
|
||||
}
|
||||
|
||||
.hw {
|
||||
|
||||
}
|
||||
|
||||
.hwTitle {
|
||||
|
||||
}
|
||||
@@ -3,19 +3,21 @@ import s from './App.module.css'
|
||||
import HW1 from '../s2-homeworks/hw01/HW1'
|
||||
import HW2 from '../s2-homeworks/hw02/HW2'
|
||||
import HW3 from '../s2-homeworks/hw03/HW3'
|
||||
import HW4 from '../s2-homeworks/hw04/HW4'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div className={s.App}>
|
||||
<div>react homeworks:</div>
|
||||
<HW1/>
|
||||
<HW2/>
|
||||
<HW3/>
|
||||
{/*<HW4/>*/}
|
||||
{/*<HW5/>*/}
|
||||
return (
|
||||
<div className={s.App}>
|
||||
<div>react homeworks:</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
<HW1/>
|
||||
<HW2/>
|
||||
<HW3/>
|
||||
<HW4/>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -2,6 +2,7 @@ import React from 'react'
|
||||
import Message from './Message'
|
||||
import MessageSender from './MessageSender'
|
||||
import s from './Message.module.css'
|
||||
import s2 from '../../s1-main/App.module.css'
|
||||
import FriendMessage from './FriendMessage'
|
||||
|
||||
// нужно создать правильный тип вместо any
|
||||
@@ -34,11 +35,11 @@ export const friendMessage0: MessageType = {
|
||||
|
||||
const HW1 = () => {
|
||||
return (
|
||||
<div id={'hw1'} className={s.hw1}>
|
||||
<div id={'hw1'} className={s2.hw}>
|
||||
<hr/>
|
||||
{/*можно убрать этот тег*/}
|
||||
|
||||
<div className={s.hwTitle}>homeworks 1</div>
|
||||
<div className={s2.hwTitle}>homeworks 1</div>
|
||||
|
||||
{/*проверка отображения (не менять)*/}
|
||||
<Message message={message0}/>
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
.hw1 {
|
||||
|
||||
}
|
||||
|
||||
.hwTitle {
|
||||
|
||||
}
|
||||
|
||||
.message {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
.hw2 {
|
||||
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 10px;
|
||||
width: 60px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {useState} from 'react'
|
||||
import Affairs from './Affairs'
|
||||
import s from './Affairs.module.css'
|
||||
import s2 from '../hw01/Message.module.css'
|
||||
import s2 from '../../s1-main/App.module.css'
|
||||
|
||||
// types
|
||||
export type AffairPriorityType = any // 'high' | 'low' | 'middle' // need to fix any
|
||||
@@ -44,7 +44,7 @@ function HW2() {
|
||||
const deleteAffairCallback = (_id: any) => setAffairs(deleteAffair(affairs, _id)) // need to fix any // number
|
||||
|
||||
return (
|
||||
<div id={'hw2'} className={s.hw2}>
|
||||
<div id={'hw2'} className={s2.hw}>
|
||||
<hr/>
|
||||
{/*можно убрать этот тег*/}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, {useState} from 'react'
|
||||
import {v1} from 'uuid'
|
||||
import s from './Greeting.module.css'
|
||||
import s2 from '../../s1-main/App.module.css'
|
||||
import GreetingContainer from './GreetingContainer'
|
||||
|
||||
// types
|
||||
@@ -9,7 +10,7 @@ export type UserType = {
|
||||
name: string // need to fix any
|
||||
}
|
||||
|
||||
const HW1 = () => {
|
||||
const HW3 = () => {
|
||||
const [users, setUsers] = useState<UserType[]>([]) // need to fix any
|
||||
|
||||
const addUserCallback = (name: string) => { // need to fix any
|
||||
@@ -21,10 +22,12 @@ const HW1 = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div id={'hw3'} className={s.hw3}>
|
||||
<div id={'hw3'} className={s2.hw}>
|
||||
<hr/>
|
||||
{/*можно убрать этот тег*/}
|
||||
|
||||
<div className={s2.hwTitle}>homeworks 3</div>
|
||||
|
||||
{/*для автоматической проверки дз (не менять)*/}
|
||||
<GreetingContainer users={users} addUserCallback={addUserCallback}/>
|
||||
|
||||
@@ -36,4 +39,4 @@ const HW1 = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default HW1
|
||||
export default HW3
|
||||
|
||||
25
src/s2-homeworks/hw04/HW4.tsx
Normal file
25
src/s2-homeworks/hw04/HW4.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react'
|
||||
import s2 from '../../s1-main/App.module.css'
|
||||
import Stand from './Stand'
|
||||
|
||||
const HW4 = () => {
|
||||
return (
|
||||
<div id={'hw4'} className={s2.hw}>
|
||||
<hr/>
|
||||
{/*можно убрать этот тег*/}
|
||||
|
||||
<div className={s2.hwTitle}>homeworks 4</div>
|
||||
|
||||
{/*проверка отображения*/}
|
||||
демострация возможностей компонент:
|
||||
<Stand/>
|
||||
|
||||
<hr/>
|
||||
{/*можно убрать этот тег*/}
|
||||
<hr/>
|
||||
{/*можно убрать этот тег*/}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HW4
|
||||
16
src/s2-homeworks/hw04/Stand.module.css
Normal file
16
src/s2-homeworks/hw04/Stand.module.css
Normal file
@@ -0,0 +1,16 @@
|
||||
.stand {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
|
||||
}
|
||||
|
||||
.buttons {
|
||||
|
||||
}
|
||||
|
||||
.checkboxes {
|
||||
|
||||
}
|
||||
79
src/s2-homeworks/hw04/Stand.tsx
Normal file
79
src/s2-homeworks/hw04/Stand.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, {useState} from 'react'
|
||||
import s from './Stand.module.css'
|
||||
import SuperInputText from './common/c1-SuperInputText/SuperInputText'
|
||||
import SuperCheckbox from './common/c3-SuperCheckbox/SuperCheckbox'
|
||||
import SuperButton from "./common/c2-SuperButton/SuperButton";
|
||||
|
||||
const Stand = () => {
|
||||
const [stateForAllInputs, setValue] = useState('')
|
||||
const [error, setError] = useState<undefined | string>(undefined)
|
||||
|
||||
const [stateForAllCheckboxes, setChecked] = useState(false)
|
||||
|
||||
return (
|
||||
<div className={s.stand}>
|
||||
<div className={s.inputs}>
|
||||
инпут с ошибкой:
|
||||
<div>
|
||||
<SuperInputText
|
||||
id={'super-input-with-error'}
|
||||
value={stateForAllInputs}
|
||||
onChangeText={setValue}
|
||||
error={error}
|
||||
onEnter={() => {
|
||||
setError(stateForAllInputs.trim() ? undefined : 'some error')
|
||||
setValue('')
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
совместим со старым кодом
|
||||
<div>
|
||||
<SuperInputText
|
||||
id={'super-input-like-old'}
|
||||
value={stateForAllInputs}
|
||||
onChange={e => setValue(e.currentTarget.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={s.buttons}>
|
||||
обычная кнопка:
|
||||
<div>
|
||||
<SuperButton id={'super-button-default'}>default</SuperButton>
|
||||
</div>
|
||||
красная кнопка:
|
||||
<div>
|
||||
<SuperButton id={'super-button-red'} xType={'red'}>red</SuperButton>
|
||||
</div>
|
||||
задизэйбленная кнопка:
|
||||
<div>
|
||||
<SuperButton id={'super-button-disabled'} xType={'red'} disabled>disabled</SuperButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={s.checkboxes}>
|
||||
чекбокс с текстом:
|
||||
<div>
|
||||
<SuperCheckbox
|
||||
id={'super-checkbox-with-text'}
|
||||
checked={stateForAllCheckboxes}
|
||||
onChangeChecked={setChecked}
|
||||
>
|
||||
some text
|
||||
</SuperCheckbox>
|
||||
</div>
|
||||
совместим со старым кодом
|
||||
<div>
|
||||
<SuperCheckbox
|
||||
id={'super-checkbox-like-old'}
|
||||
checked={stateForAllCheckboxes}
|
||||
onChange={e => setChecked(e.currentTarget.checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Stand
|
||||
@@ -0,0 +1,26 @@
|
||||
.input:focus {
|
||||
outline: none;
|
||||
border: #99ff99 solid 2px;
|
||||
}
|
||||
|
||||
.superInput {
|
||||
margin: 10px;
|
||||
|
||||
background: #003300;
|
||||
color: #99ff99;
|
||||
}
|
||||
|
||||
.errorInput {
|
||||
margin: 10px;
|
||||
|
||||
background: #003300;
|
||||
color: #99ff99;
|
||||
|
||||
border: 2px solid #dd3355;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #dd3355;
|
||||
height: 21px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, {ChangeEvent, DetailedHTMLProps, InputHTMLAttributes, KeyboardEvent, ReactNode} from 'react'
|
||||
import s from './SuperInputText.module.css'
|
||||
|
||||
// тип пропсов обычного инпута
|
||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
||||
|
||||
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
||||
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
||||
type SuperInputTextPropsType = Omit<DefaultInputPropsType, 'type'> & { // и + ещё пропсы которых нет в стандартном инпуте
|
||||
onChangeText?: (value: string) => void
|
||||
onEnter?: () => void
|
||||
error?: ReactNode
|
||||
spanClassName?: string
|
||||
}
|
||||
|
||||
const SuperInputText: React.FC<SuperInputTextPropsType> = (
|
||||
{
|
||||
// type, // достаём и игнорируем чтоб нельзя было задать другой тип инпута
|
||||
onChange, onChangeText,
|
||||
onKeyPress, onEnter,
|
||||
error,
|
||||
className, spanClassName,
|
||||
id,
|
||||
|
||||
...restProps// все остальные пропсы попадут в объект restProps
|
||||
}
|
||||
) => {
|
||||
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
onChange?.(e) // если есть пропс onChange, то передать ему е (поскольку onChange не обязателен)
|
||||
|
||||
onChangeText?.(e.currentTarget.value)
|
||||
}
|
||||
const onKeyPressCallback = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
onKeyPress?.(e)
|
||||
|
||||
onEnter // если есть пропс onEnter
|
||||
&& e.key === 'Enter' // и если нажата кнопка Enter
|
||||
&& onEnter() // то вызвать его
|
||||
}
|
||||
|
||||
const finalSpanClassName = `${s.error} ${spanClassName ? spanClassName : ''}`
|
||||
const finalInputClassName = `${s.input} ${error ? s.errorInput : s.superInput} ${className}` // задача на смешивание классов
|
||||
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
id={id}
|
||||
type={'text'}
|
||||
onChange={onChangeCallback}
|
||||
onKeyPress={onKeyPressCallback}
|
||||
className={finalInputClassName}
|
||||
|
||||
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
||||
/>
|
||||
<span id={id ? id + '-span' : undefined} className={finalSpanClassName}>{error}</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SuperInputText
|
||||
@@ -0,0 +1,88 @@
|
||||
@keyframes blink {
|
||||
0% {
|
||||
left: -130%;
|
||||
}
|
||||
100% {
|
||||
left: 130%;
|
||||
}
|
||||
}
|
||||
|
||||
.default {
|
||||
background: #003300;
|
||||
color: #99ff99;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.red {
|
||||
background: #dd3355;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #005500;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button::after {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
left: -130%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 20%;
|
||||
|
||||
transform: skew(45deg);
|
||||
|
||||
background-color: #ffffff;
|
||||
opacity: 0.7;
|
||||
|
||||
z-index: 14;
|
||||
}
|
||||
|
||||
.button:hover::after {
|
||||
animation: blink 0.35s ease; /*https://html5book.ru/css3-animation/*/
|
||||
}
|
||||
|
||||
.button:hover::before {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
left: -100vw;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
width: 300vw;
|
||||
|
||||
background-color: #ffffff;
|
||||
opacity: 0.2;
|
||||
|
||||
z-index: 7;
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
outline: #99ff99 solid 1px;
|
||||
}
|
||||
|
||||
.button:active {
|
||||
background: #99ff99;
|
||||
color: #003300;
|
||||
}
|
||||
|
||||
.button:disabled {
|
||||
cursor: no-drop;
|
||||
}
|
||||
|
||||
.button:disabled::after {
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.button:disabled::before {
|
||||
z-index: -1;
|
||||
}
|
||||
35
src/s2-homeworks/hw04/common/c2-SuperButton/SuperButton.tsx
Normal file
35
src/s2-homeworks/hw04/common/c2-SuperButton/SuperButton.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React, {ButtonHTMLAttributes, DetailedHTMLProps} from 'react'
|
||||
import s from './SuperButton.module.css'
|
||||
|
||||
// тип пропсов обычной кнопки, children в котором храниться название кнопки там уже описан
|
||||
type DefaultButtonPropsType = DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
|
||||
|
||||
type SuperButtonPropsType = DefaultButtonPropsType & {
|
||||
xType?: string
|
||||
}
|
||||
|
||||
const SuperButton: React.FC<SuperButtonPropsType> = (
|
||||
{
|
||||
xType, className,
|
||||
disabled,
|
||||
...restProps// все остальные пропсы попадут в объект restProps, там же будет children
|
||||
}
|
||||
) => {
|
||||
const finalClassName = `${s.button} ${
|
||||
disabled
|
||||
? s.disabled
|
||||
: xType === 'red'
|
||||
? s.red
|
||||
: s.default
|
||||
} ${className}` // задачка на смешивание классов
|
||||
|
||||
return (
|
||||
<button
|
||||
disabled={disabled}
|
||||
className={finalClassName}
|
||||
{...restProps} // отдаём кнопке остальные пропсы если они есть (children там внутри)
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default SuperButton
|
||||
@@ -0,0 +1,42 @@
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*input[type="checkbox"] - no*/
|
||||
|
||||
.checkbox {
|
||||
appearance: none; /*Свойство appearance изменяет внешний вид элемента интерфейса, при сохранении его функции.
|
||||
Если задать значение none, то чекбокс пропадет, но по нему, тем не менее,
|
||||
можно щелкать и состояние чекбокса будет меняться*/
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
/*background-repeat: no-repeat;*/
|
||||
/*background-position: center center;*/
|
||||
|
||||
/*background-size: 90% 90%;*/
|
||||
/*vertical-align: middle;*/
|
||||
margin-right: 10px;
|
||||
|
||||
background: #335533;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox:checked {
|
||||
appearance: none;
|
||||
|
||||
background-image: url("checked.png");
|
||||
/*background: #99ff99;*/
|
||||
}
|
||||
|
||||
.checkbox:focus {
|
||||
outline: #99ff99 solid 1px;
|
||||
}
|
||||
|
||||
.spanClassName {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, {ChangeEvent, DetailedHTMLProps, InputHTMLAttributes} from 'react'
|
||||
import s from './SuperCheckbox.module.css'
|
||||
|
||||
// тип пропсов обычного инпута
|
||||
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
||||
|
||||
type SuperCheckboxPropsType = Omit<DefaultInputPropsType, 'type'> & {
|
||||
onChangeChecked?: (checked: boolean) => void
|
||||
spanClassName?: string
|
||||
}
|
||||
|
||||
const SuperCheckbox: React.FC<SuperCheckboxPropsType> = (
|
||||
{
|
||||
onChange, onChangeChecked,
|
||||
className, spanClassName,
|
||||
children, // в эту переменную попадёт текст, типизировать не нужно так как он затипизирован в React.FC
|
||||
id,
|
||||
|
||||
...restProps// все остальные пропсы попадут в объект restProps
|
||||
}
|
||||
) => {
|
||||
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => { // задачка на написание онченджа
|
||||
onChange?.(e)
|
||||
|
||||
onChangeChecked?.(e.currentTarget.checked)
|
||||
}
|
||||
|
||||
const finalInputClassName = `${s.checkbox} ${className ? className : ''}`
|
||||
|
||||
return (
|
||||
<label className={s.label}>
|
||||
<input
|
||||
id={id}
|
||||
type={'checkbox'}
|
||||
onChange={onChangeCallback}
|
||||
className={finalInputClassName}
|
||||
|
||||
{...restProps} // отдаём инпуту остальные пропсы если они есть (checked например там внутри)
|
||||
/>
|
||||
{children && <span id={id ? id + '-span' : undefined} className={s.spanClassName}>{children}</span>}
|
||||
</label> // благодаря label нажатие на спан передастся в инпут
|
||||
)
|
||||
}
|
||||
|
||||
export default SuperCheckbox
|
||||
BIN
src/s2-homeworks/hw04/common/c3-SuperCheckbox/checked.png
Normal file
BIN
src/s2-homeworks/hw04/common/c3-SuperCheckbox/checked.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 711 B |
Reference in New Issue
Block a user