Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment 7 #6

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 18 additions & 20 deletions velog-clone-react/src/components/Article/index.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import PropTypes from 'prop-types';
import styled from 'styled-components';

import { Tag } from 'components/common';
import { Tag, ImageWrapper } from 'components/common';
import { useNavigate } from 'react-router-dom';

function Article({ articleInfo }) {
const navigator = useNavigate();
const {
title, summary = '', tags = [], date = '', thumbnail = '',
title, summary = '', tags = [], date = '', thumbnail = '', id,
} = articleInfo;

const onClickArticle = () => {
navigator(`/article/${id}`);
};

return (
<StyledArticle>
<StyledArticle onClick={onClickArticle}>
{thumbnail && (
<ThumbnailWrapper>
<ImageWrapper ratio={45}>
<img src={thumbnail} alt="article-thumbnail" />
</ThumbnailWrapper>
</ImageWrapper>
)}
<Title>{title}</Title>
<Summary>{summary}</Summary>
Expand All @@ -26,27 +32,18 @@ function Article({ articleInfo }) {
}

const StyledArticle = styled.article`
width: 800px;
position: relative;
width: 50%;
display: flex;
flex-direction: column;

padding-bottom: 3rem;
margin-bottom: 3rem;
border-bottom: 2px solid lightgray;
`;

const ThumbnailWrapper = styled.div`
position: relative;
overflow: hidden;
padding-top: 50%;

& > img {
position: absolute;
top: 0px;
left: 0px;
width: 60%;
height: 100%;
display: block;
object-fit: cover;
&:hover {
cursor: pointer;
opacity: 0.7;
}
`;

Expand Down Expand Up @@ -77,6 +74,7 @@ Article.propTypes = {
tags: PropTypes.arrayOf(PropTypes.string),
date: PropTypes.string,
thumbnail: PropTypes.string,
id: PropTypes.string,
}).isRequired,
};

Expand Down
8 changes: 4 additions & 4 deletions velog-clone-react/src/components/Navbar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ const UserMenu = styled.div`

& > img {
border-radius: 50%;
overflow: hidden;
overflow: hidden;

width: 2.5rem;
height: 2.5rem;
width: 2.5rem;
height: 2.5rem;
}

& > svg {
width: 1.3rem;
height: 1.3rem;
height: 1.3rem;
}

&:hover {
Expand Down
36 changes: 36 additions & 0 deletions velog-clone-react/src/components/common/index.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PropTypes from 'prop-types';
import styled from 'styled-components';

export const Delimiter = styled.hr`
Expand All @@ -18,3 +19,38 @@ export const Tag = styled.span`
cursor: pointer;
}
`;

export const ImageWrapper = (props) => {
const { ratio, children } = props;
return (
<StyledWrapper ratio={ratio}>
{children}
</StyledWrapper>
);
};

ImageWrapper.propTypes = {
ratio: PropTypes.number,
children: PropTypes.node,
};

ImageWrapper.defaultProps = {
ratio: 62.5,
children: null,
};

const StyledWrapper = styled.div`
position: relative;
overflow: hidden;
padding-top: ${({ ratio }) => ratio}%;

& > img {
position: absolute;
top: 0px;
left: 0px;
width: 60%;
height: 100%;
display: block;
object-fit: cover;
}
`;
5 changes: 4 additions & 1 deletion velog-clone-react/src/core/Router.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom';

import MainPage from 'pages/MainPage';
import WritePage from 'pages/WritePage';
import ArticlePage from 'pages/ArticlePage';

function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<MainPage />}>
<Route path="/series" element={<MainPage />} />
<Route path="/series" />
</Route>
<Route path="/article/:id" element={<ArticlePage />} />
<Route path="/write" element={<WritePage />} />
<Route path="/edit/:id" element={<WritePage mode="edit" />} />
</Routes>
</BrowserRouter>
);
Expand Down
18 changes: 10 additions & 8 deletions velog-clone-react/src/core/api.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import axios from 'axios';

const api = axios.create({
baseURL: 'http://localhost:4000',
export const api = axios.create({
baseURL: 'http://localhost:5000/api',
});

export const imageApi = axios.create({
baseURL: 'http://localhost:5000/api/image',
headers: {
'Content-type': 'multipart/form-data',
},
});

export const getArticle = async () => {
Expand All @@ -17,7 +24,7 @@ export const getArticle = async () => {

export const getSeries = async () => {
try {
const result = await api.get('/series');
const result = await api.get('/article');
const { data } = result;

return data;
Expand All @@ -27,14 +34,9 @@ export const getSeries = async () => {
};

export const postArticle = async (articleData) => {
const today = new Date().toLocaleDateString('ko-kr')
.replace('.', '๋…„')
.replace('.', '์›”')
.replace('.', '์ผ');
try {
await api.post('/article', {
...articleData,
date: today,
});
} catch (error) {
throw new Error('Failed to Post Article.');
Expand Down
7 changes: 5 additions & 2 deletions velog-clone-react/src/core/useInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ function useInput(validate) {
warnText: null,
});

const initialize = (initValue) => setValue(initValue ?? '');

if (!validate) {
const onChange = (e) => setValue(e.target.value);
const initialize = () => setValue('');
return { value, onChange, initialize };
}

Expand All @@ -32,7 +33,9 @@ function useInput(validate) {
}
};

return { value, onChange, validInfo };
return {
value, onChange, validInfo, initialize,
};
}

const StyledWarnText = styled.span`
Expand Down
90 changes: 90 additions & 0 deletions velog-clone-react/src/pages/ArticlePage/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import styled from 'styled-components';

import Navbar from 'components/Navbar';
import UserBoard from 'components/UserBoard';
import Loader from 'components/Loader';
import Article from 'components/Article';
import { api } from 'core/api';

function ArticlePage() {
const navigator = useNavigate();
const [isLoading, setIsLoading] = useState(false);
const [currentArticleData, setCurrentArticleData] = useState();
const { id } = useParams();

useEffect(() => {
async function fetchArticle() {
setIsLoading(true);
const { data } = await api.get(`/article/${id}`);
setCurrentArticleData(data);
setIsLoading(false);
}
fetchArticle();
}, [id]);

const onClickDeleteButton = (e) => {
e.stopPropagation();
api.delete(`/article/${id}`);
navigator('/');
};

const onClickEditButton = (e) => {
e.stopPropagation();
navigator(`/edit/${id}`);
};

return (
<Container>
<Navbar />
<UserBoard />
<ArticleOptions>
<li>
<CommonButton onClick={onClickEditButton}>์ˆ˜์ •</CommonButton>
</li>
<li>
<CommonButton onClick={onClickDeleteButton}>์‚ญ์ œ</CommonButton>
</li>
</ArticleOptions>
<ArticleList>
{isLoading && !currentArticleData && <Loader />}
{!isLoading && currentArticleData && (
<Article articleInfo={currentArticleData} />
)}
</ArticleList>
</Container>

);
}

const Container = styled.main`
width: 100%;
height: 100%;
margin: 0 auto;
`;

const ArticleList = styled.section`
width: 800px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 3rem;
`;

const ArticleOptions = styled.ul`
width: 800px;
display: flex;
gap: 1rem;
margin: 5% auto;
`;

const CommonButton = styled.button`
border: 1px solid black;
border-radius: 18px;
color: white;
background-color: black;
padding: 0.5rem 1rem;
`;

export default ArticlePage;
9 changes: 7 additions & 2 deletions velog-clone-react/src/pages/MainPage/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { useState, useEffect, useRef } from 'react';
import { useLocation, useNavigate, Outlet } from 'react-router-dom';
import styled from 'styled-components';

import Navbar from 'components/Navbar';
Expand All @@ -18,6 +18,7 @@ function MainPage() {
const [currentActive, setCurrentActive] = useState(ROOT);
const location = useLocation();
const navigator = useNavigate();
const prevPathname = useRef(location.pathname);

const getNextActive = (current) => (current === ROOT ? SERIES : ROOT);
const isActiveWithSeries = () => currentActive === SERIES;
Expand All @@ -34,7 +35,10 @@ function MainPage() {
const showArticle = () => currentList
.map((article) => <Article key={article.id} articleInfo={article} />).reverse();

const scrollToTop = () => window.scrollTo(0, 0);

useEffect(() => {
if (location && prevPathname !== location.pathname) scrollToTop();
if (location && location.pathname !== currentActive) setCurrentActive(location.pathname);
}, [currentActive, location]);

Expand Down Expand Up @@ -66,6 +70,7 @@ function MainPage() {
์‹œ๋ฆฌ์ฆˆ
</ArticleType>
</TypeSelector>
<Outlet />
<ArticleList>
{isLoading && <Loader width="50px" />}
{!isLoading && currentList && showArticle()}
Expand Down
Loading