Skip to content

Commit

Permalink
Merge pull request #467 from SoobinJ/part3-전수빈-week13
Browse files Browse the repository at this point in the history
[전수빈] week13
  • Loading branch information
jayjnu authored Dec 3, 2023
2 parents 1472169 + de98cae commit 6240f39
Show file tree
Hide file tree
Showing 67 changed files with 3,893 additions and 2,200 deletions.
13 changes: 13 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"presets": ["next/babel"],
"plugins": [
[
"babel-plugin-styled-components",
{
"fileName": true,
"displayName": true,
"pure": true
}
]
]
}
71 changes: 71 additions & 0 deletions components/button/AddFloatingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import styled from "styled-components";
import FolderAddWhIcon from "@/public/assets/button/img_add.png";
import { device } from "@/styles/globalStyle";
import Image from "next/image";
import { modalState } from "@/recoil/modal";
import { useRecoilState } from "recoil";

const AddFloatingBtn = () => {
const [, setModalOpened] = useRecoilState(modalState);

return (
<AddFloatingBtnContainer
onClick={() =>
setModalOpened((prev: any) => ({
...prev,
defaultModal: {
display: true,
content: {
id: 0,
title: "",
},
state: "folderAdd",
},
}))
}
>
<div className="floatingBtnTitle">폴더 추가</div>
<Image
width="16"
height="16"
className="floatingBtnIcon"
src={FolderAddWhIcon}
alt="folderAddIcon"
/>
</AddFloatingBtnContainer>
);
};

export default AddFloatingBtn;

const AddFloatingBtnContainer = styled.div`
display: none;
@media all and (${device.mobile}) {
display: flex;
align-items: center;
justify-content: center;
padding: 0.8rem 2.4rem;
border-radius: 2rem;
border: 1px solid #fff;
background: var(--primary);
width: fit-content;
height: 3.7rem;
box-sizing: border-box;
gap: 0.4rem;
position: fixed;
z-index: 5;
bottom: 10.1rem;
margin: 0 auto;
left: 50%;
transform: translate(-50%, 0);
.floatingBtnTitle {
color: var(--gray10);
text-align: center;
font-size: 1.6rem;
font-weight: 500;
letter-spacing: -0.3px;
}
}
`;
35 changes: 35 additions & 0 deletions components/button/DefaultButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import styled from "styled-components";

interface IProps {
children: string;
onClick: (e: React.MouseEvent) => void;
type: "red" | "default";
}

const DefaultBtn = ({ children, onClick, type }: IProps) => {
return (
<DefaultBtnContainer onClick={onClick} type={type}>
{children}
</DefaultBtnContainer>
);
};

export default DefaultBtn;

export const DefaultBtnContainer = styled.button<{ type: string }>`
border-radius: 0.8rem;
background: ${(props) =>
props.type === "red"
? "var(--red)"
: "linear-gradient(91deg, var(--primary) 0.12%, #6ae3fe 101.84%)"};
color: #f5f5f5;
padding: 1.6rem 2rem;
font-size: 1.8rem;
font-weight: 600;
line-height: 2.2rem;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
`;
165 changes: 165 additions & 0 deletions components/card/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import moment from "moment";
import LogoImg from "@/public/assets/common/img_logo.png";
import {
CardContainer,
CardImgContainer,
CardWrapper,
ContentContainer,
OptionMenuContainer,
} from "./cardStyled";
import OptionIcon from "@/public/assets/card/img_option.png";
import StarIcon from "@/public/assets/card/img_star.png";
import { useState } from "react";
import Image from "next/image";

const calculateTimeAgo = (createdAt: string) => {
const createdDate = moment(createdAt, "YYYY-MM-DDTHH:mm:ss[Z]");
const currentDate = moment();
const diff = currentDate.diff(createdDate, "seconds");

if (diff < 120) {
return "1 minute ago";
} else if (diff <= 3540) {
return `${Math.floor(diff / 60)} minutes ago`;
} else if (diff < 3600) {
return "1 hour ago";
} else if (diff <= 82800) {
return `${Math.floor(diff / 3600)} hours ago`;
} else if (diff < 86400) {
return "1 day ago";
} else if (diff <= 2592000) {
return `${Math.floor(diff / 86400)} days ago`;
} else if (diff <= 28512000) {
return `${Math.floor(diff / 2592000)} months ago`;
} else if (diff <= 31536000) {
return "1 year ago";
} else {
return `${Math.floor(diff / 31536000)} years ago`;
}
};

interface ICardProp {
cardData: any;
onClickDelete?: any;
onClickAdd?: any;
isFolder: boolean;
}

const Card = ({ cardData, onClickDelete, onClickAdd, isFolder }: ICardProp) => {
const ago = calculateTimeAgo(cardData.created_at || cardData.createdAt);
const createdAtFormat = moment(
cardData.created_at || cardData.createdAt
).format("YYYY.MM.DD");
const [isOpenOption, setIsOpenOption] = useState(false);

const openUrl = () => {
window.open(cardData.url, "__blank");
};

return (
<CardWrapper>
<CardContainer onClick={openUrl}>
{cardData.image_source || cardData.imageSource ? (
<CardImgContainer>
<Image
priority
className="cardImage"
src={cardData.image_source || cardData.imageSource}
alt="cardImg"
fill
/>
{isFolder && (
<Image
src={StarIcon}
className="starIcon"
alt="starIcon"
width="34"
height="34"
/>
)}
</CardImgContainer>
) : (
<CardImgContainer>
<Image
priority
src={LogoImg}
alt="logoImg"
className="noImgLogo"
width="133"
height="24"
/>
{isFolder && (
<Image
src={StarIcon}
className="starIcon"
alt="starIcon"
width="34"
height="34"
/>
)}
</CardImgContainer>
)}

<ContentContainer>
<div className="contentOptionContainer">
<div className="contentAgo">{ago}</div>
{isFolder && (
<Image
className="optionBtn"
src={OptionIcon}
alt="optionIcon"
width="21"
height="17"
onClick={(e) => {
e.stopPropagation();
setIsOpenOption(!isOpenOption);
}}
/>
)}
</div>
<div className="content">{cardData.description}</div>
<div className="contentAt">{createdAtFormat}</div>
</ContentContainer>
</CardContainer>

{isOpenOption && (
<OptionMenu
onClickDelete={onClickDelete}
onClickAdd={onClickAdd}
content={{ id: cardData.id, title: cardData.url }}
/>
)}
</CardWrapper>
);
};

export default Card;

interface IOptionMenuProp {
onClickDelete: any;
onClickAdd: any;
content: {
id: number;
title: string;
};
}

const OptionMenu = ({
onClickDelete,
onClickAdd,
content,
}: IOptionMenuProp) => {
return (
<OptionMenuContainer>
<div
className="optionMenuItem"
onClick={() => onClickDelete("linkDelete", content)}
>
삭제하기
</div>
<div className="optionMenuItem" onClick={() => onClickAdd()}>
폴더에 추가
</div>
</OptionMenuContainer>
);
};
Loading

0 comments on commit 6240f39

Please sign in to comment.