crap
This commit is contained in:
24
src/components/Dnd/Board/Board.module.css
Normal file
24
src/components/Dnd/Board/Board.module.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/*background-color: green;*/
|
||||
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
/*border: solid var(--item-border-size) var(--mantine-color-default-border);*/
|
||||
/*border-radius: var(--item-border-radius);*/
|
||||
}
|
||||
|
||||
.items-list {
|
||||
gap: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/*background-color: red;*/
|
||||
height: 100%;
|
||||
}
|
||||
53
src/components/Dnd/Board/Board.tsx
Normal file
53
src/components/Dnd/Board/Board.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import {FC} from "react";
|
||||
import styles from './Board.module.css';
|
||||
import {Divider, Text, Title} from '@mantine/core';
|
||||
import {Draggable, Droppable} from "@hello-pangea/dnd";
|
||||
import CreateLeadButton from "../CreateLeadButton/CreateLeadButton.tsx";
|
||||
|
||||
type Props = {
|
||||
droppableId: string;
|
||||
title: string;
|
||||
withCreateButton?: boolean;
|
||||
}
|
||||
|
||||
export const Board: FC<Props> = ({droppableId, title, withCreateButton = false}) => {
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles["container"]}>
|
||||
<div className={styles["header"]}>
|
||||
<Title size={"h4"}>{title}</Title>
|
||||
<Text>12 сделок: 500р</Text>
|
||||
<Divider size={"xl"} my={10} color={"blue"}/>
|
||||
</div>
|
||||
<Droppable droppableId={droppableId}>
|
||||
{(provided, snapshot) => (
|
||||
<div ref={provided.innerRef} className={styles["items-list"]}>
|
||||
{withCreateButton &&
|
||||
<CreateLeadButton
|
||||
|
||||
onClick={() => {
|
||||
}}
|
||||
/>}
|
||||
<Draggable draggableId={droppableId + '1'} index={1}>
|
||||
{(provided, snapshot) => (
|
||||
<div {...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
ref={provided.innerRef}
|
||||
>
|
||||
</div>
|
||||
|
||||
)}
|
||||
</Draggable>
|
||||
|
||||
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Board;
|
||||
@@ -0,0 +1,19 @@
|
||||
.container {
|
||||
/*background-color: red;*/
|
||||
min-height: 5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
border: dashed var(--item-border-size) var(--mantine-color-default-border);
|
||||
border-radius: var(--item-border-radius);
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
background-color: light-dark(var(--mantine-color-default-hover), var(--mantine-color-gray-filled-hover));
|
||||
|
||||
}
|
||||
60
src/components/Dnd/CreateLeadButton/CreateLeadButton.tsx
Normal file
60
src/components/Dnd/CreateLeadButton/CreateLeadButton.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React, {FC, useState} from "react";
|
||||
|
||||
import styles from './CreateLeadButton.module.css';
|
||||
import {Button, Center, rem, Text, TextInput, Transition} from '@mantine/core';
|
||||
|
||||
type Props = {
|
||||
onClick: () => void;
|
||||
}
|
||||
const CreateLeadButton: FC<Props> = ({onClick}) => {
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [showButton, setShowButton] = useState(true);
|
||||
console.log(`isCreating: ${isCreating}`)
|
||||
console.log(`showButton: ${showButton}`)
|
||||
return (
|
||||
<div className={styles['container']}
|
||||
onClick={() => {
|
||||
if (isCreating) return;
|
||||
setIsCreating(prevState => !prevState)
|
||||
setShowButton(false);
|
||||
}}
|
||||
>
|
||||
|
||||
{(!isCreating && showButton) &&
|
||||
<Text>Быстрое добавление</Text>
|
||||
}
|
||||
<Transition
|
||||
mounted={isCreating}
|
||||
transition={'scale-y'}
|
||||
duration={300}
|
||||
// onExited={()=>setShowButton(true)}
|
||||
keepMounted
|
||||
>
|
||||
{(styles) => <div style={{...styles, width: '100%'}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
gap: rem(10),
|
||||
padding: rem(10)
|
||||
}}>
|
||||
<div style={{display: "flex", flexDirection: "column", width: '100%'}}>
|
||||
<TextInput placeholder={'Название'} w={'100%'}/>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{display: "flex", flexDirection: "column", width: '100%'}}>
|
||||
<TextInput placeholder={'Компания: название'} w={'100%'}/>
|
||||
<TextInput placeholder={'Компания: адрес'} w={'100%'}/>
|
||||
</div>
|
||||
<div style={{gap:rem(10), display:"flex"}}>
|
||||
<Button>Добавить</Button>
|
||||
<Button variant={'outline'} onClick={()=>setIsCreating(false)}>Отменить</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>}
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default CreateLeadButton;
|
||||
19
src/components/DndList.module.css
Normal file
19
src/components/DndList.module.css
Normal file
@@ -0,0 +1,19 @@
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
border: rem(1px) solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
|
||||
padding: var(--mantine-spacing-sm) var(--mantine-spacing-xl);
|
||||
background-color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-5));
|
||||
margin-bottom: var(--mantine-spacing-sm);
|
||||
}
|
||||
|
||||
.itemDragging {
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
.symbol {
|
||||
font-size: rem(30px);
|
||||
font-weight: 700;
|
||||
width: rem(60px);
|
||||
}
|
||||
34
src/components/Navbar/LinksGroup/LinksGroup.module.css
Normal file
34
src/components/Navbar/LinksGroup/LinksGroup.module.css
Normal file
@@ -0,0 +1,34 @@
|
||||
.control {
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: var(--mantine-spacing-xs) var(--mantine-spacing-md);
|
||||
color: var(--mantine-color-text);
|
||||
font-size: var(--mantine-font-size-sm);
|
||||
|
||||
@mixin hover {
|
||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7));
|
||||
color: light-dark(var(--mantine-color-black), var(--mantine-color-dark-0));
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: var(--mantine-spacing-xs) var(--mantine-spacing-md);
|
||||
padding-left: var(--mantine-spacing-md);
|
||||
margin-left: var(--mantine-spacing-xl);
|
||||
font-size: var(--mantine-font-size-sm);
|
||||
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
|
||||
border-left: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
|
||||
|
||||
@mixin hover {
|
||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7));
|
||||
color: light-dark(var(--mantine-color-black), var(--mantine-color-dark-0));
|
||||
}
|
||||
}
|
||||
|
||||
.chevron {
|
||||
transition: transform 200ms ease;
|
||||
}
|
||||
73
src/components/Navbar/LinksGroup/LinksGroup.tsx
Normal file
73
src/components/Navbar/LinksGroup/LinksGroup.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import {useState} from 'react';
|
||||
import {Box, Collapse, Group, rem, ThemeIcon, UnstyledButton} from '@mantine/core';
|
||||
import {IconCalendarStats, IconChevronRight} from '@tabler/icons-react';
|
||||
import classes from './LinksGroup.module.css';
|
||||
import {Link} from "@tanstack/react-router";
|
||||
|
||||
interface LinksGroupProps {
|
||||
icon: React.FC<any>;
|
||||
label: string;
|
||||
initiallyOpened?: boolean;
|
||||
links?: { label: string; link: string }[];
|
||||
}
|
||||
|
||||
export function LinksGroup({icon: Icon, label, initiallyOpened, links}: LinksGroupProps) {
|
||||
const hasLinks = Array.isArray(links);
|
||||
const [opened, setOpened] = useState(initiallyOpened || false);
|
||||
const items = (hasLinks ? links : []).map((link) => (
|
||||
<Link to={link.link}
|
||||
className={classes.link}
|
||||
key={link.label}
|
||||
|
||||
>
|
||||
|
||||
{link.label}
|
||||
</Link>
|
||||
|
||||
));
|
||||
|
||||
return (
|
||||
<>
|
||||
<UnstyledButton onClick={() => setOpened((o) => !o)} className={classes.control}>
|
||||
<Group justify="space-between" gap={0}>
|
||||
<Box style={{display: 'flex', alignItems: 'center'}}>
|
||||
<ThemeIcon variant="light" size={30}>
|
||||
<Icon style={{width: rem(18), height: rem(18)}}/>
|
||||
</ThemeIcon>
|
||||
<Box ml="md">{label}</Box>
|
||||
</Box>
|
||||
{hasLinks && (
|
||||
<IconChevronRight
|
||||
className={classes.chevron}
|
||||
stroke={1.5}
|
||||
style={{
|
||||
width: rem(16),
|
||||
height: rem(16),
|
||||
transform: opened ? 'rotate(-90deg)' : 'none',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
{hasLinks ? <Collapse in={opened}>{items}</Collapse> : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const mockdata = {
|
||||
label: 'Releases',
|
||||
icon: IconCalendarStats,
|
||||
links: [
|
||||
{label: 'Upcoming releases', link: '/'},
|
||||
{label: 'Previous releases', link: '/'},
|
||||
{label: 'Releases schedule', link: '/'},
|
||||
],
|
||||
};
|
||||
|
||||
export function NavbarLinksGroup() {
|
||||
return (
|
||||
<Box mih={220} p="md">
|
||||
<LinksGroup {...mockdata} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
37
src/components/Navbar/Logo.tsx
Normal file
37
src/components/Navbar/Logo.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
export function Logo(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg {...props} version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1024.000000 1024.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)"
|
||||
fill="#2a75ec" stroke="none">
|
||||
<path d="M2600 7290 l0 -760 690 0 690 0 0 196 0 195 728 -4 c613 -3 743 -7
|
||||
831 -20 57 -10 106 -15 108 -13 7 7 341 -80 358 -93 8 -7 79 -34 95 -36 28 -4
|
||||
293 -151 298 -166 2 -5 8 -9 13 -9 9 0 75 -51 177 -138 44 -38 120 -123 218
|
||||
-245 73 -91 215 -390 230 -484 3 -21 8 -42 11 -46 20 -33 46 -190 58 -355 12
|
||||
-165 12 -219 0 -385 -12 -164 -38 -321 -58 -354 -3 -4 -8 -25 -11 -46 -15 -95
|
||||
-157 -394 -230 -484 -96 -119 -128 -156 -176 -203 -65 -65 -206 -180 -219
|
||||
-180 -5 0 -11 -4 -13 -9 -7 -20 -253 -151 -333 -177 -27 -9 -55 -20 -60 -25
|
||||
-6 -4 -45 -17 -88 -28 -42 -12 -111 -30 -152 -41 -42 -11 -88 -21 -103 -22
|
||||
-15 0 -67 -8 -117 -16 -72 -12 -238 -16 -827 -19 l-738 -4 0 245 0 246 -687
|
||||
-2 -688 -3 -3 -808 -2 -807 1487 0 c1611 0 1542 -2 1908 56 88 14 207 37 265
|
||||
51 108 27 369 106 405 123 11 5 52 21 90 36 168 65 524 255 588 314 11 11 27
|
||||
20 34 20 7 0 13 3 13 8 0 4 39 37 88 72 160 119 365 330 507 525 58 79 122
|
||||
173 132 195 4 8 22 39 41 68 18 29 35 61 37 70 2 10 17 41 34 70 17 29 31 57
|
||||
31 63 0 5 11 32 25 59 28 55 78 194 102 280 8 30 26 94 39 141 13 48 28 120
|
||||
34 160 5 41 17 121 27 179 26 154 25 728 -1 880 -9 58 -22 137 -27 175 -5 39
|
||||
-20 111 -33 160 -13 50 -30 113 -37 140 -7 28 -23 74 -36 104 -12 29 -23 60
|
||||
-23 67 0 8 -16 48 -35 90 -19 41 -35 79 -35 84 0 5 -14 33 -31 62 -17 29 -33
|
||||
61 -35 71 -2 11 -10 27 -18 36 -7 9 -24 36 -36 60 -12 24 -26 49 -32 55 -8 9
|
||||
-40 57 -103 155 -5 9 -15 20 -21 26 -6 5 -40 48 -76 95 -127 165 -291 325
|
||||
-473 459 -38 29 -83 62 -98 74 -16 12 -40 29 -55 37 -15 8 -67 39 -115 69 -99
|
||||
59 -339 177 -443 216 -245 93 -524 167 -774 205 -335 51 -306 50 -1877 50
|
||||
l-1473 0 0 -760z"/>
|
||||
<path d="M1730 5175 l0 -1095 1580 0 1580 0 0 1095 0 1095 -1580 0 -1580 0 0
|
||||
-1095z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
)
|
||||
}
|
||||
36
src/components/Navbar/Navbar.module.css
Normal file
36
src/components/Navbar/Navbar.module.css
Normal file
@@ -0,0 +1,36 @@
|
||||
.navbar {
|
||||
width: rem(80px);
|
||||
height: 100%;
|
||||
padding: var(--mantine-spacing-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
|
||||
}
|
||||
|
||||
.navbarMain {
|
||||
flex: 1;
|
||||
margin-top: rem(50px);
|
||||
}
|
||||
|
||||
.link {
|
||||
width: rem(50px);
|
||||
height: rem(50px);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
|
||||
|
||||
&:hover {
|
||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-5));
|
||||
}
|
||||
|
||||
&[data-active] {
|
||||
&,
|
||||
&:hover {
|
||||
background-color: var(--mantine-color-blue-light);
|
||||
color: var(--mantine-color-blue-light-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
89
src/components/Navbar/Navbar.tsx
Normal file
89
src/components/Navbar/Navbar.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import {Center, Image, rem, Stack, Tooltip, UnstyledButton, useMantineColorScheme} from '@mantine/core';
|
||||
import {IconCash, IconHome2, IconLogout, IconMoon, IconSun,} from '@tabler/icons-react';
|
||||
import classes from './Navbar.module.css';
|
||||
import {useAppDispatch} from "../../redux/store.ts";
|
||||
import {logout} from "../../features/authSlice.ts";
|
||||
import {useNavigate, useRouterState} from "@tanstack/react-router";
|
||||
|
||||
interface NavbarLinkProps {
|
||||
icon: typeof IconHome2;
|
||||
label?: string;
|
||||
active?: boolean;
|
||||
href: string;
|
||||
|
||||
onClick?(navlink: NavbarLinkProps): void;
|
||||
|
||||
index: number;
|
||||
}
|
||||
|
||||
function NavbarLink(props: NavbarLinkProps) {
|
||||
const {icon: Icon, label, active, onClick} = props;
|
||||
return (
|
||||
<Tooltip display={!label ? "none" : "flex"} label={label} position="right" transitionProps={{duration: 0}}>
|
||||
<UnstyledButton onClick={() => onClick && onClick(props)}
|
||||
className={classes.link}
|
||||
data-active={active || undefined}>
|
||||
<Icon style={{width: rem(20), height: rem(20)}} stroke={1.5}/>
|
||||
</UnstyledButton>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
const mockdata = [
|
||||
{
|
||||
icon: IconHome2,
|
||||
label: 'Главная',
|
||||
href: '/'
|
||||
},
|
||||
{
|
||||
icon: IconCash,
|
||||
label: 'Сделки',
|
||||
href: '/leads'
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
export function Navbar() {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const router = useRouterState();
|
||||
const {colorScheme, toggleColorScheme} = useMantineColorScheme({keepTransitions: false});
|
||||
const onLogoutClick = () => {
|
||||
dispatch(logout());
|
||||
navigate({to: '/login'});
|
||||
}
|
||||
const onNavlinkClick = (props: NavbarLinkProps) => {
|
||||
navigate({to: props.href});
|
||||
}
|
||||
const links = mockdata.map((link, index) => (
|
||||
<NavbarLink
|
||||
{...link}
|
||||
index={index}
|
||||
key={link.label}
|
||||
active={router.location.pathname === link.href}
|
||||
onClick={onNavlinkClick}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<nav className={classes.navbar}>
|
||||
<Center>
|
||||
<Image
|
||||
style={{filter: "drop-shadow(0 0 30px #fff)"}}
|
||||
src={colorScheme == "dark" ? "/icons/logo-light.png" : "/icons/logo.png"}
|
||||
/>
|
||||
</Center>
|
||||
|
||||
<div className={classes.navbarMain}>
|
||||
<Stack justify="center" gap={rem(10)}>
|
||||
{links}
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
<Stack justify="center" gap={0}>
|
||||
<NavbarLink label={"Сменить тему"} onClick={toggleColorScheme} icon={colorScheme == "dark" ? IconSun : IconMoon} href={"#"} index={-1}/>
|
||||
<NavbarLink index={-1} href={"#"} onClick={onLogoutClick} icon={IconLogout} label="Выйти"/>
|
||||
</Stack>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
10
src/components/Navbar/UserButton/UserButton.module.css
Normal file
10
src/components/Navbar/UserButton/UserButton.module.css
Normal file
@@ -0,0 +1,10 @@
|
||||
.user {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: var(--mantine-spacing-md);
|
||||
color: light-dark(var(--mantine-color-black), var(--mantine-color-dark-0));
|
||||
|
||||
@mixin hover {
|
||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-8));
|
||||
}
|
||||
}
|
||||
28
src/components/Navbar/UserButton/UserButton.tsx
Normal file
28
src/components/Navbar/UserButton/UserButton.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { UnstyledButton, Group, Avatar, Text, rem } from '@mantine/core';
|
||||
import { IconChevronRight } from '@tabler/icons-react';
|
||||
import classes from './UserButton.module.css';
|
||||
|
||||
export function UserButton() {
|
||||
return (
|
||||
<UnstyledButton className={classes.user}>
|
||||
<Group>
|
||||
<Avatar
|
||||
src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-8.png"
|
||||
radius="xl"
|
||||
/>
|
||||
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text size="sm" fw={500}>
|
||||
Harriette Spoonlicker
|
||||
</Text>
|
||||
|
||||
<Text c="dimmed" size="xs">
|
||||
hspoonlicker@outlook.com
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<IconChevronRight style={{ width: rem(14), height: rem(14) }} stroke={1.5} />
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
);
|
||||
}
|
||||
25
src/components/Navbar/data.ts
Normal file
25
src/components/Navbar/data.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {IconAdjustments, IconGauge} from "@tabler/icons-react";
|
||||
|
||||
export const NavbarLinks = [
|
||||
{
|
||||
label: 'Главная',
|
||||
icon: IconGauge,
|
||||
links: [
|
||||
{
|
||||
label: "123",
|
||||
link: "/login"
|
||||
},
|
||||
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Настройки',
|
||||
icon: IconAdjustments,
|
||||
links:[
|
||||
{
|
||||
label: "Профиль"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
];
|
||||
114
src/components/TelegramAuthButton/TelegramAuthButton.tsx
Normal file
114
src/components/TelegramAuthButton/TelegramAuthButton.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { useRef, useEffect } from 'react'
|
||||
|
||||
export interface TelegramUser {
|
||||
id: number
|
||||
first_name: string
|
||||
username: string
|
||||
photo_url: string
|
||||
auth_date: number
|
||||
hash: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
botName: string
|
||||
usePic?: boolean
|
||||
className?: string
|
||||
cornerRadius?: number
|
||||
requestAccess?: boolean
|
||||
dataAuthUrl?: string
|
||||
dataOnauth?: (user: TelegramUser) => void
|
||||
buttonSize?: 'large' | 'medium' | 'small'
|
||||
wrapperProps?: React.HTMLProps<HTMLDivElement>
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
TelegramLoginWidget: {
|
||||
dataOnauth: (user: TelegramUser) => void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TelegramLoginButton: React.FC<Props> = ({
|
||||
wrapperProps,
|
||||
dataAuthUrl,
|
||||
usePic = false,
|
||||
botName,
|
||||
className,
|
||||
buttonSize = 'large',
|
||||
dataOnauth,
|
||||
cornerRadius,
|
||||
requestAccess = true
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current === null) return
|
||||
|
||||
if (
|
||||
typeof dataOnauth === 'undefined' &&
|
||||
typeof dataAuthUrl === 'undefined'
|
||||
) {
|
||||
throw new Error(
|
||||
'One of this props should be defined: dataAuthUrl (redirect URL), dataOnauth (callback fn) should be defined.'
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof dataOnauth === 'function') {
|
||||
window.TelegramLoginWidget = {
|
||||
dataOnauth: (user: TelegramUser) => dataOnauth(user)
|
||||
}
|
||||
}
|
||||
|
||||
const script = document.createElement('script')
|
||||
script.src = 'https://telegram.org/js/telegram-widget.js?22'
|
||||
script.setAttribute('data-telegram-login', botName)
|
||||
script.setAttribute('data-size', buttonSize)
|
||||
|
||||
if (cornerRadius !== undefined) {
|
||||
script.setAttribute('data-radius', cornerRadius.toString())
|
||||
}
|
||||
|
||||
if (requestAccess) {
|
||||
script.setAttribute('data-request-access', 'write')
|
||||
}
|
||||
|
||||
script.setAttribute('data-userpic', usePic.toString())
|
||||
|
||||
if (typeof dataAuthUrl === 'string') {
|
||||
script.setAttribute('data-auth-url', dataAuthUrl)
|
||||
} else {
|
||||
script.setAttribute('data-onauth', 'TelegramLoginWidget.dataOnauth(user)')
|
||||
}
|
||||
|
||||
script.async = true
|
||||
|
||||
ref.current.appendChild(script)
|
||||
}, [
|
||||
botName,
|
||||
buttonSize,
|
||||
cornerRadius,
|
||||
dataOnauth,
|
||||
requestAccess,
|
||||
usePic,
|
||||
ref,
|
||||
dataAuthUrl
|
||||
])
|
||||
|
||||
return <div ref={ref} className={className} {...wrapperProps} />
|
||||
}
|
||||
|
||||
TelegramLoginButton.propTypes = {
|
||||
botName: PropTypes.string.isRequired,
|
||||
usePic: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
cornerRadius: PropTypes.number,
|
||||
requestAccess: PropTypes.bool,
|
||||
wrapperProps: PropTypes.object,
|
||||
dataOnauth: PropTypes.func,
|
||||
dataAuthUrl: PropTypes.string,
|
||||
buttonSize: PropTypes.oneOf(['large', 'medium', 'small'])
|
||||
}
|
||||
|
||||
export default TelegramLoginButton
|
||||
64
src/components/test.tsx
Normal file
64
src/components/test.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import cx from 'clsx';
|
||||
import {Text} from '@mantine/core';
|
||||
import {useListState} from '@mantine/hooks';
|
||||
import {DragDropContext, Droppable, Draggable} from '@hello-pangea/dnd';
|
||||
import classes from './DndList.module.css';
|
||||
|
||||
|
||||
const data = [
|
||||
{position: 6, mass: 12.011, symbol: 'C', name: 'Carbon'},
|
||||
{position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen'},
|
||||
{position: 39, mass: 88.906, symbol: 'Y', name: 'Yttrium'},
|
||||
{position: 56, mass: 137.33, symbol: 'Ba', name: 'Barium'},
|
||||
{position: 58, mass: 140.12, symbol: 'Ce', name: 'Cerium'},
|
||||
];
|
||||
|
||||
export function DndList() {
|
||||
const [state, handlers] = useListState(data);
|
||||
|
||||
const items = (listIndex: number) => state.map((item, index) => (
|
||||
<Draggable key={item.symbol + `${listIndex}`} index={index} draggableId={item.symbol + `${listIndex}`}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
className={cx(classes.item, {[classes.itemDragging]: snapshot.isDragging})}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
ref={provided.innerRef}
|
||||
>
|
||||
<Text className={classes.symbol}>{item.symbol}</Text>
|
||||
<div>
|
||||
<Text>{item.name}</Text>
|
||||
<Text c="dimmed" size="sm">
|
||||
Position: {item.position} • Mass: {item.mass}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
));
|
||||
|
||||
return (
|
||||
<DragDropContext
|
||||
onDragEnd={({destination, source}) =>
|
||||
handlers.reorder({from: source.index, to: destination?.index || 0})
|
||||
}
|
||||
>
|
||||
<Droppable droppableId="dnd-list" direction="vertical">
|
||||
{(provided) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
{items(1)}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
<Droppable droppableId="dnd-list-2" direction="vertical">
|
||||
{(provided) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
{items(2)}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user