From b3015869f4af2ec6948f9a7a903b1921e7cb494a Mon Sep 17 00:00:00 2001 From: gs0428 Date: Sun, 18 Feb 2024 02:32:10 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feature-075:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=8A=A4=EC=BC=88?= =?UTF-8?q?=EB=A0=88=ED=86=A4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/skeleton/CardSkeleton.tsx | 20 +++++ .../skeleton/CategoryPageSkeleton.tsx | 34 +++++++++ src/pages/CategoryPage.tsx | 7 ++ src/styles/skeleton/CardSkeleton.style.ts | 35 +++++++++ .../skeleton/CategoryPageSkeleton.style.ts | 73 +++++++++++++++++++ src/utils/handleVideo.ts | 3 + 6 files changed, 172 insertions(+) create mode 100644 src/components/skeleton/CardSkeleton.tsx create mode 100644 src/components/skeleton/CategoryPageSkeleton.tsx create mode 100644 src/styles/skeleton/CardSkeleton.style.ts create mode 100644 src/styles/skeleton/CategoryPageSkeleton.style.ts diff --git a/src/components/skeleton/CardSkeleton.tsx b/src/components/skeleton/CardSkeleton.tsx new file mode 100644 index 0000000..e6615db --- /dev/null +++ b/src/components/skeleton/CardSkeleton.tsx @@ -0,0 +1,20 @@ +import * as CardSkeletonStyles from '@/styles/skeleton/CardSkeleton.style'; +const CardSkeleton = () => { + return ( + + + + + + + + + + + + + + ); +}; + +export default CardSkeleton; diff --git a/src/components/skeleton/CategoryPageSkeleton.tsx b/src/components/skeleton/CategoryPageSkeleton.tsx new file mode 100644 index 0000000..1e2dc73 --- /dev/null +++ b/src/components/skeleton/CategoryPageSkeleton.tsx @@ -0,0 +1,34 @@ +import * as CategoryPageSkeletonStyles from '@/styles/skeleton/CategoryPageSkeleton.style'; +import CardSkeleton from './CardSkeleton'; + +interface ICategoryPageSkeletonProp { + isSubSkeleton: boolean; +} + +const CategoryPageSkeleton = ({ isSubSkeleton }: ICategoryPageSkeletonProp) => { + return ( + + + + + + + + + + + + + + + + + + ); +}; + +export default CategoryPageSkeleton; diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index 18fb70d..e7fc9cf 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -15,9 +15,11 @@ import VideoSelectMenu from '@/components/category/VideoSelectMenu'; import DefaultMenu from '@/components/category/DefaultMenu'; import { putVideoToOtherCategory } from '@/apis/category'; import handleVideo from '@/utils/handleVideo'; +import CategoryPageSkeleton from '@/components/skeleton/CategoryPageSkeleton'; const CategoryPage = () => { const params = useParams(); + const [isLoading, setIsLoading] = useState(true); const [name, setName] = useState(''); const [menus, setMenus] = useState([]); const [videos, setVideos] = useState([]); @@ -39,6 +41,7 @@ const CategoryPage = () => { setMenus, setName, setVideos, + setIsLoading, ); setCheckedVideos([]); }, [categories, params.sub_folder, params.top_folder]); @@ -73,10 +76,14 @@ const CategoryPage = () => { setMenus, setName, setVideos, + setIsLoading, ); } }; + if (isLoading) + return ; + return ( diff --git a/src/styles/skeleton/CardSkeleton.style.ts b/src/styles/skeleton/CardSkeleton.style.ts new file mode 100644 index 0000000..bbbbd72 --- /dev/null +++ b/src/styles/skeleton/CardSkeleton.style.ts @@ -0,0 +1,35 @@ +import styled from 'styled-components'; +import { CommonBackground } from './CategoryPageSkeleton.style'; + +export const Container = styled.div` + height: 346px; +`; + +export const Image = styled(CommonBackground)` + height: 163px; +`; + +export const ContentWrap = styled.div` + padding: 26.87px 16px 0; +`; + +export const ContentLong = styled(CommonBackground)` + height: 20px; + margin-bottom: 6px; +`; + +export const ContentShort = styled(CommonBackground)` + width: 142px; + height: 20px; + margin-bottom: 20px; +`; + +export const TagWrap = styled.div` + display: flex; +`; + +export const Tag = styled(CommonBackground)` + width: 62px; + height: 31px; + margin-right: 8px; +`; diff --git a/src/styles/skeleton/CategoryPageSkeleton.style.ts b/src/styles/skeleton/CategoryPageSkeleton.style.ts new file mode 100644 index 0000000..46bd0c5 --- /dev/null +++ b/src/styles/skeleton/CategoryPageSkeleton.style.ts @@ -0,0 +1,73 @@ +import styled, { keyframes } from 'styled-components'; +import theme from '../theme'; + +const gradient = keyframes` + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +`; + +export const CommonBackground = styled.div` + background: linear-gradient( + -45deg, + ${theme.color.gray100}, + ${theme.color.gray200}, + ${theme.color.gray100} + ); + background-size: 200% 100%; + animation: ${gradient} 1.5s ease infinite; + + border-radius: 4px; +`; + +export const Container = styled.div` + padding: 60px 60px 40px 120px; + width: 100%; + margin-inline: auto; +`; + +export const Title = styled(CommonBackground)` + height: 40px; + width: 259px; + background-color: ${theme.color.gray100}; +`; + +export const MenuWrap = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin: 32px 0 44px; +`; + +export const TagWrap = styled.div` + display: flex; +`; + +export const Tag = styled(CommonBackground)` + visibility: hidden; + width: 64px; + height: 20px; + margin-right: 20px; + + &.show { + visibility: visible; + } +`; + +export const Menu = styled(CommonBackground)` + width: 90px; + height: 20px; +`; + +export const CardContainer = styled.div` + display: grid; + grid-template-columns: repeat(3, 290px); + column-gap: 20px; + row-gap: 61px; +`; diff --git a/src/utils/handleVideo.ts b/src/utils/handleVideo.ts index 538ca0d..6187637 100644 --- a/src/utils/handleVideo.ts +++ b/src/utils/handleVideo.ts @@ -12,7 +12,9 @@ const handleVideo = async ( >, setName: React.Dispatch>, setVideos: React.Dispatch>, + setIsLoading: React.Dispatch>, ) => { + setIsLoading(true); if (!topCategoryId) { await getRecentVideos().then((res) => { setVideos(res.result.videos); @@ -37,6 +39,7 @@ const handleVideo = async ( setName(topCategory!.name); setMenus(topCategory!.subFolders); } + setIsLoading(false); setVideos(res.isSuccess ? res.result.videos : []); }); } From da15ad62b6baf0b9e6f378c85c195c0698b16ce9 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Sun, 18 Feb 2024 02:33:12 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feature-075:=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=EC=A4=91=EB=8B=A8=20=ED=95=A8=EC=88=98=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/handleVideo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/handleVideo.ts b/src/utils/handleVideo.ts index 6187637..9fb99c0 100644 --- a/src/utils/handleVideo.ts +++ b/src/utils/handleVideo.ts @@ -39,10 +39,10 @@ const handleVideo = async ( setName(topCategory!.name); setMenus(topCategory!.subFolders); } - setIsLoading(false); setVideos(res.isSuccess ? res.result.videos : []); }); } + setIsLoading(false); }; export default handleVideo; From 1810a971021d9b12154daa34c6fdfc8408291d24 Mon Sep 17 00:00:00 2001 From: gs0428 Date: Sun, 18 Feb 2024 03:11:57 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feature-075:=20React=20Suspense=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/CategoryPage.tsx | 119 ++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index e7fc9cf..9a88cab 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -1,8 +1,6 @@ -import CategoryTitle from '@/components/category/CategoryTitle'; -import { useEffect, useState } from 'react'; +import React, { Suspense, useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import * as CategoryPageStyles from '@/styles/category/index.style'; -import Card from '@/components/category/Card'; import { useRecoilValue } from 'recoil'; import { categoryState } from '@/stores/category'; import { ISubFolderProps, ITagProps } from 'types/category'; @@ -17,6 +15,11 @@ import { putVideoToOtherCategory } from '@/apis/category'; import handleVideo from '@/utils/handleVideo'; import CategoryPageSkeleton from '@/components/skeleton/CategoryPageSkeleton'; +const CategoryTitle = React.lazy( + () => import('@/components/category/CategoryTitle'), +); +const Card = React.lazy(() => import('@/components/category/Card')); + const CategoryPage = () => { const params = useParams(); const [isLoading, setIsLoading] = useState(true); @@ -85,61 +88,65 @@ const CategoryPage = () => { return ; return ( - - - - {checkedVideos.length > 0 ? ( - - ) : ( - - )} - + } + > + + + + {checkedVideos.length > 0 ? ( + + ) : ( + + )} + - {(sortedVideos.length === 0 || sortedVideos === undefined) && ( - - )} - {sortedVideos.length > 0 && ( - - {sortedVideos.map((video) => { - // 하위 카테고리에 있을 때 태그 선택된 것에 따라 비디오 보여지게하는 로직 - const matchedTagCount = video.tag.reduce((acc, cur) => { - if (selectedTags.includes(cur.name)) return (acc += 1); - return acc; - }, 0); - if ( - params.sub_folder && - selectedTags.length && - matchedTagCount !== selectedTags.length - ) - return; + {(sortedVideos.length === 0 || sortedVideos === undefined) && ( + + )} + {sortedVideos.length > 0 && ( + + {sortedVideos.map((video) => { + // 하위 카테고리에 있을 때 태그 선택된 것에 따라 비디오 보여지게하는 로직 + const matchedTagCount = video.tag.reduce((acc, cur) => { + if (selectedTags.includes(cur.name)) return (acc += 1); + return acc; + }, 0); + if ( + params.sub_folder && + selectedTags.length && + matchedTagCount !== selectedTags.length + ) + return; - return ( - - ); - })} - - )} - + return ( + + ); + })} + + )} + + ); }; From f706fa70a8c5a70324cbb59d0551bb10085a732e Mon Sep 17 00:00:00 2001 From: gs0428 Date: Sun, 18 Feb 2024 03:17:37 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feature-075:=20lazy=20loading=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/CategoryPage.tsx | 10 +++------- src/utils/handleVideo.ts | 3 --- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/pages/CategoryPage.tsx b/src/pages/CategoryPage.tsx index 9a88cab..ae7500a 100644 --- a/src/pages/CategoryPage.tsx +++ b/src/pages/CategoryPage.tsx @@ -10,7 +10,6 @@ import { IVideoProps } from 'types/videos'; import { sortVideos } from '@/utils/sortVideos'; import { CardContainer } from '@/styles/category/Card.style'; import VideoSelectMenu from '@/components/category/VideoSelectMenu'; -import DefaultMenu from '@/components/category/DefaultMenu'; import { putVideoToOtherCategory } from '@/apis/category'; import handleVideo from '@/utils/handleVideo'; import CategoryPageSkeleton from '@/components/skeleton/CategoryPageSkeleton'; @@ -19,10 +18,12 @@ const CategoryTitle = React.lazy( () => import('@/components/category/CategoryTitle'), ); const Card = React.lazy(() => import('@/components/category/Card')); +const DefaultMenu = React.lazy( + () => import('@/components/category/DefaultMenu'), +); const CategoryPage = () => { const params = useParams(); - const [isLoading, setIsLoading] = useState(true); const [name, setName] = useState(''); const [menus, setMenus] = useState([]); const [videos, setVideos] = useState([]); @@ -44,7 +45,6 @@ const CategoryPage = () => { setMenus, setName, setVideos, - setIsLoading, ); setCheckedVideos([]); }, [categories, params.sub_folder, params.top_folder]); @@ -79,14 +79,10 @@ const CategoryPage = () => { setMenus, setName, setVideos, - setIsLoading, ); } }; - if (isLoading) - return ; - return ( } diff --git a/src/utils/handleVideo.ts b/src/utils/handleVideo.ts index 9fb99c0..538ca0d 100644 --- a/src/utils/handleVideo.ts +++ b/src/utils/handleVideo.ts @@ -12,9 +12,7 @@ const handleVideo = async ( >, setName: React.Dispatch>, setVideos: React.Dispatch>, - setIsLoading: React.Dispatch>, ) => { - setIsLoading(true); if (!topCategoryId) { await getRecentVideos().then((res) => { setVideos(res.result.videos); @@ -42,7 +40,6 @@ const handleVideo = async ( setVideos(res.isSuccess ? res.result.videos : []); }); } - setIsLoading(false); }; export default handleVideo;