This commit is contained in:
neko
2022-06-07 20:27:43 +03:00
parent 0e359b05e7
commit d7e7ef9471
17 changed files with 447 additions and 29 deletions

View File

@@ -1,3 +1,11 @@
.App {
}
.hw {
}
.hwTitle {
}

View File

@@ -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

View File

@@ -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}/>

View File

@@ -1,11 +1,3 @@
.hw1 {
}
.hwTitle {
}
.message {
display: flex;
justify-content: right;

View File

@@ -1,7 +1,3 @@
.hw2 {
}
.button {
margin: 10px;
width: 60px;

View File

@@ -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/>
{/*можно убрать этот тег*/}

View File

@@ -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

View 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

View File

@@ -0,0 +1,16 @@
.stand {
display: flex;
justify-content: space-around;
}
.inputs {
}
.buttons {
}
.checkboxes {
}

View 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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View 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

View File

@@ -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 {
}

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B