-
Notifications
You must be signed in to change notification settings - Fork 41
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
feat(app, home): 홈페이지 내부를 React 컴포넌트로 분리하고, 공용 레이아웃으로 감싸도록 페이지 내부를 리팩토링합니다. #74
Changes from all commits
3ce8c2f
21eb554
eee902a
dc006d2
2cd24b2
5d2186d
eb39b96
4c60715
bc15bc3
e1fe18b
7cc8f5b
122b906
319d1c1
73124f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export const Footer: React.FC = () => { | ||
return ( | ||
<footer> | ||
<div className="container"> | ||
<a href="/" className="logo-font"> | ||
conduit | ||
</a> | ||
<span className="attribution"> | ||
An interactive learning project from{' '} | ||
<a href="https://thinkster.io">Thinkster</a>. Code & design | ||
licensed under MIT. | ||
</span> | ||
</div> | ||
</footer> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { PropsWithChildren } from 'react'; | ||
import { Navbar } from '../components/NavBar'; | ||
import { Footer } from '../components/Footer'; | ||
|
||
type LayoutProps = PropsWithChildren; | ||
|
||
export const Layout = ({ children }: LayoutProps) => { | ||
return ( | ||
<> | ||
<Navbar /> | ||
{children} | ||
<Footer /> | ||
</> | ||
); | ||
}; | ||
Comment on lines
+7
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. {children} 부분을 react-router-dom의 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
export const Navbar: React.FC = () => { | ||
return ( | ||
<nav className="navbar navbar-light"> | ||
<div className="container"> | ||
<a className="navbar-brand" href="/"> | ||
conduit | ||
</a> | ||
<ul className="nav navbar-nav pull-xs-right"> | ||
<li className="nav-item"> | ||
<a className="nav-link active" href="/"> | ||
Home | ||
</a> | ||
</li> | ||
<li className="nav-item"> | ||
<a className="nav-link" href="/login"> | ||
Sign in | ||
</a> | ||
</li> | ||
<li className="nav-item"> | ||
<a className="nav-link" href="/register"> | ||
Sign up | ||
</a> | ||
</li> | ||
</ul> | ||
</div> | ||
</nav> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
interface ArticlePreviewProps { | ||
authorProfileLink: string; | ||
authorProfileImageUrl: string; | ||
authorName: string; | ||
publishDate: string; | ||
likeCount: number; | ||
articleLink: string; | ||
articleTitle: string; | ||
articleDescription: string; | ||
tags: string[]; | ||
} | ||
Comment on lines
+1
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 타입스크립트를 다룰 때 조금 고통스러운 첫 관문이 interface/type 별칭을 어떤 걸로 가져가야 하는가? 입니다. 앞서 말씀드리자면 interface <> type은 완벽하게 호환되나, 사용처를 명확하게 구분하는 컨벤션을 가져가는 것이 좋습니다. 다른 파일에서 type으로 선언한 부분이 보였는데요, interface의 기준을 세우신 것이 있을까요? 🔍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
아쉽게도 아직은 기준이 없습니다! 아마도 여러 코드들 참고하면서 제 프로젝트 내부적으로 이것저것 사용하게 되는 상황인 것 같고, 두 개의 차이를 찾아보았을 때에도 그래서 뭘 써라 라고 하는 부분은 여전히 애매하더라구요. 이건 추후 오프라인에서 한 번 여쭤보고 싶습니다 ㅎㅎ |
||
|
||
const ArticlePreview: React.FC<ArticlePreviewProps> = ({ | ||
authorProfileLink, | ||
authorProfileImageUrl, | ||
authorName, | ||
publishDate, | ||
likeCount, | ||
articleLink, | ||
articleTitle, | ||
articleDescription, | ||
tags, | ||
}) => ( | ||
Comment on lines
+13
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이러한 props 할당은.... 현재 상황에서는 어쩔 수 없어보이지만요 🥲 모든 값이 required 하기 때문에 차라리 flat한 프로퍼티 값들 보다는 너무 많은 props를 제 3자가 핸들링해야 하는 상황은 썩 유쾌하지 않기 때문에, 개수를 줄이는 것이 효율적이게 됩니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
아하 props 로 넘기는 개수 자체를 줄이는 방식이군요! 이건 추후 개발할 때 반영해보겠습니다 🙏 |
||
<div className="article-preview"> | ||
<div className="article-meta"> | ||
<a href={authorProfileLink}> | ||
<img src={authorProfileImageUrl} /> | ||
</a> | ||
<div className="info"> | ||
<a href={authorProfileLink} className="author"> | ||
{authorName} | ||
</a> | ||
<span className="date">{publishDate}</span> | ||
</div> | ||
<button className="btn btn-outline-primary btn-sm pull-xs-right"> | ||
<i className="ion-heart"></i> {likeCount} | ||
</button> | ||
</div> | ||
<a href={articleLink} className="preview-link"> | ||
<h1>{articleTitle}</h1> | ||
<p>{articleDescription}</p> | ||
<span>Read more...</span> | ||
<ul className="tag-list"> | ||
{tags.map(tag => ( | ||
<li className="tag-default tag-pill tag-outline" key={tag}> | ||
{tag} | ||
</li> | ||
))} | ||
</ul> | ||
</a> | ||
</div> | ||
); | ||
|
||
export default ArticlePreview; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
interface ArticleTagListProps { | ||
tags: string[]; | ||
} | ||
|
||
const ArticleTagList: React.FC<ArticleTagListProps> = ({ tags }) => ( | ||
<div className="col-md-3"> | ||
<div className="sidebar"> | ||
<p>Popular Tags</p> | ||
<div className="tag-list"> | ||
{tags.map(tag => ( | ||
<a key={tag} href="" className="tag-pill tag-default"> | ||
{tag} | ||
</a> | ||
Comment on lines
+11
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. href 부분의 공백은 추후에 놓치실 수 있으니 꼭 유념해주셔야 합니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
오 공백으로 만들어 버렸군요 나중에 제대로 수정해두겠습니다! |
||
))} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
|
||
export default ArticleTagList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export const HomeBanner: React.FC = () => { | ||
return ( | ||
<div className="home-page"> | ||
<div className="banner"> | ||
<div className="container"> | ||
<h1 className="logo-font">conduit</h1> | ||
<p>A place to share your knowledge.</p> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import ArticlePreview from './ArticlePreview'; | ||
import ArticleTagList from './ArticleTagList'; | ||
import HomeFeedTab from './HomeFeedTab'; | ||
import Pagination from './Pagination'; | ||
|
||
const HomeFeedContents: React.FC = () => ( | ||
<div className="container page"> | ||
<div className="row"> | ||
<div className="col-md-9"> | ||
<HomeFeedTab activeFeed="global_feed" /> | ||
{/* 더미 데이터 */} | ||
<ArticlePreview | ||
authorProfileLink="/profile/eric-simons" | ||
authorProfileImageUrl="http://i.imgur.com/Qr71crq.jpg" | ||
authorName="Eric Simons" | ||
publishDate="January 20th" | ||
likeCount={29} | ||
articleLink="/article/how-to-build-webapps-that-scale" | ||
articleTitle="How to build webapps that scale" | ||
articleDescription="This is the description for the post." | ||
tags={['realworld', 'implementations']} | ||
/> | ||
<ArticlePreview | ||
authorProfileLink="/profile/albert-pai" | ||
authorProfileImageUrl="http://i.imgur.com/N4VcUeJ.jpg" | ||
authorName="Albert Pai" | ||
publishDate="January 20th" | ||
likeCount={32} | ||
articleLink="/article/the-song-you" | ||
articleTitle="The song you won't ever stop singing. No matter how hard you try." | ||
articleDescription="This is the description for the post." | ||
tags={['realworld', 'implementations']} | ||
/> | ||
<Pagination pages={[1, 2]} activePage={1} /> | ||
</div> | ||
|
||
<ArticleTagList | ||
tags={[ | ||
'programming', | ||
'javascript', | ||
'emberjs', | ||
'angularjs', | ||
'react', | ||
'mean', | ||
'node', | ||
'rails', | ||
]} | ||
/> | ||
</div> | ||
</div> | ||
); | ||
|
||
export default HomeFeedContents; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
interface HomeFeedTabProps { | ||
activeFeed: 'my_feed' | 'global_feed'; | ||
} | ||
|
||
const HomeFeedTab: React.FC<HomeFeedTabProps> = ({ activeFeed }) => ( | ||
<div className="feed-toggle"> | ||
<ul className="nav nav-pills outline-active"> | ||
<li className="nav-item"> | ||
<a | ||
className={`nav-link ${activeFeed === 'my_feed' ? 'active' : ''}`} | ||
href="" | ||
> | ||
Your Feed | ||
</a> | ||
</li> | ||
<li className="nav-item"> | ||
<a | ||
className={`nav-link ${activeFeed === 'global_feed' ? 'active' : ''}`} | ||
href="" | ||
> | ||
Global Feed | ||
</a> | ||
</li> | ||
</ul> | ||
</div> | ||
); | ||
|
||
export default HomeFeedTab; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
interface HomePageContainerProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
const HomePageContainer: React.FC<HomePageContainerProps> = ({ children }) => { | ||
return <div className="home-page">{children}</div>; | ||
}; | ||
|
||
export default HomePageContainer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
interface PaginationProps { | ||
pages: number[]; | ||
activePage: number; | ||
} | ||
|
||
const Pagination: React.FC<PaginationProps> = ({ pages, activePage }) => { | ||
return ( | ||
<ul className="pagination"> | ||
{pages.map(page => ( | ||
<li | ||
key={page} | ||
className={`page-item ${page === activePage ? 'active' : ''}`} | ||
> | ||
<a className="page-link" href=""> | ||
{page} | ||
</a> | ||
</li> | ||
))} | ||
</ul> | ||
); | ||
}; | ||
|
||
export default Pagination; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 설정이 없으니 props 쪽에서 타입 관련 이슈가 발생하네요. 찾아보니 이걸 끄면 된다고 해서 이번 PR부터 적용했습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prop-types를 직접 할당하는 코드가 있을 때 해당 린트 에러가 발생할텐데... 이상하네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입 설정 없이 props 선언만 빼두었는데도 그렇더라구요..! ㅠ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어랏,,, 저두 요 타입 이슈는 발생하지 않는데 스터디 날에 함께 확인해봐요!! 궁금궁금