Refactor dropdowns (#109)

This commit is contained in:
Szymon Szlachtowicz 2021-11-03 00:43:06 +01:00 committed by GitHub
parent 6db3b9272d
commit ac77a0ada2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 136 additions and 143 deletions

View File

@ -1,5 +1,4 @@
import React from "react"; import React from "react";
import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider"; import { useNarrow } from "../../contexts/narrowProvider";
@ -9,22 +8,8 @@ import { CheckSvg } from "../Icons/CheckIcon";
import { ClearSvg } from "../Icons/ClearIcon"; import { ClearSvg } from "../Icons/ClearIcon";
import { MembersSmallSvg } from "../Icons/MembersSmallIcon"; import { MembersSmallSvg } from "../Icons/MembersSmallIcon";
import { MuteSvg } from "../Icons/MuteIcon"; import { MuteSvg } from "../Icons/MuteIcon";
import { textSmallStyles } from "../Text";
type MenuItemProps = { import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
Svg: ({ width, height }: { width: number; height: number }) => JSX.Element;
text: string;
onClick: () => void;
};
function MenuItem({ Svg, text, onClick }: MenuItemProps) {
return (
<Item onClick={onClick}>
<Svg width={16} height={16} />
<MenuText>{text}</MenuText>
</Item>
);
}
interface ChannelMenuProps { interface ChannelMenuProps {
channel: ChannelData; channel: ChannelData;
@ -43,82 +28,35 @@ export const ChannelMenu = ({
const { clearNotifications } = useMessengerContext(); const { clearNotifications } = useMessengerContext();
return ( return (
<MenuBlock> <DropdownMenu>
<MenuList> {narrow && (
{narrow && (
<MenuItem
onClick={() => {
switchMemberList();
setShowChannelMenu(false);
}}
Svg={MembersSmallSvg}
text="View Members"
/>
)}
<MenuItem <MenuItem
onClick={() => { onClick={() => {
channel.isMuted = true; switchMemberList();
setShowChannelMenu(false); setShowChannelMenu(false);
}} }}
Svg={MuteSvg} >
text="Mute Chat" <MembersSmallSvg height={16} width={16} />
/> <MenuText>View Members</MenuText>
<MenuItem </MenuItem>
onClick={() => clearNotifications(channel.id)} )}
Svg={CheckSvg} <MenuItem
text="Mark as Read" onClick={() => {
/> channel.isMuted = true;
<MenuItem setShowChannelMenu(false);
onClick={() => messages.length === 0} }}
Svg={ClearSvg} >
text="Clear History" <MuteSvg height={16} width={16} />
/> <MenuText>Mute Chat</MenuText>
</MenuList> </MenuItem>
</MenuBlock> <MenuItem onClick={() => clearNotifications(channel.id)}>
<CheckSvg height={16} width={16} />
<MenuText>Mark as Read</MenuText>
</MenuItem>
<MenuItem onClick={() => messages.length === 0}>
<ClearSvg height={16} width={16} />
<MenuText>Clear History</MenuText>
</MenuItem>
</DropdownMenu>
); );
}; };
const MenuBlock = styled.div`
width: 207px;
background: ${({ theme }) => theme.bodyBackgroundColor};
box-shadow: 0px 2px 4px rgba(0, 34, 51, 0.16),
0px 4px 12px rgba(0, 34, 51, 0.08);
borderradius: 8px;
padding: 8px 0;
position: absolute;
right: 8px;
top: calc(100% - 8px);
z-index: 2;
`;
const MenuList = styled.ul`
list-style: none;
`;
const Item = styled.li`
width: 100%;
display: flex;
align-items: center;
padding: 8px 14px;
cursor: pointer;
color: ${({ theme }) => theme.primary};
&:hover {
background: ${({ theme }) => theme.tertiary};
color: ${({ theme }) => theme.bodyBackgroundColor};
}
& > svg {
fill: ${({ theme }) => theme.tertiary};
}
&:hover > svg {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
`;
const MenuText = styled.span`
margin-left: 6px;
${textSmallStyles}
`;

View File

@ -0,0 +1,61 @@
import React, { ReactNode } from "react";
import styled from "styled-components";
import { textSmallStyles } from "../Text";
type DropdownMenuProps = {
children: ReactNode;
className?: string;
};
export function DropdownMenu({ children, className }: DropdownMenuProps) {
return (
<MenuBlock className={className}>
<MenuList>{children}</MenuList>
</MenuBlock>
);
}
export const MenuItem = styled.li`
width: 100%;
display: flex;
align-items: center;
padding: 8px 14px;
cursor: pointer;
color: ${({ theme }) => theme.primary};
&:hover {
background: ${({ theme }) => theme.tertiary};
color: ${({ theme }) => theme.bodyBackgroundColor};
}
& > svg {
fill: ${({ theme }) => theme.tertiary};
}
&:hover > svg {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
`;
export const MenuText = styled.span`
margin-left: 6px;
${textSmallStyles}
`;
const MenuBlock = styled.div`
width: 207px;
background: ${({ theme }) => theme.bodyBackgroundColor};
box-shadow: 0px 2px 4px rgba(0, 34, 51, 0.16),
0px 4px 12px rgba(0, 34, 51, 0.08);
border-radius: 8px;
padding: 8px 0;
position: absolute;
right: 8px;
top: calc(100% - 8px);
z-index: 2;
`;
const MenuList = styled.ul`
list-style: none;
`;

View File

@ -4,9 +4,10 @@ import styled from "styled-components";
import { useContextMenu } from "../../hooks/useContextMenu"; import { useContextMenu } from "../../hooks/useContextMenu";
import { copyImg } from "../../utils/copyImg"; import { copyImg } from "../../utils/copyImg";
import { downloadImg } from "../../utils/downloadImg"; import { downloadImg } from "../../utils/downloadImg";
import { CopyIcon } from "../Icons/CopyIcon"; import { CopySvg } from "../Icons/CopyIcon";
import { DownloadIcon } from "../Icons/DownloadIcon"; import { DownloadSvg } from "../Icons/DownloadIcon";
import { textSmallStyles } from "../Text";
import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
interface ImageMenuProps { interface ImageMenuProps {
imageId: string; imageId: string;
@ -16,51 +17,22 @@ export const ImageMenu = ({ imageId }: ImageMenuProps) => {
const { showMenu } = useContextMenu(imageId); const { showMenu } = useContextMenu(imageId);
return showMenu ? ( return showMenu ? (
<MenuBlock> <ImageDropdown>
<MenuList> <MenuItem onClick={() => copyImg(imageId)}>
<MenuItem onClick={() => copyImg(imageId)}> <CopySvg height={16} width={16} /> <MenuText>Copy image</MenuText>
<CopyIcon /> <MenuText>Copy image</MenuText> </MenuItem>
</MenuItem> <MenuItem onClick={() => downloadImg(imageId)}>
<MenuItem onClick={() => downloadImg(imageId)}> <DownloadSvg height={16} width={16} />
<DownloadIcon /> <MenuText> Download image</MenuText>
<MenuText> Download image</MenuText> </MenuItem>
</MenuItem> </ImageDropdown>
</MenuList>
</MenuBlock>
) : ( ) : (
<></> <></>
); );
}; };
const MenuBlock = styled.div` const ImageDropdown = styled(DropdownMenu)`
width: 176px; width: 176px;
height: 84px;
background: ${({ theme }) => theme.bodyBackgroundColor};
box-shadow: 0px 2px 4px rgba(0, 34, 51, 0.16),
0px 4px 12px rgba(0, 34, 51, 0.08);
border-radius: 8px;
padding: 8px 0;
position: absolute;
left: 120px; left: 120px;
top: 46px; top: 46px;
z-index: 2;
`;
const MenuList = styled.ul`
list-style: none;
`;
const MenuItem = styled.li`
width: 100%;
display: flex;
align-items: center;
padding: 8px 14px;
cursor: pointer;
`;
const MenuText = styled.span`
margin-left: 6px;
color: ${({ theme }) => theme.primary};
${textSmallStyles}
`; `;

View File

@ -1,13 +1,20 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
export const CopyIcon = () => { type CopySvgProps = {
width: number;
height: number;
className?: string;
};
export function CopySvg({ width, height, className }: CopySvgProps) {
return ( return (
<Icon <svg
width="16" width={width}
height="16" height={height}
viewBox="0 0 16 16" viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
className={className}
> >
<path d="M4.16683 7.00065C4.44297 7.00065 4.66683 6.77679 4.66683 6.50065C4.66683 6.22451 4.44297 6.00065 4.16683 6.00065H4.00016C2.5274 6.00065 1.3335 7.19456 1.3335 8.66732V12.0007C1.3335 13.4734 2.5274 14.6673 4.00016 14.6673H7.3335C8.80626 14.6673 10.0002 13.4734 10.0002 12.0007V11.834C10.0002 11.5578 9.77631 11.334 9.50016 11.334C9.22402 11.334 9.00016 11.5578 9.00016 11.834V12.0007C9.00016 12.9211 8.25397 13.6673 7.3335 13.6673H4.00016C3.07969 13.6673 2.3335 12.9211 2.3335 12.0007V8.66732C2.3335 7.74684 3.07969 7.00065 4.00016 7.00065H4.16683Z" /> <path d="M4.16683 7.00065C4.44297 7.00065 4.66683 6.77679 4.66683 6.50065C4.66683 6.22451 4.44297 6.00065 4.16683 6.00065H4.00016C2.5274 6.00065 1.3335 7.19456 1.3335 8.66732V12.0007C1.3335 13.4734 2.5274 14.6673 4.00016 14.6673H7.3335C8.80626 14.6673 10.0002 13.4734 10.0002 12.0007V11.834C10.0002 11.5578 9.77631 11.334 9.50016 11.334C9.22402 11.334 9.00016 11.5578 9.00016 11.834V12.0007C9.00016 12.9211 8.25397 13.6673 7.3335 13.6673H4.00016C3.07969 13.6673 2.3335 12.9211 2.3335 12.0007V8.66732C2.3335 7.74684 3.07969 7.00065 4.00016 7.00065H4.16683Z" />
<path <path
@ -15,11 +22,15 @@ export const CopyIcon = () => {
clipRule="evenodd" clipRule="evenodd"
d="M6.00016 4.00065C6.00016 2.52789 7.19407 1.33398 8.66683 1.33398H12.0002C13.4729 1.33398 14.6668 2.52789 14.6668 4.00065V7.33398C14.6668 8.80674 13.4729 10.0007 12.0002 10.0007H8.66683C7.19407 10.0007 6.00016 8.80674 6.00016 7.33398V4.00065ZM8.66683 2.33398H12.0002C12.9206 2.33398 13.6668 3.08018 13.6668 4.00065V7.33398C13.6668 8.25446 12.9206 9.00065 12.0002 9.00065H8.66683C7.74636 9.00065 7.00016 8.25446 7.00016 7.33398V4.00065C7.00016 3.08018 7.74636 2.33398 8.66683 2.33398Z" d="M6.00016 4.00065C6.00016 2.52789 7.19407 1.33398 8.66683 1.33398H12.0002C13.4729 1.33398 14.6668 2.52789 14.6668 4.00065V7.33398C14.6668 8.80674 13.4729 10.0007 12.0002 10.0007H8.66683C7.19407 10.0007 6.00016 8.80674 6.00016 7.33398V4.00065ZM8.66683 2.33398H12.0002C12.9206 2.33398 13.6668 3.08018 13.6668 4.00065V7.33398C13.6668 8.25446 12.9206 9.00065 12.0002 9.00065H8.66683C7.74636 9.00065 7.00016 8.25446 7.00016 7.33398V4.00065C7.00016 3.08018 7.74636 2.33398 8.66683 2.33398Z"
/> />
</Icon> </svg>
); );
}
export const CopyIcon = () => {
return <Icon width={16} height={16} />;
}; };
const Icon = styled.svg` const Icon = styled(CopySvg)`
& > path { & > path {
fill: ${({ theme }) => theme.tertiary}; fill: ${({ theme }) => theme.tertiary};
} }

View File

@ -1,21 +1,32 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
export const DownloadIcon = () => { type DownloadSvgProps = {
width: number;
height: number;
className?: string;
};
export function DownloadSvg({ width, height, className }: DownloadSvgProps) {
return ( return (
<Icon <svg
width="16" width={width}
height="16" height={height}
viewBox="0 0 16 16" viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
className={className}
> >
<path d="M10.6668 8.83399C10.6668 8.55784 10.8924 8.33835 11.1647 8.29286C12.5846 8.05568 13.6668 6.82121 13.6668 5.33399C13.6668 3.67713 12.3237 2.33399 10.6668 2.33399L5.3335 2.33399C3.67664 2.33399 2.3335 3.67713 2.3335 5.33399C2.3335 6.82121 3.4157 8.05568 4.83559 8.29286C5.10796 8.33835 5.3335 8.55784 5.3335 8.83399C5.3335 9.11013 5.10852 9.33726 4.83449 9.30316C2.86085 9.05755 1.3335 7.37414 1.3335 5.33399C1.3335 3.12485 3.12436 1.33398 5.3335 1.33398L10.6668 1.33399C12.876 1.33399 14.6668 3.12485 14.6668 5.33399C14.6668 7.37414 13.1395 9.05755 11.1658 9.30316C10.8918 9.33726 10.6668 9.11013 10.6668 8.83399Z" /> <path d="M10.6668 8.83399C10.6668 8.55784 10.8924 8.33835 11.1647 8.29286C12.5846 8.05568 13.6668 6.82121 13.6668 5.33399C13.6668 3.67713 12.3237 2.33399 10.6668 2.33399L5.3335 2.33399C3.67664 2.33399 2.3335 3.67713 2.3335 5.33399C2.3335 6.82121 3.4157 8.05568 4.83559 8.29286C5.10796 8.33835 5.3335 8.55784 5.3335 8.83399C5.3335 9.11013 5.10852 9.33726 4.83449 9.30316C2.86085 9.05755 1.3335 7.37414 1.3335 5.33399C1.3335 3.12485 3.12436 1.33398 5.3335 1.33398L10.6668 1.33399C12.876 1.33399 14.6668 3.12485 14.6668 5.33399C14.6668 7.37414 13.1395 9.05755 11.1658 9.30316C10.8918 9.33726 10.6668 9.11013 10.6668 8.83399Z" />
<path d="M8.00016 4.83399C8.27631 4.83399 8.50016 5.05784 8.50016 5.33399V11.9888C8.50016 12.2858 8.85921 12.4345 9.0692 12.2245L10.3133 10.9804C10.5085 10.7852 10.8251 10.7852 11.0204 10.9804C11.2156 11.1757 11.2156 11.4923 11.0204 11.6875L8.35372 14.3542C8.15845 14.5495 7.84187 14.5495 7.64661 14.3542L4.97994 11.6875C4.78468 11.4923 4.78468 11.1757 4.97994 10.9804C5.1752 10.7852 5.49179 10.7852 5.68705 10.9804L6.93113 12.2245C7.14112 12.4345 7.50016 12.2858 7.50016 11.9888V5.33399C7.50016 5.05784 7.72402 4.83399 8.00016 4.83399Z" /> <path d="M8.00016 4.83399C8.27631 4.83399 8.50016 5.05784 8.50016 5.33399V11.9888C8.50016 12.2858 8.85921 12.4345 9.0692 12.2245L10.3133 10.9804C10.5085 10.7852 10.8251 10.7852 11.0204 10.9804C11.2156 11.1757 11.2156 11.4923 11.0204 11.6875L8.35372 14.3542C8.15845 14.5495 7.84187 14.5495 7.64661 14.3542L4.97994 11.6875C4.78468 11.4923 4.78468 11.1757 4.97994 10.9804C5.1752 10.7852 5.49179 10.7852 5.68705 10.9804L6.93113 12.2245C7.14112 12.4345 7.50016 12.2858 7.50016 11.9888V5.33399C7.50016 5.05784 7.72402 4.83399 8.00016 4.83399Z" />
</Icon> </svg>
); );
}
export const DownloadIcon = () => {
return <Icon width={16} height={16} />;
}; };
const Icon = styled.svg` const Icon = styled(DownloadSvg)`
& > path { & > path {
fill: ${({ theme }) => theme.tertiary}; fill: ${({ theme }) => theme.tertiary};
} }