@@ -51,4 +51,4 @@ const MainRightFooter: React.FC
= props => {
);
};
-export default MainRightFooter;
+export default HomeRightFooter;
diff --git a/src/components/home/HomeSidebar.tsx b/src/components/home/HomeSidebar.tsx
index 9495daac..721144f5 100644
--- a/src/components/home/HomeSidebar.tsx
+++ b/src/components/home/HomeSidebar.tsx
@@ -1,8 +1,8 @@
import React from 'react';
import styled from 'styled-components';
-import MainNoticeWidgetContainer from '../../containers/main/MainNoticeWidgetContainer';
-import MainTagWidgetContainer from '../../containers/main/MainTagWidgetContainer';
-import MainRightFooter from '../main/MainRightFooter';
+import MainNoticeWidgetContainer from '../../containers/home/MainNoticeWidgetContainer';
+import MainTagWidgetContainer from '../../containers/home/MainTagWidgetContainer';
+import HomeRightFooter from './HomeRightFooter';
import Sticky from '../common/Sticky';
export type HomeSidebarProps = {};
@@ -13,7 +13,7 @@ function HomeSidebar(props: HomeSidebarProps) {
-
+
);
diff --git a/src/components/home/HomeTab.tsx b/src/components/home/HomeTab.tsx
index 86498a62..53b72dc4 100644
--- a/src/components/home/HomeTab.tsx
+++ b/src/components/home/HomeTab.tsx
@@ -6,7 +6,7 @@ import { MdTrendingUp, MdAccessTime, MdMoreVert } from 'react-icons/md';
import { useSpring, animated } from 'react-spring';
import { mediaQuery } from '../../lib/styles/media';
import useToggle from '../../lib/hooks/useToggle';
-import MainMobileHeadExtra from '../../components/main/MainMobileHeadExtra';
+import HomeMobileHeadExtra from './HomeMobileHeadExtra';
export type HomeTabProps = {};
@@ -58,7 +58,7 @@ function HomeTab(props: HomeTabProps) {
-
+
);
}
@@ -100,7 +100,7 @@ const Block = styled.div`
font-size: 1.125rem;
text-decoration: none;
color: ${palette.gray6};
- height: 2.875rem;
+ height: 3rem;
svg {
font-size: 1.5rem;
diff --git a/src/components/main/MainTagWidget.tsx b/src/components/home/HomeTagWidget.tsx
similarity index 84%
rename from src/components/main/MainTagWidget.tsx
rename to src/components/home/HomeTagWidget.tsx
index ebf27711..d22d949e 100644
--- a/src/components/main/MainTagWidget.tsx
+++ b/src/components/home/HomeTagWidget.tsx
@@ -1,15 +1,15 @@
import React from 'react';
import styled from 'styled-components';
-import MainWidget from './MainWidget';
+import HomeWidget from './HomeWidget';
import palette from '../../lib/styles/palette';
import { Link } from 'react-router-dom';
import Skeleton from '../common/Skeleton';
-export type MainTagWidgetProps = {
+export type HomeTagWidgetProps = {
tags: string[];
};
-function MainTagWidget({ tags }: MainTagWidgetProps) {
+function HomeTagWidget({ tags }: HomeTagWidgetProps) {
return (
@@ -26,7 +26,7 @@ function MainTagWidget({ tags }: MainTagWidgetProps) {
);
}
-export function MainTagWidgetSkeleton() {
+export function HomeTagWidgetSkeleton() {
return (
@@ -40,7 +40,7 @@ export function MainTagWidgetSkeleton() {
);
}
-const StyledWidget = styled(MainWidget)`
+const StyledWidget = styled(HomeWidget)`
ul {
list-style: none;
padding-left: 0;
@@ -72,4 +72,4 @@ const StyledWidget = styled(MainWidget)`
}
`;
-export default MainTagWidget;
+export default HomeTagWidget;
diff --git a/src/components/home/HomeTemplate.tsx b/src/components/home/HomeTemplate.tsx
deleted file mode 100644
index 5ace3bdb..00000000
--- a/src/components/home/HomeTemplate.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import styled, { createGlobalStyle } from 'styled-components';
-import palette from '../../lib/styles/palette';
-import { Link } from 'react-router-dom';
-
-const BackgroundStyle = createGlobalStyle`
- body {
- background: ${palette.gray0};
- }
-`;
-
-export type HomeTemplateProps = {
- children: React.ReactNode;
-};
-
-function HomeTemplate({ children }: HomeTemplateProps) {
- return (
- <>
-
- {children}
- >
- );
-}
-
-const Block = styled.div``;
-
-export default HomeTemplate;
diff --git a/src/components/main/MainWidget.tsx b/src/components/home/HomeWidget.tsx
similarity index 83%
rename from src/components/main/MainWidget.tsx
rename to src/components/home/HomeWidget.tsx
index 821a9886..0927954e 100644
--- a/src/components/main/MainWidget.tsx
+++ b/src/components/home/HomeWidget.tsx
@@ -2,13 +2,13 @@ import React from 'react';
import styled from 'styled-components';
import palette from '../../lib/styles/palette';
-export type MainWidgetProps = {
+export type HomeWidgetProps = {
title: string;
children: React.ReactNode;
className?: string;
};
-function MainWidget({ title, children, className }: MainWidgetProps) {
+function HomeWidget({ title, children, className }: HomeWidgetProps) {
return (
{title}
@@ -33,4 +33,4 @@ const MainWidgetBlock = styled.section`
}
`;
-export default MainWidget;
+export default HomeWidget;
diff --git a/src/components/main/FloatingHomeHeader.tsx b/src/components/main/FloatingHomeHeader.tsx
new file mode 100644
index 00000000..e22db2e8
--- /dev/null
+++ b/src/components/main/FloatingHomeHeader.tsx
@@ -0,0 +1,124 @@
+import React, { useEffect, useCallback, useRef, useState } from 'react';
+import styled from 'styled-components';
+import MainHeader from './MainHeader';
+import HomeTab from '../home/HomeTab';
+import MainResponsive from './MainResponsive';
+import { getScrollTop } from '../../lib/utils';
+import { Route } from 'react-router-dom';
+import ReadingListTab from '../readingList/ReadingListTab';
+
+export type FloatingMainHeaderProps = {};
+
+function FloatingMainHeader(props: FloatingMainHeaderProps) {
+ const [visible, setVisible] = useState(false);
+ const blockRef = useRef(null);
+ const [height, setHeight] = useState(0);
+ const [marginTop, setMarginTop] = useState(0);
+ useEffect(() => {
+ if (!blockRef.current) return;
+ setHeight(blockRef.current.clientHeight);
+ setMarginTop(-1 * blockRef.current.clientHeight);
+ }, []);
+
+ const prevScrollTop = useRef(0);
+ const direction = useRef<'UP' | 'DOWN'>('DOWN');
+ const transitionPoint = useRef(0);
+
+ const onScroll = useCallback(() => {
+ const scrollTop = getScrollTop();
+ const nextDirection = prevScrollTop.current > scrollTop ? 'UP' : 'DOWN';
+
+ if (
+ direction.current === 'DOWN' &&
+ nextDirection === 'UP' &&
+ transitionPoint.current - scrollTop < 0
+ ) {
+ setVisible(true);
+ transitionPoint.current = scrollTop;
+ }
+
+ if (
+ direction.current === 'UP' &&
+ nextDirection === 'DOWN' &&
+ scrollTop - transitionPoint.current < -1 * height
+ ) {
+ transitionPoint.current = scrollTop + height;
+ }
+
+ if (scrollTop < 64) {
+ setVisible(false);
+ }
+
+ setMarginTop(
+ Math.min(0, -1 * height + transitionPoint.current - scrollTop),
+ );
+
+ direction.current = nextDirection;
+ prevScrollTop.current = scrollTop;
+ }, [height]);
+
+ useEffect(() => {
+ document.addEventListener('scroll', onScroll);
+ return () => {
+ document.removeEventListener('scroll', onScroll);
+ };
+ }, [onScroll]);
+
+ return (
+
+
+ (
+
+
+
+
+
+ )}
+ exact
+ />
+ (
+
+
+
+ )}
+ exact
+ />
+
+ );
+}
+
+const Block = styled.div`
+ position: fixed;
+ top: 0;
+ background: white;
+ width: 100%;
+ z-index: 10;
+
+ box-shadow: 0px 0 8px rgba(0, 0, 0, 0.08);
+ .tab-wrapper {
+ margin-top: -2rem;
+ }
+`;
+
+const StyledMainResponsive = styled(MainResponsive)`
+ margin-top: 1.5rem;
+`;
+
+export default FloatingMainHeader;
diff --git a/src/components/home/HomeHeader.tsx b/src/components/main/MainHeader.tsx
similarity index 85%
rename from src/components/home/HomeHeader.tsx
rename to src/components/main/MainHeader.tsx
index 1a10527d..44f89710 100644
--- a/src/components/home/HomeHeader.tsx
+++ b/src/components/main/MainHeader.tsx
@@ -2,24 +2,26 @@ import React from 'react';
import styled from 'styled-components';
import { Logo, SearchIcon2 } from '../../static/svg';
import RoundButton from '../common/RoundButton';
-import HomeResponsive from './HomeResponsive';
-import useHeader from './hooks/useHeader';
+import MainResponsive from './MainResponsive';
+import useHeader from '../home/hooks/useHeader';
import HeaderUserIcon from '../base/HeaderUserIcon';
import useToggle from '../../lib/hooks/useToggle';
import HeaderUserMenu from '../base/HeaderUserMenu';
import { Link } from 'react-router-dom';
import { mediaQuery } from '../../lib/styles/media';
-export type HomeHeaderProps = {};
+export type MainHeaderProps = {};
-function HomeHeader(props: HomeHeaderProps) {
+function MainHeader(props: MainHeaderProps) {
const { user, onLoginClick, onLogout } = useHeader();
const [userMenu, toggleUserMenu] = useToggle(false);
return (
-
+
+
+
{user ? (
@@ -62,6 +64,11 @@ const Block = styled.div`
height: 4rem;
`;
+const StyledLink = styled(Link)`
+ display: flex;
+ align-items: center;
+`;
+
const SearchButton = styled(Link)`
display: flex;
align-items: center;
@@ -83,7 +90,7 @@ const SearchButton = styled(Link)`
margin-right: 0.75rem;
`;
-const Inner = styled(HomeResponsive)`
+const Inner = styled(MainResponsive)`
height: 100%;
display: flex;
align-items: center;
@@ -101,4 +108,4 @@ const Right = styled.div`
}
`;
-export default HomeHeader;
+export default MainHeader;
diff --git a/src/components/main/MainMobileHead.tsx b/src/components/main/MainMobileHead.tsx
deleted file mode 100644
index 0863f3bc..00000000
--- a/src/components/main/MainMobileHead.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import React, { useState, useRef } from 'react';
-import {
- MdTrendingUp,
- MdAccessTime /*, MdRssFeed */,
- MdMoreVert,
-} from 'react-icons/md';
-import styled from 'styled-components';
-import { NavLink } from 'react-router-dom';
-import palette from '../../lib/styles/palette';
-import media from '../../lib/styles/media';
-import MainMobileHeadExtra from './MainMobileHeadExtra';
-import useToggle from '../../lib/hooks/useToggle';
-
-export type MainMobileHeadProps = {};
-
-function MainMobileHead(props: MainMobileHeadProps) {
- const [extra, toggle] = useToggle(false);
- const moreButtonRef = useRef(null);
-
- const onClose = (e: React.MouseEvent) => {
- if (!moreButtonRef.current) return;
- if (
- e.target === moreButtonRef.current ||
- moreButtonRef.current.contains(e.target as Node)
- ) {
- return;
- }
- toggle();
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-const Section = styled.section`
- position: relative;
- display: none;
- align-items: center;
- justify-content: space-between;
- width: 100%;
- margin-bottom: 1.5rem;
- .menu {
- display: flex;
- }
- .more {
- font-size: 1.5rem;
- color: ${palette.gray6};
- }
-
- ${media.medium} {
- display: flex;
- }
-`;
-
-const MenuItem = styled(NavLink)`
- width: 5rem;
- height: 2rem;
- display: flex;
- align-items: center;
- justify-content: center;
- text-decoration: none;
- font-weight: 600;
- svg {
- font-size: 1.125rem;
- margin-right: 0.5rem;
- }
- font-size: 0.875rem;
- border-bottom: 2px solid transparent;
- color: ${palette.gray7};
- &.active {
- background: ${palette.teal0};
- color: ${palette.teal6};
- border-bottom: 2px solid ${palette.teal6};
- }
-`;
-
-export default MainMobileHead;
diff --git a/src/components/main/MainPageTemplate.tsx b/src/components/main/MainPageTemplate.tsx
new file mode 100644
index 00000000..966eaf87
--- /dev/null
+++ b/src/components/main/MainPageTemplate.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import MainTemplate from './MainTemplate';
+import MainHeader from './MainHeader';
+import FloatingMainHeader from './FloatingHomeHeader';
+
+export type MainPageTemplateProps = {
+ children?: React.ReactNode;
+};
+
+function MainPageTemplate({ children }: MainPageTemplateProps) {
+ return (
+
+
+
+ {children}
+
+ );
+}
+
+export default MainPageTemplate;
diff --git a/src/components/home/HomeResponsive.tsx b/src/components/main/MainResponsive.tsx
similarity index 81%
rename from src/components/home/HomeResponsive.tsx
rename to src/components/main/MainResponsive.tsx
index fff46d05..ae0d3205 100644
--- a/src/components/home/HomeResponsive.tsx
+++ b/src/components/main/MainResponsive.tsx
@@ -2,12 +2,12 @@ import React from 'react';
import styled from 'styled-components';
import { mediaQuery } from '../../lib/styles/media';
-export type HomeResponsiveProps = {
+export type MainResponsiveProps = {
className?: string;
children: React.ReactNode;
};
-function HomeResponsive({ className, children }: HomeResponsiveProps) {
+function MainResponsive({ className, children }: MainResponsiveProps) {
return {children};
}
@@ -32,4 +32,4 @@ const Block = styled.div`
}
`;
-export default HomeResponsive;
+export default MainResponsive;
diff --git a/src/components/main/MainSideMenu.tsx b/src/components/main/MainSideMenu.tsx
deleted file mode 100644
index b8fd6a3b..00000000
--- a/src/components/main/MainSideMenu.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-import { NavLink, RouteComponentProps, withRouter } from 'react-router-dom';
-import palette from '../../lib/styles/palette';
-import { MdTrendingUp, MdAccessTime /*, MdRssFeed */ } from 'react-icons/md';
-import SearchInput from '../search/SearchInput';
-
-const MainSideMenuBlock = styled.div`
- position: sticky;
- top: 96px;
- display: flex;
- flex-direction: column;
-`;
-const MenuItem = styled(NavLink)`
- display: flex;
- color: ${palette.gray8};
- text-decoration: none;
- height: 48px;
- align-items: center;
- padding-left: 1rem;
- font-size: 1.125rem;
- border-left: 3px solid transparent;
- transition: 0.125s all ease-in;
- svg {
- margin-right: 1rem;
- font-size: 1.5rem;
- }
- &.active {
- background: ${palette.teal0};
- border-color: ${palette.teal6};
- color: ${palette.teal6};
- font-weight: bold;
- }
-`;
-
-const StyledSearchInput = styled(SearchInput)`
- margin-bottom: 1.5rem;
-`;
-
-interface MainSideMenuProps extends RouteComponentProps {}
-
-const MainSideMenu: React.FC = ({ history }) => {
- const onSearch = (keyword: string) => {
- history.push(`/search/?q=${keyword}`);
- };
-
- return (
-
-
-
-
- {/* */}
-
- );
-};
-
-export default withRouter(MainSideMenu);
diff --git a/src/components/main/MainTemplate.tsx b/src/components/main/MainTemplate.tsx
index d35fe30a..95f5fc9e 100644
--- a/src/components/main/MainTemplate.tsx
+++ b/src/components/main/MainTemplate.tsx
@@ -1,73 +1,27 @@
-import * as React from 'react';
-import styled from 'styled-components';
-import PageTemplate from '../base/PageTemplate';
-import media from '../../lib/styles/media';
+import React from 'react';
+import styled, { createGlobalStyle } from 'styled-components';
+import palette from '../../lib/styles/palette';
+import { Link } from 'react-router-dom';
-const MainTemplateBlock = styled(PageTemplate)`
- main {
- width: 1200px;
- ${media.large} {
- width: 1024px;
- }
- margin: 0 auto;
- margin-top: 3.5rem;
- margin-bottom: 8rem;
- display: flex;
- justify-content: space-between;
- ${media.medium} {
- justify-content: center;
- width: 100%;
- margin-top: 1rem;
- }
+const BackgroundStyle = createGlobalStyle`
+ body {
+ background: ${palette.gray0};
}
`;
-const Left = styled.div`
- width: 192px;
- ${media.medium} {
- display: none;
- }
-`;
-const Main = styled.div`
- width: 702px;
- ${media.large} {
- width: 526px;
- }
- ${media.medium} {
- width: 768px;
- }
- ${media.small} {
- width: 100%;
- padding-left: 1rem;
- padding-right: 1rem;
- }
-`;
-const Right = styled.div`
- width: 240px;
- ${media.medium} {
- display: none;
- }
-`;
-
-type MainTemplateNamespace = {
- Left: typeof Left;
- Main: typeof Main;
- Right: typeof Right;
+export type MainTemplateProps = {
+ children: React.ReactNode;
};
-interface MainTemplateProps {}
-const MainTemplate: React.FC & MainTemplateNamespace = ({
- children,
-}) => {
+function MainTemplate({ children }: MainTemplateProps) {
return (
-
- {children}
-
+ <>
+
+ {children}
+ >
);
-};
+}
-MainTemplate.Left = Left;
-MainTemplate.Main = Main;
-MainTemplate.Right = Right;
+const Block = styled.div``;
export default MainTemplate;
diff --git a/src/components/readingList/ReadingListTab.tsx b/src/components/readingList/ReadingListTab.tsx
new file mode 100644
index 00000000..ccd0aa70
--- /dev/null
+++ b/src/components/readingList/ReadingListTab.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import HorizontalTab from '../common/HorizontalTab';
+
+export type ReadingListTabProps = {
+ type: 'liked' | 'read';
+};
+
+function ReadingListTab({ type }: ReadingListTabProps) {
+ return (
+
+
+
+
+ );
+}
+
+export default ReadingListTab;
diff --git a/src/containers/main/MainNoticeWidgetContainer.tsx b/src/containers/home/MainNoticeWidgetContainer.tsx
similarity index 67%
rename from src/containers/main/MainNoticeWidgetContainer.tsx
rename to src/containers/home/MainNoticeWidgetContainer.tsx
index e290582a..21542ee0 100644
--- a/src/containers/main/MainNoticeWidgetContainer.tsx
+++ b/src/containers/home/MainNoticeWidgetContainer.tsx
@@ -1,7 +1,7 @@
import React from 'react';
-import MainNoticeWidget, {
- MainNoticeWidgetSkeleton,
-} from '../../components/main/MainNoticeWidget';
+import HomeNoticeWidget, {
+ HomeNoticeWidgetSkeleton,
+} from '../../components/home/HomeNoticeWidget';
import { useQuery } from '@apollo/react-hooks';
import { GET_POST_LIST, PartialPost } from '../../lib/graphql/post';
@@ -15,9 +15,9 @@ function MainNoticeWidgetContainer(props: MainNoticeWidgetContainerProps) {
},
});
- if (!data || !data.posts) return ;
+ if (!data || !data.posts) return ;
- return ;
+ return ;
}
export default MainNoticeWidgetContainer;
diff --git a/src/containers/main/MainTagWidgetContainer.tsx b/src/containers/home/MainTagWidgetContainer.tsx
similarity index 75%
rename from src/containers/main/MainTagWidgetContainer.tsx
rename to src/containers/home/MainTagWidgetContainer.tsx
index b375c065..49932616 100644
--- a/src/containers/main/MainTagWidgetContainer.tsx
+++ b/src/containers/home/MainTagWidgetContainer.tsx
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
-import MainTagWidget, {
- MainTagWidgetSkeleton,
-} from '../../components/main/MainTagWidget';
+import HomeTagWidget, {
+ HomeTagWidgetSkeleton,
+} from '../../components/home/HomeTagWidget';
import { useQuery } from '@apollo/react-hooks';
import { GET_TAGS, GetTagsResponse } from '../../lib/graphql/tags';
@@ -20,9 +20,9 @@ function MainTagWidgetContainer(props: MainTagWidgetContainerProps) {
[data],
);
- if (!tags) return ;
+ if (!tags) return ;
- return ;
+ return ;
}
export default MainTagWidgetContainer;
diff --git a/src/containers/main/RecentPosts.tsx b/src/containers/main/RecentPosts.tsx
deleted file mode 100644
index 26147bd4..00000000
--- a/src/containers/main/RecentPosts.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import React, { useCallback } from 'react';
-import PostCardList, {
- PostCardListSkeleton,
-} from '../../components/common/FlatPostCardList';
-import { GET_POST_LIST, PartialPost } from '../../lib/graphql/post';
-import { useQuery } from '@apollo/react-hooks';
-import useScrollPagination from '../../lib/hooks/useScrollPagination';
-import { safe } from '../../lib/utils';
-import { Helmet } from 'react-helmet-async';
-
-interface RecentPostsProps {}
-
-const RecentPosts: React.FC = props => {
- const getPostList = useQuery<{ posts: PartialPost[] }>(GET_POST_LIST, {
- notifyOnNetworkStatusChange: true,
- });
-
- const { data } = getPostList;
- const onLoadMore = useCallback(
- (cursor: string) => {
- getPostList.fetchMore({
- variables: {
- cursor,
- },
- updateQuery: (prev, { fetchMoreResult }) => {
- if (!fetchMoreResult) return prev;
- return {
- posts: [...prev.posts, ...fetchMoreResult.posts],
- };
- },
- });
- },
- [getPostList],
- );
-
- const cursor = safe(() => data!.posts[data!.posts.length - 1].id);
-
- useScrollPagination({
- cursor,
- onLoadMore,
- });
-
- if (!data || !data.posts) return ;
-
- return (
- <>
-
- 최신 포스트 - velog
-
-
-
- {getPostList.loading && }
- >
- );
-};
-
-export default RecentPosts;
diff --git a/src/containers/main/TrendingPosts.tsx b/src/containers/main/TrendingPosts.tsx
deleted file mode 100644
index a2220d69..00000000
--- a/src/containers/main/TrendingPosts.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import React, { useCallback } from 'react';
-import PostCardList, {
- PostCardListSkeleton,
-} from '../../components/common/FlatPostCardList';
-import {
- GET_TRENDING_POSTS,
- GetTrendingPostsResponse,
-} from '../../lib/graphql/post';
-import { useQuery } from '@apollo/react-hooks';
-import useScrollPagination from '../../lib/hooks/useScrollPagination';
-import { safe } from '../../lib/utils';
-import { Helmet } from 'react-helmet-async';
-
-interface TrendingPostsProps {}
-
-const TrendingPosts: React.FC = props => {
- const getTrendingPosts = useQuery(
- GET_TRENDING_POSTS,
- { notifyOnNetworkStatusChange: true },
- );
-
- const { data, loading } = getTrendingPosts;
- const onLoadMoreByOffset = useCallback(
- (offset: number) => {
- getTrendingPosts.fetchMore({
- variables: {
- offset,
- },
- updateQuery: (prev, { fetchMoreResult }) => {
- if (!fetchMoreResult) return prev;
-
- // filter unique posts
- const idMap: Record = prev.trendingPosts.reduce(
- (acc, current) => {
- Object.assign(acc, { [current.id]: true });
- return acc;
- },
- {},
- );
-
- const uniquePosts = fetchMoreResult.trendingPosts.filter(
- post => !idMap[post.id],
- );
-
- return {
- trendingPosts: [...prev.trendingPosts, ...uniquePosts],
- };
- },
- });
- },
- [getTrendingPosts],
- );
-
- const offset = safe(() => data!.trendingPosts.length);
-
- useScrollPagination({
- offset,
- onLoadMoreByOffset,
- });
-
- if (!data || !data.trendingPosts) return ;
-
- return (
- <>
-
-
-
-
-
- >
- );
-};
-
-export default TrendingPosts;
diff --git a/src/lib/graphql/post.ts b/src/lib/graphql/post.ts
index 03425d77..242ab3b6 100644
--- a/src/lib/graphql/post.ts
+++ b/src/lib/graphql/post.ts
@@ -704,8 +704,32 @@ export type PostViewResponse = {
postView: boolean;
};
-// mutation {
-// createPostHistory(post_id: "41f19ed8-bc7e-4af3-86e9-4c5e482cb8e4", title: "안녕하세요", body: "내용입니다.", is_markdown:true) {
-// id
-// }
-// }
+export const GET_READING_LIST = gql`
+ query ReadingList($type: ReadingListOption, $cursor: ID, $limit: Int) {
+ readingList(type: $type, cursor: $cursor, limit: $limit) {
+ id
+ title
+ short_description
+ thumbnail
+ user {
+ id
+ username
+ profile {
+ id
+ thumbnail
+ }
+ }
+ url_slug
+ released_at
+ updated_at
+ comments_count
+ tags
+ is_private
+ likes
+ }
+ }
+`;
+
+export type GetReadingListResponse = {
+ readingList: PartialPost[];
+};
diff --git a/src/lib/hooks/useScrollPagination.ts b/src/lib/hooks/useScrollPagination.ts
index bb7d12d8..a90f2800 100644
--- a/src/lib/hooks/useScrollPagination.ts
+++ b/src/lib/hooks/useScrollPagination.ts
@@ -19,7 +19,6 @@ export default function useScrollPagination({
const last = useRef(null);
const preventBottomStick = useCallback(() => {
- console.log(getScrollBottom());
if (getScrollBottom() === 0) {
window.scrollTo(0, getScrollTop() - 1);
}
@@ -43,7 +42,7 @@ export default function useScrollPagination({
const onScroll = useCallback(() => {
const scrollBottom = getScrollBottom();
- if (scrollBottom < 768) {
+ if (scrollBottom < window.screen.height) {
loadMore();
loadMoreUsingOffset();
}
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index f82f9741..e9151d7d 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -4,6 +4,7 @@ import LargeSearchInput from '../containers/search/LargeSearchInput';
import SearchResult from '../containers/search/SearchResult';
import { RouteComponentProps } from 'react-router';
import qs from 'qs';
+import { Helmet } from 'react-helmet-async';
export interface SearchPageProps extends RouteComponentProps {}
@@ -17,6 +18,11 @@ function SearchPage({ location }: SearchPageProps) {
return (
+
+ {(query.q || query.username) && (
+
+ )}
+
diff --git a/src/pages/getMatches.ts b/src/pages/getMatches.ts
deleted file mode 100644
index 0d1af1a9..00000000
--- a/src/pages/getMatches.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { matchPath, RouteProps, match } from 'react-router';
-import MainPage from './main/MainPage';
-
-const config: RouteProps[] = [
- {
- path: '/',
- component: MainPage,
- },
-];
-
-export function getMatches(path: string) {
- return config
- .map(r => {
- const match = matchPath(path, r);
- if (!match) return null;
- return {
- match,
- component: r.component,
- };
- })
- .filter(Boolean);
-}
diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx
index cd0cbdd4..121e1d67 100644
--- a/src/pages/home/HomePage.tsx
+++ b/src/pages/home/HomePage.tsx
@@ -1,23 +1,23 @@
import React from 'react';
-import HomeTemplate from '../../components/home/HomeTemplate';
-import HomeHeader from '../../components/home/HomeHeader';
+import MainTemplate from '../../components/main/MainTemplate';
+import MainHeader from '../../components/main/MainHeader';
import HomeTab from '../../components/home/HomeTab';
-import HomeResponsive from '../../components/home/HomeResponsive';
+import MainResponsive from '../../components/main/MainResponsive';
import HomeLayout from '../../components/home/HomeLayout';
import { Route } from 'react-router-dom';
import TrendingPostsPage from './TrendingPostsPage';
import RecentPostsPage from './RecentPostsPage';
import HomeSidebar from '../../components/home/HomeSidebar';
-import FloatingHomeHeader from '../../components/home/FloatingHomeHeader';
+import FloatingMainHeader from '../../components/main/FloatingHomeHeader';
export type HomePageProps = {};
function HomePage(props: HomePageProps) {
return (
-
-
-
-
+
+
+
+
}
/>
-
-
+
+
);
}
diff --git a/src/pages/home/RecentPostsPage.tsx b/src/pages/home/RecentPostsPage.tsx
index a846077d..11460976 100644
--- a/src/pages/home/RecentPostsPage.tsx
+++ b/src/pages/home/RecentPostsPage.tsx
@@ -3,17 +3,27 @@ import useRecentPosts from './hooks/useRecentPosts';
import PostCardGrid, {
PostCardGridSkeleton,
} from '../../components/common/PostCardGrid';
+import { Helmet } from 'react-helmet-async';
export type RecentPostsPageProps = {};
function RecentPostsPage(props: RecentPostsPageProps) {
const { data, loading } = useRecentPosts();
- if (!data) return ;
return (
<>
-
- {loading && }
+
+ 최신 포스트 - velog
+
+
+
>
);
}
diff --git a/src/pages/home/TrendingPostsPage.tsx b/src/pages/home/TrendingPostsPage.tsx
index a967dbd2..9adad876 100644
--- a/src/pages/home/TrendingPostsPage.tsx
+++ b/src/pages/home/TrendingPostsPage.tsx
@@ -3,18 +3,23 @@ import PostCardGrid, {
PostCardGridSkeleton,
} from '../../components/common/PostCardGrid';
import useTrendingPosts from './hooks/useTrendingPosts';
+import { Helmet } from 'react-helmet-async';
export type TrendingPageProps = {};
function TrendingPage(props: TrendingPageProps) {
- const { data, loading, isFinished } = useTrendingPosts();
+ const { data, loading } = useTrendingPosts();
- console.log(loading);
- if (!data) return ;
return (
<>
-
- {data && loading && }
+
+
+
+
>
);
}
diff --git a/src/pages/main/MainPage.tsx b/src/pages/main/MainPage.tsx
deleted file mode 100644
index c27341a5..00000000
--- a/src/pages/main/MainPage.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React, { useEffect } from 'react';
-import { Route, useLocation } from 'react-router-dom';
-import MainTemplate from '../../components/main/MainTemplate';
-import MainSideMenu from '../../components/main/MainSideMenu';
-import MainRightFooter from '../../components/main/MainRightFooter';
-import RecentPostsPage from './RecentPostsPage';
-import TrendingPostsPage from './TrendingPostsPage';
-import MainTagWidgetContainer from '../../containers/main/MainTagWidgetContainer';
-import MainNoticeWidgetContainer from '../../containers/main/MainNoticeWidgetContainer';
-import MainMobileHead from '../../components/main/MainMobileHead';
-import usePreserveScroll from '../../lib/hooks/usePreserveScroll';
-import { Helmet } from 'react-helmet-async';
-
-interface MainPageProps {}
-
-const MainPage: React.FC = () => {
- const { pathname } = useLocation();
-
- // scroll to top when path changes
- useEffect(() => {
- window.scrollTo(0, 0);
- }, [pathname]);
-
- usePreserveScroll('main');
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default MainPage;
diff --git a/src/pages/main/RecentPostsPage.tsx b/src/pages/main/RecentPostsPage.tsx
deleted file mode 100644
index e03dc55c..00000000
--- a/src/pages/main/RecentPostsPage.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import * as React from 'react';
-import styled from 'styled-components';
-
-import RecentPosts from '../../containers/main/RecentPosts';
-
-const RecentPostsPageBlock = styled.div``;
-
-interface RecentPostsPageProps {}
-
-const RecentPostsPage: React.FC = props => {
- return (
-
-
-
- );
-};
-
-export default RecentPostsPage;
diff --git a/src/pages/main/TrendingPostsPage.tsx b/src/pages/main/TrendingPostsPage.tsx
deleted file mode 100644
index 2481c31a..00000000
--- a/src/pages/main/TrendingPostsPage.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-import TrendingPosts from '../../containers/main/TrendingPosts';
-
-export type TrendingPostsPageProps = {};
-
-function TrendingPostsPage(props: TrendingPostsPageProps) {
- return ;
-}
-
-export default TrendingPostsPage;
diff --git a/src/pages/readingList/ReadingListPage.tsx b/src/pages/readingList/ReadingListPage.tsx
new file mode 100644
index 00000000..f991088e
--- /dev/null
+++ b/src/pages/readingList/ReadingListPage.tsx
@@ -0,0 +1,86 @@
+import React, { useEffect } from 'react';
+import MainPageTemplate from '../../components/main/MainPageTemplate';
+import MainResponsive from '../../components/main/MainResponsive';
+import ReadingListTab from '../../components/readingList/ReadingListTab';
+import styled from 'styled-components';
+import { RouteComponentProps } from 'react-router-dom';
+import useReadingList from './hooks/useReadingList';
+import PostCardGrid, {
+ PostCardGridSkeleton,
+} from '../../components/common/PostCardGrid';
+import { undrawEmpty } from '../../static/images';
+import palette from '../../lib/styles/palette';
+import media from '../../lib/styles/media';
+import { Helmet } from 'react-helmet-async';
+
+export type ReadingListPageProps = {} & RouteComponentProps<{
+ type: 'liked' | 'read';
+}>;
+
+function ReadingListPage({ match, history }: ReadingListPageProps) {
+ const { type } = match.params;
+
+ const { data, loading, isFinished } = useReadingList(type);
+
+ return (
+
+
+ {}
+ 읽기 목록 - velog
+
+
+
+
+
+ {data && data.readingList.length === 0 && (
+
+
+ 리스트가 비어있습니다.
+
+ )}
+
+
+
+ );
+}
+
+const StyledResponsive = styled(MainResponsive)`
+ margin-top: 1.5rem;
+`;
+
+const Wrapper = styled.div`
+ margin-top: 2rem;
+`;
+
+const EmptyWrapper = styled.div`
+ margin-top: 6rem;
+ align-items: center;
+ justify-content: center;
+ display: flex;
+ flex-direction: column;
+ img {
+ width: 25rem;
+ height: auto;
+ display: block;
+ margin-bottom: 2rem;
+ }
+
+ .description {
+ color: ${palette.gray7};
+ font-size: 1.5rem;
+ }
+
+ ${media.small} {
+ margin-top: 3rem;
+ img {
+ max-width: 300px;
+ width: calc(100% - 2rem);
+ margin-bottom: 1rem;
+ }
+ .description {
+ font-size: 1.25rem;
+ }
+ }
+`;
+
+export default ReadingListPage;
diff --git a/src/pages/readingList/hooks/useReadingList.ts b/src/pages/readingList/hooks/useReadingList.ts
new file mode 100644
index 00000000..6911fc94
--- /dev/null
+++ b/src/pages/readingList/hooks/useReadingList.ts
@@ -0,0 +1,63 @@
+import {
+ GET_READING_LIST,
+ GetReadingListResponse,
+} from '../../../lib/graphql/post';
+import { useQuery } from '@apollo/react-hooks';
+import { useCallback, useState, useEffect } from 'react';
+import useScrollPagination from '../../../lib/hooks/useScrollPagination';
+
+export default function useReadingList(type: 'liked' | 'read') {
+ const { data, loading, fetchMore } = useQuery(
+ GET_READING_LIST,
+ {
+ variables: {
+ type: type.toUpperCase(),
+ limit: 20,
+ },
+ fetchPolicy: 'cache-and-network',
+ },
+ );
+ const [isFinished, setIsFinished] = useState(false);
+
+ useEffect(() => {
+ setIsFinished(false);
+ }, [type]);
+
+ useEffect(() => {
+ if (!data) return;
+ if (data.readingList.length < 20) {
+ setIsFinished(true);
+ }
+ }, [data]);
+
+ const onLoadMore = useCallback(
+ (cursor: string) => {
+ fetchMore({
+ variables: {
+ type: type.toUpperCase(),
+ cursor,
+ limit: 24,
+ },
+ updateQuery: (prev, { fetchMoreResult }) => {
+ if (!fetchMoreResult) return prev;
+ if (fetchMoreResult.readingList.length === 0) {
+ setIsFinished(true);
+ }
+ return {
+ readingList: [...prev.readingList, ...fetchMoreResult.readingList],
+ };
+ },
+ });
+ },
+ [fetchMore, type],
+ );
+
+ const cursor = data?.readingList[data?.readingList.length - 1]?.id;
+
+ useScrollPagination({
+ cursor,
+ onLoadMore,
+ });
+
+ return { data, loading, isFinished };
+}