Skip to content

Commit

Permalink
Merge pull request #365 from grapefruit13/part3-허우림-week12
Browse files Browse the repository at this point in the history
[허우림] week12
  • Loading branch information
soonoo27 authored Jan 9, 2024
2 parents 1472169 + 298f569 commit 765ace5
Show file tree
Hide file tree
Showing 77 changed files with 3,292 additions and 792 deletions.
28 changes: 27 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
{
"extends": "next/core-web-vitals"
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"parserOptions": {
"project": "./tsconfig.json",
"createDefaultProgram": true
},
"env": {
"browser": true,
"node": true,
"es6": true
},
"ignorePatterns": ["node_modules/"],
"extends": [
"airbnb",
"airbnb-typescript",
"airbnb/hooks",
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
"rules": {
"react/react-in-jsx-scope": "off",
"react/jsx-filename-extension": ["warn", { "extensions": [".ts", ".tsx"] }],
"no-useless-catch": "off"
}
}
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}
114 changes: 114 additions & 0 deletions components/common/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { useContext, useEffect, useState } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import { calCreatedAt, calCreatedDates } from '../../utils/date';
import { KebabContextProvider } from '../../contexts/KebabContext';
import CardContext from '../../contexts/CardContext';
import NoImg from '@/public/assets/icons/card/card_no-img.svg';
import kebab from '@/public/assets/icons/card/kebab.svg';
import CardInfo from './CardInfo';
import styles from '@/styles/card/card.module.css';
interface Props {
id: string;
createdAt: string;
url: string;
title: string;
description: string;
imageSource: string;
}

export default function Card({ link }: { link: Props }) {
const { setLinkInfo } = useContext(CardContext);
const { id, createdAt, url, title, description, imageSource } = link;
const [mins, setMins] = useState('');
const [createdDates, setCreatedDates] = useState({
year: '',
month: '',
day: '',
});
const [isHovered, setIsHovered] = useState(false);

const handleSetLinkInfo = () => {
setLinkInfo({
id: id,
createdAt: createdAt,
url: url,
title: title,
description: description,
imageSource: imageSource,
});
};

const getCreatedDates = () => {
const [year, month, day] = calCreatedDates(createdAt);
setCreatedDates((prev) => ({
...prev,
year: year,
month: month,
day: day,
}));
};

const getCreatedAt = () => {
setMins(calCreatedAt(createdDates));
};

useEffect(() => {
handleSetLinkInfo();
}, []);

useEffect(() => {
getCreatedDates();
}, [createdAt]);

useEffect(() => {
getCreatedAt();
}, [createdDates]);

return (
<>
<KebabContextProvider>
<div className={styles.flexWrapper} id={`card-${id}`}>
<div className={styles.cardImgWrapper}>
<Link target="_blank" href={url}>
{imageSource ? (
<Image
className={
isHovered
? `${styles.cardImg} ${styles.grow}`
: styles.cardImg
}
width={500}
height={253}
src={imageSource}
alt={`${title}-img`}
onMouseEnter={() => {
setIsHovered(true);
}}
onMouseLeave={() => {
setIsHovered(false);
}}
/>
) : (
<Image
className={styles.cardImg}
width={500}
height={253}
src={NoImg}
alt={`${title}-img`}
/>
)}
</Link>
</div>
<CardInfo
mins={mins}
imgSrc={kebab}
title={title}
description={description}
createdDates={createdDates}
/>
</div>
</KebabContextProvider>
</>
);
}
59 changes: 59 additions & 0 deletions components/common/CardInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Image from 'next/image';
import { useContext, useReducer } from 'react';
import Dropdown from './folderPage/Dropdown';
import KebabContext from '../../contexts/KebabContext';
import styles from '@/styles/card/card.module.css';
import { useRouter } from 'next/router';

interface Props {
mins: string;
imgSrc: string;
title: string;
description: string;
createdDates: {
year: string;
month: string;
day: string;
};
}

export default function CardInfo({
mins,
imgSrc,
title,
description,
createdDates,
}: Props) {
const { setIsKebabClicked, isKebabClicked } = useContext(KebabContext);
const router = useRouter();

const handleKebabClick = () => {
if (router.pathname !== '/') {
setIsKebabClicked((prev: boolean) => !prev);
}
};

return (
<div className={styles.cardInfoContainer}>
<div className={styles.timesAgoWrapper}>
<div className={styles.mins}>{mins}</div>
<Image
width={21}
height={17}
src={imgSrc}
alt="kebab"
onClick={handleKebabClick}
style={router.pathname !== '/' ? { cursor: 'pointer' } : undefined}
/>
{isKebabClicked && <Dropdown />}
</div>
<div>
<div className={styles.title}>{title}</div>
<div className={styles.description}>{description}</div>
</div>
<div className={styles.created}>
{createdDates.year}. {createdDates.month}. {createdDates.day}
</div>
</div>
);
}
30 changes: 30 additions & 0 deletions components/common/CardWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { CardContextProvider } from '../../contexts/CardContext';
import Card from './Card';
import styles from '@/styles/card/cardWrapper.module.css';

interface Props {
links: {
id: string;
createdAt: string;
url: string;
title: string;
imageSource: string;
description: string;
}[];
}

export default function CardWrapper({ links }: Props) {
return (
<div className={styles.wrapper}>
{links.map((link) => {
return (
<div key={link.id}>
<CardContextProvider>
<Card link={link} />
</CardContextProvider>
</div>
);
})}
</div>
);
}
37 changes: 37 additions & 0 deletions components/common/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Sns from './Sns';
import FooterSnsDatas from './FooterSnsDatas';
import styles from '@/styles/footer/footer.module.css';
import Link from 'next/link';

export default function Footer() {
const getThisYear = () => {
const date = new Date();
const thisYear = date.getFullYear();
return thisYear;
};

return (
<>
<div className={styles.wrapper}>
<span className={styles.codeit}>©codeit - {getThisYear()}</span>
<div className={styles.info}>
<span className={styles.privacy}>
<Link href="/privacy">Privacy Policy</Link>
</span>
<span className={styles.faq}>
<Link href="/faq">FAQ</Link>
</span>
</div>
<div className={styles.sns}>
{FooterSnsDatas.map((data) => {
return (
<div key={`sns-${data.id}`}>
<Sns footerSnsData={data} />
</div>
);
})}
</div>
</div>
</>
);
}
23 changes: 23 additions & 0 deletions components/common/FooterSnsDatas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import facebook from '/public/assets/icons/footer/facebook.png';
import twitter from '/public/assets/icons/footer/twitter.png';
import instagram from '/public/assets/icons/footer/instagram.png';
import youtube from '/public/assets/icons/footer/youtube.png';

export const FooterSnsDatas = [
{ id: 1, name: 'facebook', url: 'https://www.facebook.com', img: facebook },
{ id: 2, name: 'twitter', url: 'https://www.twitter.com', img: twitter },
{
id: 3,
name: 'youtube',
url: 'https://www.youtube.com',
img: youtube,
},
{
id: 4,
name: 'instagram',
url: 'https://www.instagram.com',
img: instagram,
},
];

export default FooterSnsDatas;
45 changes: 45 additions & 0 deletions components/common/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Image from 'next/image';
import LoginButton from './LoginButton';
import Logo from './Logo';
import styles from '@/styles/header/header.module.css';

interface Props {
profileDatas: {
id: number;
created_at?: string;
name: string;
image_source: string;
email: string;
auth_id?: string;
};
}

export default function Header({ profileDatas }: Props) {
const {
name = 'defaultName',
image_source = 'https://images.unsplash.com/photo-1701600713610-0f724c65168d?q=80&w=1074&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
email = '[email protected]',
} = profileDatas;

return (
<div className={styles.header}>
<div className={styles.nav}>
<Logo />
{name ? (
<div className={styles.profile}>
<Image
className={styles.profileImg}
src={image_source}
width={28}
height={28}
alt={name}
/>
<p className={styles.profileName}>{email}</p>
</div>
) : (
<LoginButton />
)}
</div>
</div>
);
}
14 changes: 14 additions & 0 deletions components/common/LoginButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styles from '@/styles/header/header.module.css';
import Link from 'next/link';

export default function LoginButton() {
return (
<>
<Link href="/signin">
<button className={`${styles.loginBtn} ${styles.button}`}>
로그인
</button>
</Link>
</>
);
}
Loading

0 comments on commit 765ace5

Please sign in to comment.