From 425d0691734c0b6cfc82461e8739ed39606aaf7f Mon Sep 17 00:00:00 2001 From: Zero Date: Thu, 26 Sep 2024 14:20:58 +0900 Subject: [PATCH] =?UTF-8?q?Feat/#41=20=EB=B3=80=EA=B2=BD=EB=90=9C=20Projec?= =?UTF-8?q?tList=EB=A5=BC=20=EC=A0=81=EC=9A=A9=ED=95=A9=EB=8B=88=EB=8B=A4.?= =?UTF-8?q?=20(#67)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: color 값들을 변경합니다. * refactor: 변경된 projectList를 적용합니다. * fix: 가운데 정렬을 통해 글자를 가운데로 맞춥니다. * refactor: web 환경에서는 프로젝트를 등록할 수 없게 합니다. --- app/(app)/project/_layout.tsx | 16 ++-- app/(app)/project/create.tsx | 12 ++- src/__mock__/project/index.ts | 47 +++++++++++ .../ProjectImage/ProjectImage.style.ts | 3 +- .../ProjectItem/ProjectItem.stories.tsx | 56 +++++++++++++ src/components/project/ProjectItem/index.tsx | 43 ++++++++++ src/components/project/ProjectItem/style.ts | 26 ++++++ .../ProjectList/ProjectList.stories.tsx | 78 +---------------- .../project/ProjectList/ProjectList.style.ts | 52 ------------ src/components/project/ProjectList/index.tsx | 84 +++---------------- src/components/project/ProjectList/style.ts | 14 ++++ src/styles/theme.ts | 12 +-- 12 files changed, 227 insertions(+), 216 deletions(-) create mode 100644 src/__mock__/project/index.ts create mode 100644 src/components/project/ProjectItem/ProjectItem.stories.tsx create mode 100644 src/components/project/ProjectItem/index.tsx create mode 100644 src/components/project/ProjectItem/style.ts delete mode 100644 src/components/project/ProjectList/ProjectList.style.ts create mode 100644 src/components/project/ProjectList/style.ts diff --git a/app/(app)/project/_layout.tsx b/app/(app)/project/_layout.tsx index e2d1f8c..b582aba 100644 --- a/app/(app)/project/_layout.tsx +++ b/app/(app)/project/_layout.tsx @@ -1,6 +1,6 @@ import { AntDesign, Feather } from '@expo/vector-icons'; import { Stack, useRouter } from 'expo-router'; -import { Pressable } from 'react-native'; +import { Platform, Pressable } from 'react-native'; import { PROJECT_NAVIGATIONS } from '@/constants'; import { color } from '@/styles/theme'; @@ -33,12 +33,14 @@ function Layout() { size={24} /> - router.push('/project/create')}> - - + {Platform.OS !== 'web' && ( + router.push('/project/create')}> + + + )} ), }} diff --git a/app/(app)/project/create.tsx b/app/(app)/project/create.tsx index afae1bf..77e7483 100644 --- a/app/(app)/project/create.tsx +++ b/app/(app)/project/create.tsx @@ -4,8 +4,9 @@ import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet'; import type { DateTimePickerEvent } from '@react-native-community/datetimepicker'; import DateTimePicker from '@react-native-community/datetimepicker'; import { launchImageLibraryAsync, MediaTypeOptions } from 'expo-image-picker'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { Alert, ScrollView } from 'react-native'; +import { useRouter } from 'expo-router'; +import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; +import { Alert, Platform, ScrollView } from 'react-native'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import SolidButton from '@/components/common/button/SolidButton'; @@ -23,6 +24,7 @@ import { color } from '@/styles/theme'; import { getSize } from '@/utils'; function Create() { + const router = useRouter(); useTabBarEffect(); const [image, setImage] = useState(null); const [startDate, setStartDate] = useState(() => new Date()); @@ -83,6 +85,12 @@ function Create() { setSelectDate(select); }, []); + useLayoutEffect(() => { + if (Platform.OS === 'web') { + return router.replace('/project'); + } + }, [router]); + useEffect(() => { return () => dataSheetClose(); }, [dataSheetClose]); diff --git a/src/__mock__/project/index.ts b/src/__mock__/project/index.ts new file mode 100644 index 0000000..52d67f8 --- /dev/null +++ b/src/__mock__/project/index.ts @@ -0,0 +1,47 @@ +import type { ProjectItemType } from '@/components/project/ProjectList'; + +export const MOCK_PROJECT_ITEM: ProjectItemType = { + id: 1, + name: '위프로', + profile: 'https://picsum.photos/200', + review_count: 3, + member_num: 6, +}; + +export const MOCK_PROJECT_LIST: ProjectItemType[] = [ + { + id: 1, + name: '위프로', + profile: 'https://picsum.photos/200', + review_count: 3, + member_num: 6, + }, + { + id: 2, + name: '후피', + profile: 'https://picsum.photos/200', + review_count: 1, + member_num: 3, + }, + { + id: 3, + name: 'Code Red', + profile: 'https://picsum.photos/200', + review_count: 2, + member_num: 3, + }, + { + id: 4, + name: 'Veco', + profile: 'https://picsum.photos/200', + review_count: 3, + member_num: 3, + }, + { + id: 5, + name: 'Zero Waste', + profile: 'https://picsum.photos/200', + review_count: 0, + member_num: 3, + }, +] as const; diff --git a/src/components/project/ProjectImage/ProjectImage.style.ts b/src/components/project/ProjectImage/ProjectImage.style.ts index ed29b00..f1087c3 100644 --- a/src/components/project/ProjectImage/ProjectImage.style.ts +++ b/src/components/project/ProjectImage/ProjectImage.style.ts @@ -7,6 +7,7 @@ export const ProjectImageBox = styled.View` position: relative; width: 48px; height: 48px; + overflow: hidden; border-radius: 8px; `; @@ -14,7 +15,7 @@ export const ProjectImageOutline = styled.View` position: absolute; width: 100%; height: 100%; - border: 1px solid rgb(115 112 114); + border: 1px solid ${({ theme }) => theme.color.Line.Normal}; border-radius: 8px; `; diff --git a/src/components/project/ProjectItem/ProjectItem.stories.tsx b/src/components/project/ProjectItem/ProjectItem.stories.tsx new file mode 100644 index 0000000..75be025 --- /dev/null +++ b/src/components/project/ProjectItem/ProjectItem.stories.tsx @@ -0,0 +1,56 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { View } from 'react-native'; + +import { MOCK_PROJECT_ITEM } from '@/__mock__/project'; +import { color } from '@/styles/theme'; + +import ProjectItem from './'; + +const ProjectItemMeta: Meta = { + title: 'project/ProjectItem', + component: ProjectItem, + argTypes: { + member_num: { + control: { + type: 'number', + }, + description: '프로젝트의 총 인원 수를 지정합니다.', + }, + name: { + control: { + type: 'text', + }, + description: '프로젝트의 이름을 지정합니다.', + }, + profile: { + control: { + type: 'text', + }, + description: '프로젝트의 이미지를 지정합니다.', + }, + review_count: { + control: { + type: 'number', + }, + description: '프로젝트의 리뷰 수를 지정합니다.', + }, + id: { + control: { + type: 'number', + }, + description: '프로젝트의 id를 지정합니다.', + }, + }, +}; + +export default ProjectItemMeta; + +export const Primary: StoryObj = { + render: () => { + return ( + + + + ); + }, +}; diff --git a/src/components/project/ProjectItem/index.tsx b/src/components/project/ProjectItem/index.tsx new file mode 100644 index 0000000..2d1ec8b --- /dev/null +++ b/src/components/project/ProjectItem/index.tsx @@ -0,0 +1,43 @@ +import SlideBar from '@/components/common/slide-bar'; +import Typography from '@/components/common/typography'; +import ProjectImage from '@/components/project/ProjectImage'; +import type { ProjectItemType } from '@/components/project/ProjectList'; +import { color } from '@/styles/theme'; + +import * as S from './style'; + +function ProjectItem({ name, member_num, profile, review_count }: ProjectItemType) { + return ( + + + + + 프로젝트 + + + + + {name} + + + {review_count} / {member_num} + + + + + + + ); +} + +export default ProjectItem; diff --git a/src/components/project/ProjectItem/style.ts b/src/components/project/ProjectItem/style.ts new file mode 100644 index 0000000..0d08c2f --- /dev/null +++ b/src/components/project/ProjectItem/style.ts @@ -0,0 +1,26 @@ +import styled from '@emotion/native'; + +import { flexDirectionColumn, flexDirectionRowItemsCenter } from '@/styles/common'; + +export const Container = styled.View` + ${flexDirectionRowItemsCenter}; + gap: 10px; + padding: 16px; + background-color: ${({ theme }) => theme.color.Background.Normal}; + border-radius: 8px; +`; + +export const ProjectStatusBox = styled.View` + ${flexDirectionColumn}; + flex-grow: 1; +`; + +export const ProgressBox = styled.View` + ${flexDirectionColumn}; + gap: 6px; +`; + +export const ProgressInfo = styled.View` + ${flexDirectionRowItemsCenter}; + justify-content: space-between; +`; diff --git a/src/components/project/ProjectList/ProjectList.stories.tsx b/src/components/project/ProjectList/ProjectList.stories.tsx index 6083d10..5812e6e 100644 --- a/src/components/project/ProjectList/ProjectList.stories.tsx +++ b/src/components/project/ProjectList/ProjectList.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react'; import { View } from 'react-native'; +import { MOCK_PROJECT_LIST } from '@/__mock__/project'; import { color } from '@/styles/theme'; import ProjectList from './'; @@ -15,84 +16,9 @@ export default ProjectListMeta; export const Primary: StoryObj = { render: () => { - const mockList = [ - { - id: 1, - name: '위프로', - profile: 'https://picsum.photos/200', - member_num: 6, - }, - { - id: 2, - name: '후피', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 3, - name: 'Code Red', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 4, - name: 'Veco', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 5, - name: '위프로', - profile: 'https://picsum.photos/200', - member_num: 6, - }, - { - id: 6, - name: '후피', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 7, - name: 'Code Red', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 8, - name: 'Veco', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 9, - name: '위프로', - profile: 'https://picsum.photos/200', - member_num: 6, - }, - { - id: 10, - name: '후피', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 11, - name: 'Code Red', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - { - id: 12, - name: 'Last Project', - profile: 'https://picsum.photos/200', - member_num: 3, - }, - ]; - return ( - + ); }, diff --git a/src/components/project/ProjectList/ProjectList.style.ts b/src/components/project/ProjectList/ProjectList.style.ts deleted file mode 100644 index 2f8523c..0000000 --- a/src/components/project/ProjectList/ProjectList.style.ts +++ /dev/null @@ -1,52 +0,0 @@ -import styled from '@emotion/native'; -import Animated from 'react-native-reanimated'; - -import { COMPONENT_SIZE } from '@/constants'; -import { - flexDirectionColumn, - flexDirectionColumnItemsCenter, - flexDirectionRow, -} from '@/styles/common'; - -export const Container = styled.ScrollView` - padding-bottom: ${COMPONENT_SIZE.BOTTOM_NAV + 'px'}; -`; - -export const ProjectContainer = styled.View` - ${flexDirectionColumn}; - background-color: ${({ theme }) => theme.color.Background.Normal}; - border-radius: 8px; -`; - -export const ProjectInActiveBox = styled.View` - ${flexDirectionRow}; - align-items: center; - justify-content: space-between; - padding: 20px 16px; -`; - -export const ProjectInfoBox = styled.View` - ${flexDirectionRow}; - gap: 8px; -`; - -export const ProjectStatusBox = styled.View` - ${flexDirectionColumn}; -`; - -export const ProjectActiveDivider = styled.View` - height: 1px; - margin: 0 20px; - border-bottom-color: ${({ theme }) => theme.color.Line.Neutral}; - border-bottom-width: 1px; -`; - -export const ProjectActiveBox = styled(Animated.View)` - overflow: 'hidden'; -`; - -export const DeleteButton = styled.Pressable` - ${flexDirectionColumnItemsCenter}; - width: 71px; - background: ${({ theme }) => theme.color.Status.Error}; -`; diff --git a/src/components/project/ProjectList/index.tsx b/src/components/project/ProjectList/index.tsx index 55469f7..4e5a6ea 100644 --- a/src/components/project/ProjectList/index.tsx +++ b/src/components/project/ProjectList/index.tsx @@ -1,16 +1,11 @@ -import { Ionicons } from '@expo/vector-icons'; -import { useState } from 'react'; -import { FlatList, Pressable } from 'react-native'; +import { FlatList } from 'react-native'; import { GestureHandlerRootView, Swipeable } from 'react-native-gesture-handler'; -import { useAnimatedStyle, withTiming } from 'react-native-reanimated'; -import type { ProjectDTO } from '@/apis/project/project.type'; import Typography from '@/components/common/typography'; -import ProjectImage from '@/components/project/ProjectImage'; +import ProjectItem from '@/components/project/ProjectItem'; import { COMPONENT_SIZE } from '@/constants'; -import { color } from '@/styles/theme'; -import * as S from './ProjectList.style'; +import * as S from './style'; type ProjectDeleteButtonProps = { deleteId: string | number; @@ -24,71 +19,16 @@ function ProjectDeleteButton({ deleteId }: ProjectDeleteButtonProps) { ); } -type OneProjectProps = ProjectDTO; - -function OneProject({ - member_num, - profile, - name, -}: Pick) { - const [active, setActive] = useState(() => false); - - const activeStyle = useAnimatedStyle(() => ({ - paddingTop: withTiming(active ? 20 : 0), - paddingBottom: withTiming(active ? 20 : 0), - height: withTiming(active ? 64 : 0), - })); - - return ( - - - - - - - {name} - - - {member_num}명 - - - - setActive((prev) => !prev)}> - {active ? ( - - ) : ( - - )} - - - {active ? : null} - - - 리뷰 만들기 - - - - ); -} +export type ProjectItemType = { + id: string | number; + name: string; + profile: string; + review_count: number; + member_num: number; +}; type Props = { - data: Pick[]; + data: ProjectItemType[]; }; function ProjectList({ data }: Props) { @@ -105,7 +45,7 @@ function ProjectList({ data }: Props) { renderItem={(info) => ( }> - + )} diff --git a/src/components/project/ProjectList/style.ts b/src/components/project/ProjectList/style.ts new file mode 100644 index 0000000..6fd66fc --- /dev/null +++ b/src/components/project/ProjectList/style.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/native'; + +import { COMPONENT_SIZE } from '@/constants'; +import { flexDirectionColumnItemsCenter } from '@/styles/common'; + +export const Container = styled.ScrollView` + padding-bottom: ${COMPONENT_SIZE.BOTTOM_NAV + 'px'}; +`; + +export const DeleteButton = styled.Pressable` + ${flexDirectionColumnItemsCenter}; + width: 71px; + background: ${({ theme }) => theme.color.Status.Error}; +`; diff --git a/src/styles/theme.ts b/src/styles/theme.ts index f3c31ed..26bd740 100644 --- a/src/styles/theme.ts +++ b/src/styles/theme.ts @@ -198,9 +198,9 @@ const semantic = { Disable: '#F7F7F8', }, Line: { - Normal: 'rgba(112, 115, 124, 0.22)', - Neutral: 'rgba(112, 115, 124, 0.16)', - Alternative: 'rgba(112, 115, 124, 0.08)', + Normal: '#E0E0E2', + Neutral: '#E8E8EA', + Alternative: '#F4F4F5', }, Status: { Success: '#00BF40', @@ -216,9 +216,9 @@ const semantic = { Pink: '#F553DA', }, Component: { - Fill: 'rgba(112, 115, 124, 0.08)', - Strong: 'rgba(112, 115, 124, 0.16)', - Alternative: 'rgba(112, 115, 124, 0.05)', + Fill: '#F4F4F5', + Strong: '#E8E8EA', + Alternative: '#F8F8F8', }, Material: { Dimmer: '#0c0c0d',