Skip to content

Commit

Permalink
Merge pull request #490 from Accept77/part3-양진수
Browse files Browse the repository at this point in the history
  • Loading branch information
SINHOLEE authored Dec 6, 2023
2 parents 1472169 + 51fdf7d commit f101283
Show file tree
Hide file tree
Showing 56 changed files with 2,797 additions and 536 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": [
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": true
}
]
]
}
40 changes: 0 additions & 40 deletions README.md

This file was deleted.

14 changes: 14 additions & 0 deletions component/api/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import axios from "axios";

const apiUrl = "https://bootcamp-api.codeit.kr/api";

export default async function getApi(path: string) {
try {
const res = await axios.get(`${apiUrl}${path}`);
if (res.status === 200) {
return res.data;
}
} catch (e) {
throw new Error("Unknown error");
}
}
175 changes: 175 additions & 0 deletions component/card/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import styled from "styled-components";
import star from "../../public/images/card/star.png";
import kebab from "../../public/images/card/kebab.svg";
import { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import dateCalculator from "@/utils/dateCalculator";
import { CardProps, CardsProps } from "../../types/type";
import filterItems from "./filterItems";
import { NoLink } from "@/pages/folder";

function Card({ item, setClose, setTag, close }: CardProps) {
const [status, setStatus] = useState(true);

function handlePopOver(tag: string) {
setStatus(!status);
if (setClose !== undefined && setTag !== undefined) {
setClose(!close);
setTag(tag);
}
}

const apiDate = new Date(item.createdAt as string);
const elapsedTime = dateCalculator(apiDate);
const year = apiDate.getFullYear();
const month = apiDate.getMonth() + 1;
const days = apiDate.getDate();
return (
<StyledCardBox>
<StyledHoverImg>
<Image src={star} alt="star" />
</StyledHoverImg>
<Link href={item.url} target="_blank" rel="noopener noreferrer">
<StyledCardImg
$bg={item.imageSource ?? "/images/card/no-image.svg"}
/>
</Link>
<StyledTextBox>
<StyledHoverImg onClick={() => setStatus(!status)}>
<Image src={kebab} alt="kebab" />
</StyledHoverImg>
<StyledPopOverBox $status={status}>
<StyledPopOver onClick={() => handlePopOver("deleteLink")}>
삭제하기
</StyledPopOver>
<StyledPopOver onClick={() => handlePopOver("add")}>
폴더에 추가
</StyledPopOver>
</StyledPopOverBox>
<div>{elapsedTime}</div>
<StyledDescription>{item.description}</StyledDescription>
<div>{`${year}. ${month}. ${days}`}</div>
</StyledTextBox>
</StyledCardBox>
);
}

export default function Cards({
items,
setClose,
setTag,
close,
search,
}: CardsProps) {
if (items === undefined) return;
const newItems = filterItems(items, search);
return (
<StyledCardGrid>
{newItems.length === 0 ? (
<NoLink />
) : (
newItems.map((item) => (
<Card
key={item.id}
item={item}
setClose={setClose}
setTag={setTag}
close={close}
/>
))
)}
</StyledCardGrid>
);
}

const StyledHoverImg = styled.div`
position: absolute;
top: 15px;
right: 15px;
cursor: pointer;
`;

const StyledDescription = styled.div`
text-overflow: ellipsis;
white-space: normal;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
color: #000;
`;

const StyledTextBox = styled.div`
display: flex;
padding: 15px 20px;
flex-direction: column;
gap: 10px;
position: relative;
`;

const StyledCardBox = styled.div`
width: 340px;
background-color: #fff;
border-radius: 15px;
position: relative;
`;

const StyledCardImg = styled.div<{ $bg: string }>`
overflow: hidden;
width: 340px;
height: 253.746px;
background-image: url(${({ $bg }) => $bg});
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border-radius: 15px 15px 0px 0px;
&:hover {
background-size: 160%;
}
`;

const StyledCardGrid = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 25px 20px;
@media (max-width: 767px) {
grid-template-columns: 1fr;
gap: 20px 0;
margin: 0 32px;
align-items: center;
justify-items: center;
}
@media (min-width: 768px) and (max-width: 1124px) {
grid-template-columns: repeat(2, 1fr);
gap: 24px 25px;
margin: 0 32px;
align-items: center;
justify-items: center;
}
`;

const StyledPopOverBox = styled.div<{ $status: boolean }>`
background-color: #fff;
display: flex;
width: 100px;
flex-direction: column;
gap: 2px;
box-shadow: 0px 2px 8px 0px rgba(51, 50, 54, 0.1);
position: absolute;
top: 30px;
right: -60px;
z-index: 1;
text-align: center;
display: ${({ $status }) => ($status ? "none" : "")};
`;

const StyledPopOver = styled.div`
padding: 7px 12px;
font-size: 14px;
&:hover {
background-color: #e7effb;
color: #6d6afe;
}
cursor: pointer;
`;
33 changes: 33 additions & 0 deletions component/card/filterItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { CardItem } from "@/types/type";

export default function filterItems(
items: CardItem[],
search: string | undefined
) {
const filterItems = items.map((item) => {
const newItem = { ...item };
if ("created_at" in newItem && "image_source" in newItem) {
if (
typeof newItem.created_at === "string" ||
typeof newItem.image_source === "string"
) {
newItem.createdAt = newItem.created_at;
delete newItem.created_at;
newItem.imageSource = newItem.image_source!;
delete newItem.image_source;
}
}
return newItem;
});
if (search !== undefined && search !== "") {
const searchItems = filterItems.filter(
(item) =>
(item.title !== null && item.title.search(search) !== -1) ||
(item.url !== null && item.url.search(search) !== -1) ||
(item.description !== null &&
item.description.search(search) !== -1)
);
return searchItems;
}
return filterItems;
}
56 changes: 56 additions & 0 deletions component/common/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import facebookIcon from "../../public/images/footer/facebook-fill.png";
import twitterIcon from "../../public/images/footer/twitter-fill.png";
import youtubeIcon from "../../public/images/footer/youtube-fill.png";
import instagramIcon from "../../public/images/footer/instagram-filled.png";
import styled from "styled-components";
import Image from "next/image";
import Link from "next/link";

export default function Footer() {
return (
<StyledFooterBox>
©codeit - 2023
<StyledFaq>
<Link href="/privacy">Privacy Policy</Link>
<Link href="/faq">FAQ</Link>
</StyledFaq>
<StyledSns>
<Link href="https://www.facebook.com/">
<Image src={facebookIcon} alt="facebook" />
</Link>
<Link href="https://twitter.com/">
<Image src={twitterIcon} alt="twitter" />
</Link>
<Link href="https://www.youtube.com/">
<Image src={youtubeIcon} alt="youtube" />
</Link>
<Link href="https://www.instagram.com/">
<Image src={instagramIcon} alt="instagram" />
</Link>
</StyledSns>
</StyledFooterBox>
);
}

const StyledFooterBox = styled.div`
height: 160px;
padding: 32px 104px 108px;
display: flex;
justify-content: space-between;
align-items: center;
background: #111322;
color: #676767;
`;

const StyledFaq = styled.div`
display: flex;
gap: 30px;
a {
color: #676767;
}
`;

const StyledSns = styled.div`
display: flex;
gap: 12px;
`;
Loading

0 comments on commit f101283

Please sign in to comment.