Compare commits
5 Commits
8e744cf2dd
...
d7c438715e
Author | SHA1 | Date | |
---|---|---|---|
d7c438715e | |||
5aa97a5255 | |||
f8f6fb991a | |||
ca360b2451 | |||
0a1d4067a8 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -128,4 +128,6 @@ dist
|
|||||||
.yarn/unplugged
|
.yarn/unplugged
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
ngrok.exe
|
1071
package-lock.json
generated
1071
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
src/app.tsx
12
src/app.tsx
@ -1,7 +1,17 @@
|
|||||||
import React from 'react';
|
import React, {useEffect} from 'react';
|
||||||
import Main from './container/main';
|
import Main from './container/main';
|
||||||
|
import useTelegram from './container/hooks/useTelegram';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
const { isScriptLoaded, onClose, onToggleButton, tg, user_id, username } = useTelegram();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isScriptLoaded && tg) {
|
||||||
|
tg.ready(); // Инициализация WebApp после загрузки скрипта
|
||||||
|
console.log('Telegram WebApp готов:', tg);
|
||||||
|
}
|
||||||
|
}, [isScriptLoaded, tg]);
|
||||||
|
|
||||||
return <Main />;
|
return <Main />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,36 +1,61 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
Telegram: {
|
Telegram: {
|
||||||
WebApp: any;
|
WebApp: any;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const useTelegram = () => {
|
|
||||||
|
|
||||||
const tg = window.Telegram.WebApp;
|
|
||||||
const onClose = () => {
|
|
||||||
tg.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onToggleButton = () => {
|
|
||||||
if(tg.MainButton.isVisible) {
|
|
||||||
tg.MainButton.hide();
|
|
||||||
} else {
|
|
||||||
tg.MainButton.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
onClose,
|
|
||||||
onToggleButton,
|
|
||||||
tg,
|
|
||||||
user_id: tg.initDataUnsafe?.user?.id,
|
|
||||||
user: tg.initDataUnsafe?.user,
|
|
||||||
username: tg.initDataUnsafe?.user?.username,
|
|
||||||
queryId: tg.initDataUnsafe?.query_id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useTelegram;
|
const useTelegram = () => {
|
||||||
|
const [isScriptLoaded, setIsScriptLoaded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Проверяем, был ли скрипт уже загружен
|
||||||
|
if (!window.Telegram) {
|
||||||
|
// Если Telegram API еще не доступен, загружаем скрипт
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = 'https://telegram.org/js/telegram-web-app.js';
|
||||||
|
script.async = true;
|
||||||
|
script.onload = () => {
|
||||||
|
setIsScriptLoaded(true); // Скрипт загружен
|
||||||
|
};
|
||||||
|
script.onerror = () => {
|
||||||
|
console.error('Ошибка при загрузке Telegram Web App SDK');
|
||||||
|
};
|
||||||
|
document.body.appendChild(script);
|
||||||
|
} else {
|
||||||
|
// Если Telegram Web App уже доступен, просто обновляем состояние
|
||||||
|
setIsScriptLoaded(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Логика, которая будет выполняться, когда скрипт загружен
|
||||||
|
const tg = window.Telegram?.WebApp;
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
tg?.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onToggleButton = () => {
|
||||||
|
if (tg?.MainButton?.isVisible) {
|
||||||
|
tg.MainButton.hide();
|
||||||
|
} else {
|
||||||
|
tg.MainButton.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isScriptLoaded,
|
||||||
|
onClose,
|
||||||
|
onToggleButton,
|
||||||
|
tg,
|
||||||
|
user_id: tg?.initDataUnsafe?.user?.id,
|
||||||
|
user: tg?.initDataUnsafe?.user,
|
||||||
|
username: tg?.initDataUnsafe?.user?.username,
|
||||||
|
queryId: tg?.initDataUnsafe?.query_id,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTelegram;
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { getNavigationsValue } from '@brojs/cli';
|
|
||||||
|
|
||||||
const navigations: Array<{ name: string; href: string }> = [
|
|
||||||
{
|
|
||||||
name: 'Регистрация',
|
|
||||||
href: getNavigationsValue('sberhubproject.signup')
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const Header = (): React.ReactElement => {
|
|
||||||
return (
|
|
||||||
<header>
|
|
||||||
<ul>
|
|
||||||
{navigations.map((item) => {
|
|
||||||
return (
|
|
||||||
<li key={item.name}>
|
|
||||||
<Link to={item.href}>{item.name}</Link>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
|
@ -0,0 +1,7 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import AppBar from '@mui/material/AppBar';
|
||||||
|
|
||||||
|
export const AppBarStyled = styled(AppBar)`
|
||||||
|
background-color: var(--tg-theme-button-color);
|
||||||
|
|
||||||
|
`;
|
18
src/container/main/components/layout/header/index.tsx
Normal file
18
src/container/main/components/layout/header/index.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Logo from './logo';
|
||||||
|
import { AppBarStyled } from './index.style';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
|
|
||||||
|
const Header = (): React.ReactElement => {
|
||||||
|
return (
|
||||||
|
<header>
|
||||||
|
<AppBarStyled position="static">
|
||||||
|
<Toolbar>
|
||||||
|
<Logo />
|
||||||
|
</Toolbar>
|
||||||
|
</AppBarStyled>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
14
src/container/main/components/layout/header/logo/index.tsx
Normal file
14
src/container/main/components/layout/header/logo/index.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import logoPng from './logo.png';
|
||||||
|
|
||||||
|
const LogoStyled = styled.img`
|
||||||
|
height: 40px;
|
||||||
|
padding: 8px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Logo = () => {
|
||||||
|
return <LogoStyled src={logoPng} alt={'logo'} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
BIN
src/container/main/components/layout/header/logo/logo.png
Normal file
BIN
src/container/main/components/layout/header/logo/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
60
src/container/signup/about/index.style.ts
Normal file
60
src/container/signup/about/index.style.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import TextField from '@mui/material/TextField';
|
||||||
|
|
||||||
|
export const AboutStyled = styled(TextField)`
|
||||||
|
& .MuiInputBase-input {
|
||||||
|
color: var(--tg-theme-text-color,rgba(0, 0, 0, 0.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
& .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-text-color, rgba(0, 0, 0, 0.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
& .Mui-focused .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-label-focus-color, #0066ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
& .MuiOutlinedInput-root {
|
||||||
|
fieldset {
|
||||||
|
border-color: var(--tg-theme-border-color, #cccccc);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover fieldset {
|
||||||
|
border-color: var(--tg-theme-border-hover, #888888);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Mui-focused fieldset {
|
||||||
|
border-color: var(--tg-theme-border-focused, #0066ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
& .MuiInputBase-input {
|
||||||
|
color: var(--tg-theme-text-color-dark, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-label-color-dark, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .Mui-focused .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-label-focus-color-dark, #0066ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .MuiOutlinedInput-root {
|
||||||
|
fieldset {
|
||||||
|
border-color: var(--tg-theme-border-color-dark, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover fieldset {
|
||||||
|
border-color: var(--tg-theme-border-hover-dark, #777777);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Mui-focused fieldset {
|
||||||
|
border-color: var(--tg-theme-border-focused-dark, #0066ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
19
src/container/signup/about/index.tsx
Normal file
19
src/container/signup/about/index.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { AboutStyled } from './index.style';
|
||||||
|
|
||||||
|
const About = ({rows, id, label, name, placeholder="Введите текст...", className = null}): React.ReactElement => {
|
||||||
|
return (
|
||||||
|
<AboutStyled
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
rows={rows}
|
||||||
|
id={id}
|
||||||
|
label={label}
|
||||||
|
name={name}
|
||||||
|
placeholder={placeholder}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default About;
|
7
src/container/signup/button/index.style.ts
Normal file
7
src/container/signup/button/index.style.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
|
||||||
|
export const RegisterButtonStyled = styled(Button)`
|
||||||
|
background-color: var(--tg-theme-button-color);
|
||||||
|
color: var(--tg-theme-button-text-color);
|
||||||
|
`;
|
19
src/container/signup/button/index.tsx
Normal file
19
src/container/signup/button/index.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { RegisterButtonStyled } from './index.style';
|
||||||
|
|
||||||
|
const RegisterButton = ({children, id = null, name = null, className = null}): React.ReactElement => {
|
||||||
|
return (
|
||||||
|
<RegisterButtonStyled
|
||||||
|
id={id}
|
||||||
|
name={name}
|
||||||
|
className={className}
|
||||||
|
type="submit"
|
||||||
|
fullWidth
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</RegisterButtonStyled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RegisterButton;
|
@ -1,7 +1,3 @@
|
|||||||
.upload-input {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.basic-multi-select {
|
.basic-multi-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
9
src/container/signup/index.style.ts
Normal file
9
src/container/signup/index.style.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { Grid2 } from '@mui/material';
|
||||||
|
|
||||||
|
export const GridChildrenStyle = styled(Grid2)`
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
@ -1,33 +1,24 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Avatar from '@mui/material/Avatar';
|
import {Button, Grid2, Box, Container
|
||||||
import Button from '@mui/material/Button';
|
} from '@mui/material';
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
import Title from './title';
|
||||||
import TextField from '@mui/material/TextField';
|
import Name from './name';
|
||||||
import Grid from '@mui/material/Grid';
|
import About from './about';
|
||||||
import Box from '@mui/material/Box';
|
import Photo from './photo';
|
||||||
import Typography from '@mui/material/Typography';
|
import Interests from './interests';
|
||||||
import Container from '@mui/material/Container';
|
import RegisterButton from './button';
|
||||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import student_icon from '../../assets/images/student-icon.png';
|
import student_icon from './student-icon.png';
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
//import useTelegram from "../hooks/useTelegram";
|
//import useTelegram from "../hooks/useTelegram";
|
||||||
import Select from 'react-select';
|
import Select from 'react-select';
|
||||||
import makeAnimated from 'react-select/animated';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useConstant } from '../Constant';
|
import { useConstant } from '../Constant';
|
||||||
|
import { GridChildrenStyle } from './index.style';
|
||||||
const animatedComponents = makeAnimated();
|
|
||||||
const theme = createTheme();
|
|
||||||
|
|
||||||
|
|
||||||
const SingUpPage = (): React.ReactElement => {
|
const SingUpPage = (): React.ReactElement => {
|
||||||
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
|
|
||||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
|
||||||
const handleChange = (selectedOption) => {
|
|
||||||
setSelectedOption(selectedOption);
|
|
||||||
};
|
|
||||||
const { interests } = useConstant();
|
const { interests } = useConstant();
|
||||||
|
|
||||||
//const { user_id, username, onClose } = useTelegram();
|
//const { user_id, username, onClose } = useTelegram();
|
||||||
/*
|
/*
|
||||||
const handleSubmit = async (event) => {
|
const handleSubmit = async (event) => {
|
||||||
@ -48,123 +39,66 @@ const SingUpPage = (): React.ReactElement => {
|
|||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
const handleAvatarClick = () => {
|
|
||||||
const fileInput = document.getElementById('avatar-input') as HTMLInputElement;
|
|
||||||
fileInput.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAvatarChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = () => {
|
|
||||||
setAvatarUrl(reader.result as string);
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
|
||||||
<Container component="main" maxWidth="xs">
|
<Container component="main" maxWidth="xs">
|
||||||
<CssBaseline />
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: 8,
|
marginTop: 4,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography component="h1" variant="h5">
|
<Title>Регистрация</Title>
|
||||||
Регистрация
|
|
||||||
</Typography>
|
|
||||||
<Box component="form" noValidate sx={{ mt: 3 }}>
|
<Box component="form" noValidate sx={{ mt: 3 }}>
|
||||||
<Grid container spacing={2}>
|
<Grid2 container>
|
||||||
<Grid item xs={12} sm={6}>
|
<GridChildrenStyle size={6}>
|
||||||
<TextField
|
<Name
|
||||||
required
|
id="lastname"
|
||||||
fullWidth
|
label="Фамилия"
|
||||||
id="lname"
|
name="lastname"
|
||||||
label="Фамилия"
|
|
||||||
name="lname"
|
|
||||||
autoComplete="family-name"
|
autoComplete="family-name"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</GridChildrenStyle>
|
||||||
<Grid item xs={12} sm={6}>
|
<GridChildrenStyle size={6}>
|
||||||
<TextField
|
<Name
|
||||||
autoComplete="given-name"
|
id="firstname"
|
||||||
name="fname"
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
id="fname"
|
|
||||||
label="Имя"
|
label="Имя"
|
||||||
autoFocus
|
name="firstname"
|
||||||
|
autoComplete="given-name"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</GridChildrenStyle>
|
||||||
<Grid item xs={12}>
|
<GridChildrenStyle size={12}>
|
||||||
<TextField
|
<About
|
||||||
fullWidth
|
|
||||||
multiline
|
|
||||||
rows={3}
|
rows={3}
|
||||||
id="about"
|
id="about"
|
||||||
label="Обо мне"
|
label="Обо мне"
|
||||||
name="about"
|
name="about"
|
||||||
variant="outlined"
|
|
||||||
placeholder="Напишите о себе"
|
placeholder="Напишите о себе"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</GridChildrenStyle>
|
||||||
<Grid
|
<GridChildrenStyle size={12}>
|
||||||
container
|
<Photo
|
||||||
spacing={0}
|
id="photo"
|
||||||
direction="column"
|
name="photo"
|
||||||
alignItems="center"
|
|
||||||
justifyContent="center"
|
|
||||||
sx={{ paddingTop: 7, paddingLeft: 3 }}
|
|
||||||
>
|
|
||||||
<Avatar src={avatarUrl || student_icon} onClick={handleAvatarClick} sx={{ width: 200, height: 200 }}/>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
name="image"
|
|
||||||
accept="image/*"
|
|
||||||
onChange={handleAvatarChange}
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
id="avatar-input"
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</GridChildrenStyle>
|
||||||
<Grid
|
<GridChildrenStyle size={12}>
|
||||||
container
|
<Interests
|
||||||
spacing={0}
|
|
||||||
direction="column"
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="center"
|
|
||||||
sx={{ paddingTop: 7, ml: 3 }}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
onChange={handleChange}
|
|
||||||
closeMenuOnSelect={false}
|
|
||||||
components={animatedComponents}
|
|
||||||
isMulti
|
|
||||||
options={interests}
|
options={interests}
|
||||||
className="basic-multi-select"
|
placeholder='Выберите интересы...'
|
||||||
classNamePrefix="select"
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</GridChildrenStyle>
|
||||||
<Button
|
<GridChildrenStyle size={12}>
|
||||||
type="submit"
|
<RegisterButton>
|
||||||
fullWidth
|
|
||||||
variant="contained"
|
|
||||||
sx={{ mt: 3, mb: 2, ml: 3 }}
|
|
||||||
>
|
|
||||||
Регистрация
|
Регистрация
|
||||||
</Button>
|
</RegisterButton>
|
||||||
</Grid>
|
</GridChildrenStyle>
|
||||||
|
</Grid2>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
</ThemeProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
68
src/container/signup/interests/index.style.ts
Normal file
68
src/container/signup/interests/index.style.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import Select from 'react-select';
|
||||||
|
|
||||||
|
export const InterestsStyled = styled(Select)`
|
||||||
|
.select__control {
|
||||||
|
background-color: var(--tg-theme-bg-color, #ffffff);
|
||||||
|
border: 1px solid var(--tg-theme-border-color, #cccccc);
|
||||||
|
color: var(--tg-theme-text-color, #000000);
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--tg-theme-border-hover, #888888);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select__menu {
|
||||||
|
background-color: var(--tg-theme-bg-color, #ffffff);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select__option {
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--tg-theme-text-color, #000000);
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--tg-theme-hover-color, #f2f2f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.select__option--is-selected {
|
||||||
|
background-color: var(--tg-theme-button-color);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.select__option--is-focused {
|
||||||
|
background-color: var(--tg-theme-hover-color, #e0e0e0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select__placeholder {
|
||||||
|
color: var(--tg-theme-placeholder-color, #888888);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select__multi-value {
|
||||||
|
background-color: var(--tg-theme-button-color);
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.select__multi-value__label {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select__multi-value__remove {
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
27
src/container/signup/interests/index.tsx
Normal file
27
src/container/signup/interests/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { InterestsStyled } from './index.style';
|
||||||
|
|
||||||
|
const Interests = ({options, placeholder = "Выберите..."}): React.ReactElement => {
|
||||||
|
|
||||||
|
const [selectedInterests, setSelectedInterests] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleChange = (selectedInterests) => {
|
||||||
|
setSelectedInterests(selectedInterests);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InterestsStyled
|
||||||
|
onChange={handleChange}
|
||||||
|
closeMenuOnSelect={false}
|
||||||
|
isMulti
|
||||||
|
options={options}
|
||||||
|
className="basic-multi-select"
|
||||||
|
classNamePrefix="select"
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={selectedInterests}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Interests;
|
60
src/container/signup/name/index.style.ts
Normal file
60
src/container/signup/name/index.style.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import TextField from '@mui/material/TextField';
|
||||||
|
|
||||||
|
export const TextFieldStyled = styled(TextField)`
|
||||||
|
& .MuiInputBase-input {
|
||||||
|
color: var(--tg-theme-text-color,rgba(0, 0, 0, 0.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
& .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-text-color, rgba(0, 0, 0, 0.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
& .Mui-focused .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-label-focus-color, #0066ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
& .MuiOutlinedInput-root {
|
||||||
|
fieldset {
|
||||||
|
border-color: var(--tg-theme-border-color, #cccccc);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover fieldset {
|
||||||
|
border-color: var(--tg-theme-border-hover, #888888);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Mui-focused fieldset {
|
||||||
|
border-color: var(--tg-theme-border-focused, #0066ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
& .MuiInputBase-input {
|
||||||
|
color: var(--tg-theme-text-color-dark, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-label-color-dark, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .Mui-focused .MuiFormLabel-root {
|
||||||
|
color: var(--tg-theme-label-focus-color-dark, #0066ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .MuiOutlinedInput-root {
|
||||||
|
fieldset {
|
||||||
|
border-color: var(--tg-theme-border-color-dark, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover fieldset {
|
||||||
|
border-color: var(--tg-theme-border-hover-dark, #777777);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Mui-focused fieldset {
|
||||||
|
border-color: var(--tg-theme-border-focused-dark, #0066ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
18
src/container/signup/name/index.tsx
Normal file
18
src/container/signup/name/index.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { TextFieldStyled } from './index.style';
|
||||||
|
|
||||||
|
const Name = ({id, label, name, autoComplete, className = null}): React.ReactElement => {
|
||||||
|
return (
|
||||||
|
<TextFieldStyled
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
id={id}
|
||||||
|
label={label}
|
||||||
|
name={name}
|
||||||
|
autoComplete={autoComplete}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Name;
|
17
src/container/signup/photo/index.style.ts
Normal file
17
src/container/signup/photo/index.style.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import Avatar from "@mui/material/Avatar";
|
||||||
|
|
||||||
|
export const PhotoStyled = styled.div<{ id: string, name: string, value: string | null }>`
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const AvatarStyled = styled(Avatar)`
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const InputStyled = styled.input`
|
||||||
|
display: none;
|
||||||
|
`;
|
50
src/container/signup/photo/index.tsx
Normal file
50
src/container/signup/photo/index.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { AvatarStyled, PhotoStyled, InputStyled } from './index.style';
|
||||||
|
|
||||||
|
const Photo = ({ id, name, defaultPhoto = null}): React.ReactElement => {
|
||||||
|
const [photo, setPhoto] = useState(defaultPhoto);
|
||||||
|
|
||||||
|
const handleFileChange = (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const newPhoto = e.target.result;
|
||||||
|
setPhoto(newPhoto);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAvatarClick = () => {
|
||||||
|
const fileInput = document.getElementById('fileInput') as HTMLInputElement;
|
||||||
|
fileInput.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PhotoStyled
|
||||||
|
id = {id}
|
||||||
|
name = {name}
|
||||||
|
value = {photo}
|
||||||
|
>
|
||||||
|
<AvatarStyled
|
||||||
|
src={photo}
|
||||||
|
alt="Выберите фотографию"
|
||||||
|
onClick={handleAvatarClick}
|
||||||
|
/>
|
||||||
|
<InputStyled
|
||||||
|
id="fileInput"
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
onChange={handleFileChange}
|
||||||
|
/>
|
||||||
|
</PhotoStyled>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Photo;
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
6
src/container/signup/title/index.style.ts
Normal file
6
src/container/signup/title/index.style.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const TitleStyled = styled.h1`
|
||||||
|
font-size: 28px;
|
||||||
|
color: var(--tg-theme-text-color);
|
||||||
|
`;
|
12
src/container/signup/title/index.tsx
Normal file
12
src/container/signup/title/index.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import * as React from 'react';;
|
||||||
|
import { TitleStyled } from './index.style';
|
||||||
|
|
||||||
|
const Title = ({children}): React.ReactElement => {
|
||||||
|
return (
|
||||||
|
<TitleStyled>
|
||||||
|
{children}
|
||||||
|
</TitleStyled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Title;
|
@ -12,7 +12,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"typeRoots": ["node_modules/@types", "src/typings"],
|
"typeRoots": ["node_modules/@types", "src/@types"],
|
||||||
"types" : ["webpack-env", "node"],
|
"types" : ["webpack-env", "node"],
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user