Refactor dropdowns (#109)
This commit is contained in:
parent
6db3b9272d
commit
ac77a0ada2
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { useNarrow } from "../../contexts/narrowProvider";
|
||||
|
@ -9,22 +8,8 @@ import { CheckSvg } from "../Icons/CheckIcon";
|
|||
import { ClearSvg } from "../Icons/ClearIcon";
|
||||
import { MembersSmallSvg } from "../Icons/MembersSmallIcon";
|
||||
import { MuteSvg } from "../Icons/MuteIcon";
|
||||
import { textSmallStyles } from "../Text";
|
||||
|
||||
type MenuItemProps = {
|
||||
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>
|
||||
);
|
||||
}
|
||||
import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
|
||||
|
||||
interface ChannelMenuProps {
|
||||
channel: ChannelData;
|
||||
|
@ -43,82 +28,35 @@ export const ChannelMenu = ({
|
|||
const { clearNotifications } = useMessengerContext();
|
||||
|
||||
return (
|
||||
<MenuBlock>
|
||||
<MenuList>
|
||||
<DropdownMenu>
|
||||
{narrow && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
switchMemberList();
|
||||
setShowChannelMenu(false);
|
||||
}}
|
||||
Svg={MembersSmallSvg}
|
||||
text="View Members"
|
||||
/>
|
||||
>
|
||||
<MembersSmallSvg height={16} width={16} />
|
||||
<MenuText>View Members</MenuText>
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
channel.isMuted = true;
|
||||
setShowChannelMenu(false);
|
||||
}}
|
||||
Svg={MuteSvg}
|
||||
text="Mute Chat"
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={() => clearNotifications(channel.id)}
|
||||
Svg={CheckSvg}
|
||||
text="Mark as Read"
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={() => messages.length === 0}
|
||||
Svg={ClearSvg}
|
||||
text="Clear History"
|
||||
/>
|
||||
</MenuList>
|
||||
</MenuBlock>
|
||||
>
|
||||
<MuteSvg height={16} width={16} />
|
||||
<MenuText>Mute Chat</MenuText>
|
||||
</MenuItem>
|
||||
<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}
|
||||
`;
|
||||
|
|
|
@ -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;
|
||||
`;
|
|
@ -4,9 +4,10 @@ import styled from "styled-components";
|
|||
import { useContextMenu } from "../../hooks/useContextMenu";
|
||||
import { copyImg } from "../../utils/copyImg";
|
||||
import { downloadImg } from "../../utils/downloadImg";
|
||||
import { CopyIcon } from "../Icons/CopyIcon";
|
||||
import { DownloadIcon } from "../Icons/DownloadIcon";
|
||||
import { textSmallStyles } from "../Text";
|
||||
import { CopySvg } from "../Icons/CopyIcon";
|
||||
import { DownloadSvg } from "../Icons/DownloadIcon";
|
||||
|
||||
import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
|
||||
|
||||
interface ImageMenuProps {
|
||||
imageId: string;
|
||||
|
@ -16,51 +17,22 @@ export const ImageMenu = ({ imageId }: ImageMenuProps) => {
|
|||
const { showMenu } = useContextMenu(imageId);
|
||||
|
||||
return showMenu ? (
|
||||
<MenuBlock>
|
||||
<MenuList>
|
||||
<ImageDropdown>
|
||||
<MenuItem onClick={() => copyImg(imageId)}>
|
||||
<CopyIcon /> <MenuText>Copy image</MenuText>
|
||||
<CopySvg height={16} width={16} /> <MenuText>Copy image</MenuText>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => downloadImg(imageId)}>
|
||||
<DownloadIcon />
|
||||
<DownloadSvg height={16} width={16} />
|
||||
<MenuText> Download image</MenuText>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</MenuBlock>
|
||||
</ImageDropdown>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
const MenuBlock = styled.div`
|
||||
const ImageDropdown = styled(DropdownMenu)`
|
||||
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;
|
||||
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}
|
||||
`;
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
export const CopyIcon = () => {
|
||||
type CopySvgProps = {
|
||||
width: number;
|
||||
height: number;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function CopySvg({ width, height, className }: CopySvgProps) {
|
||||
return (
|
||||
<Icon
|
||||
width="16"
|
||||
height="16"
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 16 16"
|
||||
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
|
||||
|
@ -15,11 +22,15 @@ export const CopyIcon = () => {
|
|||
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"
|
||||
/>
|
||||
</Icon>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const CopyIcon = () => {
|
||||
return <Icon width={16} height={16} />;
|
||||
};
|
||||
|
||||
const Icon = styled.svg`
|
||||
const Icon = styled(CopySvg)`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.tertiary};
|
||||
}
|
||||
|
|
|
@ -1,21 +1,32 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
export const DownloadIcon = () => {
|
||||
type DownloadSvgProps = {
|
||||
width: number;
|
||||
height: number;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function DownloadSvg({ width, height, className }: DownloadSvgProps) {
|
||||
return (
|
||||
<Icon
|
||||
width="16"
|
||||
height="16"
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 16 16"
|
||||
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="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 {
|
||||
fill: ${({ theme }) => theme.tertiary};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue