반응형
// 현재 URL을 클립보드에 복사하고 알림
export const copyCurrentURL = () => {
let currentUrl = window.document.location.href;
let t = document.createElement("textarea");
document.body.appendChild(t);
t.value = currentUrl;
t.select();
document.execCommand("copy");
document.body.removeChild(t);
alert("링크가 복사되었습니다.");
};
import styled from "@emotion/styled";
import classNames from "classnames";
import { theme } from "../../styles/theme";
import { copyCurrentURL } from "../../utils/common";
import { devices } from "../../styles/devices";
import PuzzleTypography from "./PuzzleTypography";
const Tab = styled.div<{ tab_color: string }>`
//position: sticky;
top: ${({ theme }) => theme.size.navBarHeight};
z-index: 100;
display: flex;
justify-content: space-between;
background-color: ${({ tab_color }) => tab_color};
@media ${devices.mobile} {
top: 0;
padding-top: 0;
}
&::before {
content: "";
display: block;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
background-color: ${({ theme }) => theme.colors.grayD0};
}
&.noUnderline {
&::before {
opacity: 0;
}
}
`;
const Div = styled.div<{ backgroundColor: string }>`
/* 양쪽에 StickyTab Buffer (검색컴포넌트 그림자 숨기기) */
&::before {
content: "";
display: block;
position: absolute;
top: 0;
left: 0px;
transform: translateX(-30px);
width: 30px;
height: 100%;
background-color: ${(props) => props.backgroundColor};
}
&::after {
content: "";
display: block;
position: absolute;
top: 0;
right: 0px;
transform: translateX(30px);
width: 30px;
height: 100%;
background-color: ${(props) => props.backgroundColor};
}
`;
const TabAnchor = styled.button`
color: ${({ theme }) => theme.colors.grayAf};
background-color: ${({ theme }) => theme.colors.white};
position: relative;
display: inline-block;
padding-bottom: 13px;
background: transparent;
border: 0;
appearance: none;
text-decoration: none;
cursor: pointer;
transition: color 0.2s cubic-bezier(0.45, 0, 0.55, 1);
&::after {
content: "";
position: absolute;
bottom: -1px;
left: -2px;
z-index: 2;
width: 105%;
height: 2px;
background-color: ${({ theme }) => theme.colors.black};
opacity: 0;
transition: opacity 0.2s cubic-bezier(0.45, 0, 0.55, 1);
}
&.isActive {
pointer-events: none;
&::after {
opacity: 1;
}
}
&.noUnderline {
&:first-of-type {
padding-left: 0;
}
&::after {
opacity: 0;
}
}
& + & {
margin-left: 40px;
@media ${devices.mobile} {
margin-left: 10px;
}
}
`;
const Share = styled.button`
border: 0px;
background-color: transparent;
cursor: pointer;
&:active {
opacity: 0.3;
}
`;
interface Props {
tabList: string[];
tabColor: string;
tabIndex: number;
setTabIndex: Function;
hasShare?: boolean;
hasUnderline?: boolean; //false인 경우 하단의 회색 라인 없음
backgroundColor: string;
}
const StickyTab = ({
tabList,
tabColor,
tabIndex,
setTabIndex,
hasShare,
hasUnderline,
backgroundColor,
}: Props) => {
return (
<Tab
className={classNames({ noUnderline: !hasUnderline })}
tab_color={tabColor}
>
<Div backgroundColor={backgroundColor}>
{tabList.map((item, i) => {
return (
<TabAnchor
key={i}
className={classNames({
isActive: tabIndex === i,
noUnderline: !hasUnderline,
})}
onClick={() => setTabIndex(i)}
data-testid={`tab-anchor-${i}`}
>
<PuzzleTypography
type={"copy"}
scale={"1"}
color={
tabIndex === i ? theme.colors.black : theme.colors.grayAf
}
>
{item}
</PuzzleTypography>
</TabAnchor>
);
})}
</Div>
{hasShare && (
<Share onClick={() => copyCurrentURL()}>
<PuzzleTypography type={"copy"} scale={"7"}>
공유하기
</PuzzleTypography>
</Share>
)}
</Tab>
);
};
StickyTab.defaultProps = {
tabColor: theme.colors.white,
tabList: [],
tabIndex: 0,
setTabIndex: () => {},
hasShare: false,
hasUnderline: true,
backgroundColor: theme.colors.white,
};
export default StickyTab;
반응형
'프론트엔드 웹 > React' 카테고리의 다른 글
React에서 svg file 사용하는 방법 (0) | 2023.05.03 |
---|---|
PresignedURL 통해서 S3로 이미지 업로드하기 (0) | 2023.03.10 |
React Emoji Not Showing (Window) (0) | 2022.12.19 |
Module not found: Error: You attempted to import /node_modules/react-refresh/runtime.js which falls outside of the project src/ directory (1) | 2022.08.31 |
Promise.all map으로 병렬로 요청하기 (0) | 2022.08.31 |