Add community dialog (#30)
This commit is contained in:
parent
654c0c29d7
commit
a4e2aee6f2
|
@ -0,0 +1,62 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { Theme } from "../../styles/themes";
|
||||
|
||||
const userAgent = window.navigator.userAgent;
|
||||
const platform = window.navigator.platform;
|
||||
const macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"];
|
||||
const windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"];
|
||||
const iosPlatforms = ["iPhone", "iPad", "iPod"];
|
||||
|
||||
export const DownloadButton = ({ theme }: { theme: Theme }) => {
|
||||
const [link, setlink] = useState("https://status.im/get/");
|
||||
const [os, setOs] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (macosPlatforms.includes(platform)) {
|
||||
setlink(
|
||||
"https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.dmg"
|
||||
);
|
||||
setOs("Mac");
|
||||
} else if (iosPlatforms.includes(platform)) {
|
||||
setlink(
|
||||
"https://apps.apple.com/us/app/status-private-communication/id1178893006"
|
||||
);
|
||||
setOs("iOS");
|
||||
} else if (windowsPlatforms.includes(platform)) {
|
||||
setlink(
|
||||
"https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.exe"
|
||||
);
|
||||
setOs("Windows");
|
||||
} else if (/Android/.test(userAgent)) {
|
||||
setlink(
|
||||
"https://play.google.com/store/apps/details?id=im.status.ethereum"
|
||||
);
|
||||
setOs("Android");
|
||||
} else if (/Linux/.test(platform)) {
|
||||
setlink(
|
||||
"https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.tar.gz"
|
||||
);
|
||||
setOs("Linux");
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Link href={link} theme={theme} target="_blank" rel="noopener noreferrer">
|
||||
{os ? `Download Status for ${os}` : "Download Status"}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const Link = styled.a`
|
||||
margin-top: 24px;
|
||||
padding: 11px 32px;
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
color: ${({ theme }) => theme.tertiary};
|
||||
background: ${({ theme }) => theme.buttonBg};
|
||||
border-radius: 8px;
|
||||
`;
|
|
@ -5,8 +5,9 @@ import { ChannelData, channels } from "../helpers/channelsMock";
|
|||
import { CommunityData } from "../helpers/communityMock";
|
||||
import { Theme } from "../styles/themes";
|
||||
|
||||
import { Community, MembersAmount } from "./Community";
|
||||
import { Community } from "./Community";
|
||||
import { MutedIcon } from "./Icons/MutedIcon";
|
||||
import { textMediumStyles } from "./Text";
|
||||
|
||||
interface ChannelsProps {
|
||||
theme: Theme;
|
||||
|
@ -37,7 +38,7 @@ export function Channels({
|
|||
|
||||
return (
|
||||
<ChannelsWrapper theme={theme}>
|
||||
<Community community={community} theme={theme} />
|
||||
<StyledCommunity theme={theme} community={community} />
|
||||
<ChannelList>
|
||||
{channels.map((channel) => (
|
||||
<Channel
|
||||
|
@ -139,6 +140,18 @@ const ChannelsWrapper = styled.div<ThemeProps>`
|
|||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const StyledCommunity = styled(Community)`
|
||||
padding-left: 0 0 0 10px;
|
||||
margin: 0 0 16px;
|
||||
`;
|
||||
|
||||
const MembersAmount = styled.p<ThemeProps>`
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.1px;
|
||||
color: ${({ theme }) => theme.secondary};
|
||||
`;
|
||||
|
||||
const ChannelList = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -193,11 +206,10 @@ const ChannelLogo = styled.div<ThemeProps>`
|
|||
`;
|
||||
|
||||
const ChannelName = styled.p<ThemeProps>`
|
||||
color: ${({ theme }) => theme.textPrimaryColor};
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
opacity: 0.7;
|
||||
color: ${({ theme }) => theme.primary};
|
||||
${textMediumStyles}
|
||||
|
||||
&.active,
|
||||
&.notified {
|
||||
|
|
|
@ -34,13 +34,13 @@ export function ChatInput({ theme, addMessage }: ChatInputProps) {
|
|||
onSelect={addEmoji}
|
||||
theme={theme === lightTheme ? "light" : "dark"}
|
||||
set="apple"
|
||||
color={theme.memberNameColor}
|
||||
color={theme.tertiary}
|
||||
emojiSize={26}
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: "100%",
|
||||
right: "0",
|
||||
color: theme.textSecondaryColor,
|
||||
color: theme.secondary,
|
||||
}}
|
||||
showPreview={false}
|
||||
showSkinTones={false}
|
||||
|
@ -106,7 +106,7 @@ const Input = styled.textarea<ThemeProps>`
|
|||
background: ${({ theme }) => theme.inputColor};
|
||||
border-radius: 36px 16px 4px 36px;
|
||||
border: 1px solid ${({ theme }) => theme.inputColor};
|
||||
color: ${({ theme }) => theme.textPrimaryColor};
|
||||
color: ${({ theme }) => theme.primary};
|
||||
margin-left: 10px;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
|
|
|
@ -4,6 +4,7 @@ import styled from "styled-components";
|
|||
import { ChatMessage } from "../../models/ChatMessage";
|
||||
import { Theme } from "../../styles/themes";
|
||||
import { UserIcon } from "../Icons/UserIcon";
|
||||
import { textSmallStyles } from "../Text";
|
||||
|
||||
import { ChatMessageContent } from "./ChatMessageContent";
|
||||
|
||||
|
@ -94,11 +95,11 @@ const DateSeparator = styled.div`
|
|||
font-family: Inter;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
color: #939ba1;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
${textSmallStyles}
|
||||
`;
|
||||
|
||||
const ContentWrapper = styled.div`
|
||||
|
@ -126,7 +127,7 @@ export const Icon = styled.div`
|
|||
const UserNameWrapper = styled.div<ThemeProps>`
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
color: ${({ theme }) => theme.memberNameColor};
|
||||
color: ${({ theme }) => theme.tertiary};
|
||||
`;
|
||||
|
||||
const TimeWrapper = styled.div<ThemeProps>`
|
||||
|
@ -134,7 +135,7 @@ const TimeWrapper = styled.div<ThemeProps>`
|
|||
line-height: 14px;
|
||||
letter-spacing: 0.2px;
|
||||
text-transform: uppercase;
|
||||
color: ${({ theme }) => theme.textSecondaryColor};
|
||||
color: ${({ theme }) => theme.secondary};
|
||||
margin-left: 4px;
|
||||
`;
|
||||
|
||||
|
@ -142,5 +143,5 @@ const MessageText = styled.div<ThemeProps>`
|
|||
overflow-wrap: anywhere;
|
||||
width: 100%;
|
||||
white-space: pre;
|
||||
color: ${({ theme }) => theme.textPrimaryColor};
|
||||
color: ${({ theme }) => theme.primary};
|
||||
`;
|
||||
|
|
|
@ -1,57 +1,42 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { CommunityData } from "../helpers/communityMock";
|
||||
import { Theme } from "../styles/themes";
|
||||
|
||||
import { CommunityIdentity } from "./CommunityIdentity";
|
||||
import { CommunityModal } from "./Modals/CommunityModal";
|
||||
|
||||
interface CommunityProps {
|
||||
theme: Theme;
|
||||
community: CommunityData;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Community({ theme, community }: CommunityProps) {
|
||||
export function Community({ theme, community, className }: CommunityProps) {
|
||||
const { name, icon, members, description } = community;
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<CommunityWrap>
|
||||
<CommunityLogo src={community.icon} alt={`${community.name} logo`} />
|
||||
<CommunityInfo>
|
||||
<CommunityName theme={theme}>{community.name}</CommunityName>
|
||||
<MembersAmount theme={theme}>{community.members} members</MembersAmount>
|
||||
</CommunityInfo>
|
||||
</CommunityWrap>
|
||||
<>
|
||||
<button className={className} onClick={() => setIsModalVisible(true)}>
|
||||
<CommunityIdentity
|
||||
name={name}
|
||||
icon={icon}
|
||||
subtitle={`${members} members`}
|
||||
theme={theme}
|
||||
/>
|
||||
</button>
|
||||
<CommunityModal
|
||||
isVisible={isModalVisible}
|
||||
onClose={() => setIsModalVisible(false)}
|
||||
icon={icon}
|
||||
name={name}
|
||||
theme={theme}
|
||||
subtitle="Public Community"
|
||||
description={description}
|
||||
publicKey="0xD95DBdaB08A9FED2D71ac9C3028AAc40905d8CF3"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface ThemeProps {
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const CommunityWrap = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const CommunityLogo = styled.img`
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
margin-left: 10px;
|
||||
`;
|
||||
|
||||
const CommunityInfo = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 8px;
|
||||
`;
|
||||
|
||||
const CommunityName = styled.h1<ThemeProps>`
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
color: ${({ theme }) => theme.textPrimaryColor};
|
||||
`;
|
||||
|
||||
export const MembersAmount = styled.p<ThemeProps>`
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.1px;
|
||||
color: ${({ theme }) => theme.textSecondaryColor};
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { Theme } from "../styles/themes";
|
||||
|
||||
import { textMediumStyles } from "./Text";
|
||||
|
||||
export interface CommunityIdentityProps {
|
||||
icon: string;
|
||||
name: string;
|
||||
subtitle: string;
|
||||
theme: Theme;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const CommunityIdentity = ({
|
||||
icon,
|
||||
name,
|
||||
subtitle,
|
||||
className,
|
||||
theme,
|
||||
}: CommunityIdentityProps) => {
|
||||
return (
|
||||
<Row className={className}>
|
||||
<Logo src={icon} alt={`${name} logo`} />
|
||||
<div>
|
||||
<Name theme={theme}>{name}</Name>
|
||||
<Subtitle theme={theme}>{subtitle}</Subtitle>
|
||||
</div>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
const Row = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const Logo = styled.img`
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const Name = styled.p`
|
||||
font-weight: 500;
|
||||
color: ${({ theme }) => theme.primary};
|
||||
|
||||
${textMediumStyles}
|
||||
`;
|
||||
|
||||
const Subtitle = styled.p`
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.1px;
|
||||
color: ${({ theme }) => theme.secondary};
|
||||
`;
|
|
@ -0,0 +1,75 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { Theme } from "../../styles/themes";
|
||||
import { copy } from "../../utils/copy";
|
||||
import { reduceString } from "../../utils/reduceString";
|
||||
import { textMediumStyles, textSmallStyles } from "../Text";
|
||||
|
||||
interface CopyInputProps {
|
||||
label: string;
|
||||
value: string;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export const CopyInput = ({ label, value, theme }: CopyInputProps) => (
|
||||
<div>
|
||||
<Label theme={theme}>{label}</Label>
|
||||
<Wrapper theme={theme}>
|
||||
<Text theme={theme}>{reduceString(value, 15, 15)}</Text>
|
||||
<CopyButtonWrapper>
|
||||
<CopyButton theme={theme} onClick={() => copy(value)}>
|
||||
Copy
|
||||
</CopyButton>
|
||||
</CopyButtonWrapper>
|
||||
</Wrapper>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Label = styled.p`
|
||||
margin-bottom: 7px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.primary};
|
||||
|
||||
${textSmallStyles}
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
position: relative;
|
||||
padding: 14px 70px 14px 8px;
|
||||
background: ${({ theme }) => theme.inputColor};
|
||||
border-radius: 8px;
|
||||
`;
|
||||
|
||||
const Text = styled.p`
|
||||
color: ${({ theme }) => theme.primary};
|
||||
|
||||
${textMediumStyles}
|
||||
`;
|
||||
|
||||
const CopyButtonWrapper = styled.div`
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 70px;
|
||||
transform: translateY(-50%);
|
||||
background: ${({ theme }) => theme.inputColor};
|
||||
border-radius: 8px;
|
||||
`;
|
||||
|
||||
const CopyButton = styled.button`
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.1px;
|
||||
color: ${({ theme }) => theme.tertiary};
|
||||
background: ${({ theme }) => theme.buttonBg};
|
||||
border: 1px solid ${({ theme }) => theme.tertiary};
|
||||
border-radius: 6px;
|
||||
`;
|
|
@ -0,0 +1,28 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { Theme } from "../../styles/themes";
|
||||
|
||||
export const CrossIcon = ({ theme }: { theme: Theme }) => (
|
||||
<Icon
|
||||
theme={theme}
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M6 4.57404L1.72275 0.296796C1.32616 -0.0997918 0.689941 -0.0975927 0.296174 0.296174C-0.100338 0.692686 -0.0973145 1.32864 0.296796 1.72275L4.57404 6L0.296796 10.2772C-0.0997918 10.6738 -0.0975927 11.3101 0.296174 11.7038C0.692686 12.1003 1.32864 12.0973 1.72275 11.7032L6 7.42596L10.2772 11.7032C10.6738 12.0998 11.3101 12.0976 11.7038 11.7038C12.1003 11.3073 12.0973 10.6714 11.7032 10.2772L7.42596 6L11.7032 1.72275C12.0998 1.32616 12.0976 0.689941 11.7038 0.296174C11.3073 -0.100338 10.6714 -0.0973145 10.2772 0.296796L6 4.57404Z"
|
||||
fill="black"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
|
||||
const Icon = styled.svg`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.primary};
|
||||
}
|
||||
`;
|
|
@ -41,10 +41,10 @@ export const EmojiIcon = ({ theme, isActive }: ThemeProps) => {
|
|||
|
||||
const Icon = styled.svg<ThemeProps>`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.textSecondaryColor};
|
||||
fill: ${({ theme }) => theme.secondary};
|
||||
}
|
||||
|
||||
& > path.active {
|
||||
fill: ${({ theme }) => theme.memberNameColor};
|
||||
fill: ${({ theme }) => theme.tertiary};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -41,10 +41,10 @@ export const GifIcon = ({ theme, isActive }: ThemeProps) => {
|
|||
|
||||
const Icon = styled.svg<ThemeProps>`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.textSecondaryColor};
|
||||
fill: ${({ theme }) => theme.secondary};
|
||||
}
|
||||
|
||||
& > path.active {
|
||||
fill: ${({ theme }) => theme.memberNameColor};
|
||||
fill: ${({ theme }) => theme.tertiary};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -28,6 +28,6 @@ export const MembersIcon = ({ theme }: ThemeProps) => {
|
|||
|
||||
const Icon = styled.svg<ThemeProps>`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.textPrimaryColor};
|
||||
fill: ${({ theme }) => theme.primary};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -30,6 +30,6 @@ export const MutedIcon = ({ theme }: ThemeProps) => {
|
|||
|
||||
const Icon = styled.svg<ThemeProps>`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.textPrimaryColor};
|
||||
fill: ${({ theme }) => theme.primary};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -32,6 +32,6 @@ export const PictureIcon = ({ theme }: ThemeProps) => {
|
|||
|
||||
const Icon = styled.svg<ThemeProps>`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.textSecondaryColor};
|
||||
fill: ${({ theme }) => theme.secondary};
|
||||
}
|
||||
`;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -33,10 +33,10 @@ export const StickerIcon = ({ theme, isActive }: ThemeProps) => {
|
|||
|
||||
const Icon = styled.svg<ThemeProps>`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.textSecondaryColor};
|
||||
fill: ${({ theme }) => theme.secondary};
|
||||
}
|
||||
|
||||
& > path.active {
|
||||
fill: ${({ theme }) => theme.memberNameColor};
|
||||
fill: ${({ theme }) => theme.tertiary};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { DownloadButton } from "../Buttons/DownloadButton";
|
||||
import {
|
||||
CommunityIdentity,
|
||||
CommunityIdentityProps,
|
||||
} from "../CommunityIdentity";
|
||||
import { CopyInput } from "../Form/CopyInput";
|
||||
import { StatusLogo } from "../Icons/StatusLogo";
|
||||
import { textMediumStyles, textSmallStyles } from "../Text";
|
||||
|
||||
import { BasicModalProps, Modal } from "./Modal";
|
||||
|
||||
interface CommunityModalProps extends BasicModalProps, CommunityIdentityProps {
|
||||
description: string;
|
||||
publicKey: string;
|
||||
}
|
||||
|
||||
export const CommunityModal = ({
|
||||
isVisible,
|
||||
onClose,
|
||||
icon,
|
||||
name,
|
||||
subtitle,
|
||||
description,
|
||||
publicKey,
|
||||
theme,
|
||||
}: CommunityModalProps) => {
|
||||
return (
|
||||
<Modal theme={theme} isVisible={isVisible} onClose={onClose}>
|
||||
<Section theme={theme}>
|
||||
<CommunityIdentity
|
||||
theme={theme}
|
||||
icon={icon}
|
||||
name={name}
|
||||
subtitle={subtitle}
|
||||
/>
|
||||
</Section>
|
||||
<Section theme={theme}>
|
||||
<Text theme={theme}>{description}</Text>
|
||||
</Section>
|
||||
<Section theme={theme}>
|
||||
<CopyInput
|
||||
theme={theme}
|
||||
value={publicKey}
|
||||
label="Community public key"
|
||||
/>
|
||||
<Hint theme={theme}>
|
||||
To access this community, paste community public key in Status desktop
|
||||
or mobile app
|
||||
</Hint>
|
||||
</Section>
|
||||
<BottomSection theme={theme}>
|
||||
<StatusLogo theme={theme} />
|
||||
<DownloadButton theme={theme} />
|
||||
</BottomSection>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const Section = styled.div`
|
||||
padding: 20px 16px;
|
||||
|
||||
& + & {
|
||||
border-top: 1px solid ${({ theme }) => theme.border};
|
||||
}
|
||||
`;
|
||||
|
||||
const Text = styled.p`
|
||||
color: ${({ theme }) => theme.primary};
|
||||
|
||||
${textMediumStyles}
|
||||
`;
|
||||
|
||||
const Hint = styled.p`
|
||||
margin-top: 16px;
|
||||
color: ${({ theme }) => theme.secondary};
|
||||
|
||||
${textSmallStyles}
|
||||
`;
|
||||
|
||||
const BottomSection = styled(Section)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
`;
|
|
@ -0,0 +1,100 @@
|
|||
import React, { ReactNode, useCallback, useEffect } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { Theme } from "../../styles/themes";
|
||||
import { CrossIcon } from "../Icons/CrossIcon";
|
||||
|
||||
export interface BasicModalProps {
|
||||
isVisible: boolean;
|
||||
onClose: () => void;
|
||||
className?: string;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export interface ModalProps extends BasicModalProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const Modal = ({
|
||||
isVisible,
|
||||
onClose,
|
||||
children,
|
||||
className,
|
||||
theme,
|
||||
}: ModalProps) => {
|
||||
const listenKeyboard = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
if (event.key === "Escape" || event.keyCode === 27) {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
window.addEventListener("keydown", listenKeyboard, true);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", listenKeyboard, true);
|
||||
};
|
||||
}
|
||||
}, [isVisible, listenKeyboard]);
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return createPortal(
|
||||
<ModalView>
|
||||
<ModalOverlay onClick={onClose} theme={theme} />
|
||||
<ModalBody theme={theme} className={className}>
|
||||
<CloseButton onClick={onClose}>
|
||||
<CrossIcon theme={theme} />
|
||||
</CloseButton>
|
||||
{children}
|
||||
</ModalBody>
|
||||
</ModalView>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
|
||||
const ModalView = styled.div`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
`;
|
||||
|
||||
const ModalBody = styled.div`
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
border-radius: 8px;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
const ModalOverlay = styled.div`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: ${({ theme }) => theme.primary};
|
||||
opacity: 0.4;
|
||||
`;
|
||||
|
||||
const CloseButton = styled.button`
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
padding: 10px;
|
||||
`;
|
|
@ -0,0 +1,11 @@
|
|||
import { css } from "styled-components";
|
||||
|
||||
export const textSmallStyles = css`
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
`;
|
||||
|
||||
export const textMediumStyles = css`
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
`;
|
|
@ -3,6 +3,7 @@ export type CommunityData = {
|
|||
name: string;
|
||||
icon: string;
|
||||
members: number;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export const community = {
|
||||
|
@ -10,4 +11,5 @@ export const community = {
|
|||
name: "CryptoKitties",
|
||||
icon: "https://www.cryptokitties.co/icons/logo.svg",
|
||||
members: 186,
|
||||
description: "A community of cat lovers, meow!",
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
export type Theme = {
|
||||
textPrimaryColor: string;
|
||||
textSecondaryColor: string;
|
||||
primary: string;
|
||||
secondary: string;
|
||||
bodyBackgroundColor: string;
|
||||
sectionBackgroundColor: string;
|
||||
memberNameColor: string;
|
||||
tertiary: string;
|
||||
guestNameColor: string;
|
||||
iconColor: string;
|
||||
iconUserColor: string;
|
||||
|
@ -11,14 +11,16 @@ export type Theme = {
|
|||
activeChannelBackground: string;
|
||||
notificationColor: string;
|
||||
inputColor: string;
|
||||
border: string;
|
||||
buttonBg: string;
|
||||
};
|
||||
|
||||
export const lightTheme: Theme = {
|
||||
textPrimaryColor: "#000",
|
||||
textSecondaryColor: "#939BA1",
|
||||
primary: "#000",
|
||||
secondary: "#939BA1",
|
||||
tertiary: "#4360DF",
|
||||
bodyBackgroundColor: "#fff",
|
||||
sectionBackgroundColor: "#F6F8FA",
|
||||
memberNameColor: "#4360DF",
|
||||
guestNameColor: "#887AF9",
|
||||
iconColor: "#D37EF4",
|
||||
iconUserColor: "#717199",
|
||||
|
@ -26,14 +28,16 @@ export const lightTheme: Theme = {
|
|||
activeChannelBackground: "#E9EDF1",
|
||||
notificationColor: "#4360DF",
|
||||
inputColor: "#EEF2F5",
|
||||
border: "#EEF2F5",
|
||||
buttonBg: "rgba(67, 96, 223, 0.2)",
|
||||
};
|
||||
|
||||
export const darkTheme: Theme = {
|
||||
textPrimaryColor: "#fff",
|
||||
textSecondaryColor: "#909090",
|
||||
primary: "#fff",
|
||||
secondary: "#909090",
|
||||
tertiary: "#88B0FF",
|
||||
bodyBackgroundColor: "#000",
|
||||
sectionBackgroundColor: "#252525",
|
||||
memberNameColor: "#88B0FF",
|
||||
guestNameColor: "#887AF9",
|
||||
iconColor: "#D37EF4",
|
||||
iconUserColor: "#717199",
|
||||
|
@ -41,6 +45,8 @@ export const darkTheme: Theme = {
|
|||
activeChannelBackground: "#2C2C2C",
|
||||
notificationColor: "#887AF9",
|
||||
inputColor: "#373737",
|
||||
border: "#373737",
|
||||
buttonBg: "rgba(134, 158, 255, 0.3)",
|
||||
};
|
||||
|
||||
export default { lightTheme, darkTheme };
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export const copy = (text: string) => {
|
||||
navigator.clipboard.writeText(text).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
export const reduceString = (
|
||||
string: string,
|
||||
limitBefore: number,
|
||||
limitAfter: number
|
||||
) => {
|
||||
return `${string.substring(0, limitBefore)}...${string.substring(
|
||||
string.length - limitAfter
|
||||
)}`;
|
||||
};
|
Loading…
Reference in New Issue