From a4bf24420d22d855ebb0b7d4c241ffec0beb5e35 Mon Sep 17 00:00:00 2001 From: Young-do Cho Date: Wed, 13 Nov 2024 21:56:59 +0900 Subject: [PATCH] =?UTF-8?q?=08feat:=20=EB=8D=B0=EC=8A=A4=ED=81=AC=ED=83=91?= =?UTF-8?q?=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?(#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 모바일, 데스크탑 레이아웃 추가 * 모바일 데스크탑 레이아웃 모두 적용 * 홈스크린 해더 제거 * 시간변경 모달로 임시 제공 * 마이페이지 ui 디자인 가이드 맞춰 변경 * 기존 전역 layout을 위한 파일 제거 * SidebarLayout, SimpleLayout 이름으로 변경 * 마이페이지 피그마 수정사항 반영 --- src/renderer/app/index.css | 2 +- src/renderer/app/layout.tsx | 11 -- src/renderer/app/router.tsx | 20 +-- .../features/time/ui/chage-time-dialog.tsx | 4 +- src/renderer/pages/home.tsx | 19 ++- src/renderer/pages/mycat.tsx | 58 +++---- src/renderer/pages/mypage.tsx | 75 +++++---- src/renderer/pages/naming.tsx | 78 +++++----- src/renderer/pages/onboarding.tsx | 101 ++++++------ src/renderer/pages/pomodoro.tsx | 102 ++++++------ src/renderer/pages/selection.tsx | 146 ++++++++++-------- .../shared/assets/svgs/clock-line.svg | 4 + src/renderer/shared/ui/icon.tsx | 4 +- src/renderer/shared/ui/index.ts | 1 + src/renderer/shared/ui/layouts.tsx | 63 ++++++++ .../widgets/pomodoro/ui/home-screen.tsx | 15 +- 16 files changed, 394 insertions(+), 309 deletions(-) delete mode 100644 src/renderer/app/layout.tsx create mode 100644 src/renderer/shared/assets/svgs/clock-line.svg create mode 100644 src/renderer/shared/ui/layouts.tsx diff --git a/src/renderer/app/index.css b/src/renderer/app/index.css index ea766bc..ad1a825 100644 --- a/src/renderer/app/index.css +++ b/src/renderer/app/index.css @@ -58,7 +58,7 @@ @apply border-border; } body { - @apply bg-background-primary text-foreground; + @apply bg-background-primary font-pretendard text-foreground; } } diff --git a/src/renderer/app/layout.tsx b/src/renderer/app/layout.tsx deleted file mode 100644 index b3d8bf4..0000000 --- a/src/renderer/app/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Outlet } from 'react-router-dom'; - -const RootLayout = () => { - return ( -
- -
- ); -}; - -export default RootLayout; diff --git a/src/renderer/app/router.tsx b/src/renderer/app/router.tsx index 9984d09..30dbf74 100644 --- a/src/renderer/app/router.tsx +++ b/src/renderer/app/router.tsx @@ -1,7 +1,5 @@ import { Navigate, MemoryRouter as ReactRouter, Route, Routes } from 'react-router-dom'; -import RootLayout from './layout'; - import Home from '@/pages/home'; import MyCat from '@/pages/mycat'; import MyPage from '@/pages/mypage'; @@ -15,16 +13,14 @@ export const Router = () => { return ( - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> ); diff --git a/src/renderer/features/time/ui/chage-time-dialog.tsx b/src/renderer/features/time/ui/chage-time-dialog.tsx index 4550b0d..7356955 100644 --- a/src/renderer/features/time/ui/chage-time-dialog.tsx +++ b/src/renderer/features/time/ui/chage-time-dialog.tsx @@ -80,7 +80,7 @@ export const ChangeTimeDialog = ({ }, [open, categoryTimeMinutes, categoryTimeSeconds]); return ( - +
@@ -127,7 +127,7 @@ export const ChangeTimeDialog = ({
-
+
diff --git a/src/renderer/pages/home.tsx b/src/renderer/pages/home.tsx index ab172ab..03046fa 100644 --- a/src/renderer/pages/home.tsx +++ b/src/renderer/pages/home.tsx @@ -6,6 +6,7 @@ import { useLocalStorage, useTimeout } from 'usehooks-ts'; import { useUser } from '@/features/user'; import appSymbolIcon from '@/shared/assets/svgs/app-symbol.svg'; import { LOCAL_STORAGE_KEY, PATH } from '@/shared/constants'; +import { SimpleLayout } from '@/shared/ui'; import { cn } from '@/shared/utils'; const Home = () => { @@ -27,14 +28,16 @@ const Home = () => { }, [isCompletedOnboarding, user]); return ( -
- -
+ +
+ +
+
); }; diff --git a/src/renderer/pages/mycat.tsx b/src/renderer/pages/mycat.tsx index 904dd08..2e2b4b2 100644 --- a/src/renderer/pages/mycat.tsx +++ b/src/renderer/pages/mycat.tsx @@ -7,7 +7,7 @@ import { useUser } from '@/features/user'; import catSelectMotionRiveFile from '@/shared/assets/rivs/cat_select_ver2.0.riv'; import { PATH } from '@/shared/constants'; import { userCatTypeAliasMap } from '@/shared/hooks'; -import { Button, Frame, Icon, Tooltip } from '@/shared/ui'; +import { Button, Frame, Icon, SimpleLayout, Tooltip } from '@/shared/ui'; const MyCat = () => { const navigate = useNavigate(); @@ -39,39 +39,41 @@ const MyCat = () => { }, [rive, user?.cat?.type]); return ( - - navigate(PATH.MY_PAGE)} /> + + + navigate(PATH.MY_PAGE)} /> -
-
- +
+
+ - + -
- +
+ +
-
- - - - + + + + + ); }; diff --git a/src/renderer/pages/mypage.tsx b/src/renderer/pages/mypage.tsx index 76dbd57..d25d6ee 100644 --- a/src/renderer/pages/mypage.tsx +++ b/src/renderer/pages/mypage.tsx @@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { useFocusNotification } from '@/features/time'; import { useUser } from '@/features/user'; import { PATH } from '@/shared/constants'; -import { Frame, Icon, Toggle } from '@/shared/ui'; +import { SidebarLayout, Icon, Toggle } from '@/shared/ui'; const SURVEY_LINK = 'https://docs.google.com/forms/d/e/1FAIpQLSdoFxWJ7TFTU0-HKZEeqmDxz5ZprYtRz08FwrzNgDWnkNaOeA/viewform'; @@ -14,41 +14,52 @@ const MyPage = () => { const { isEnabled, isUnavailable, changeEnabled } = useFocusNotification(); return ( - - navigate(PATH.POMODORO)} /> - -
- navigate(PATH.MY_CAT)}> - 나의 고양이 - {user?.cat?.name} - + +
+
+
+

나의 고양이

+ navigate(PATH.MY_CAT)}> + {user?.cat?.name} + +
- +
+

통계

+ +
-
-
-
-

집중시간 알림받기

-

- 집중・휴식시간이 되면 고양이가 알려줘요 -

+
+

알림

+
+
+
+

집중시간 알림받기

+

+ 집중・휴식시간이 되면 고양이가 알려줘요 +

+
+ { + console.log('pressed', pressed); + changeEnabled(pressed); + }} + /> +
- { - console.log('pressed', pressed); - changeEnabled(pressed); - }} - />
-
- window.open(SURVEY_LINK, '_target')}> - 의견 보내기 - +
+

서비스

+ window.open(SURVEY_LINK, '_target')}> + 의견 보내기 + +
+
- + ); }; @@ -67,10 +78,10 @@ const ActionButton = ({ children, onClick }: ActionButtonProps) => ( ); const ReadyForStat = () => ( -
+
-

통계 기능을 준비하고 있어요

+

통계 기능을 준비하고 있어요

집중시간을 모아보는 통계가
곧 업데이트될 예정이에요 diff --git a/src/renderer/pages/naming.tsx b/src/renderer/pages/naming.tsx index 468d6b4..f2210d8 100644 --- a/src/renderer/pages/naming.tsx +++ b/src/renderer/pages/naming.tsx @@ -7,7 +7,7 @@ import { useUser } from '@/features/user'; import catHomeMotionRiveFile from '@/shared/assets/rivs/cat_home.riv'; import { PATH } from '@/shared/constants'; import { useRiveCat } from '@/shared/hooks'; -import { Button, Frame, Tooltip } from '@/shared/ui'; +import { Button, Frame, SimpleLayout, Tooltip } from '@/shared/ui'; const Naming = () => { const location = useLocation(); @@ -41,47 +41,49 @@ const Naming = () => { }; return ( - - -

-
- - { - clickCatInput?.fire(); - }} - /> -
- - setTypedCatName(e.target.value)} + + + +
+
+ - {errorMessage && ( -
-
- {errorMessage} + { + clickCatInput?.fire(); + }} + /> +
+ + setTypedCatName(e.target.value)} + /> + {errorMessage && ( +
+
+ {errorMessage} +
-
- )} + )} +
-
- - - - + + + + +
); }; diff --git a/src/renderer/pages/onboarding.tsx b/src/renderer/pages/onboarding.tsx index 20de48e..74d5e00 100644 --- a/src/renderer/pages/onboarding.tsx +++ b/src/renderer/pages/onboarding.tsx @@ -7,7 +7,14 @@ import onboardingImage1 from '@/shared/assets/images/onboarding-1.png'; import onboardingImage2 from '@/shared/assets/images/onboarding-2.png'; import onboardingImage3 from '@/shared/assets/images/onboarding-3.png'; import { LOCAL_STORAGE_KEY, PATH } from '@/shared/constants'; -import { Button, Carousel, CarouselContent, CarouselItem, useCarousel } from '@/shared/ui'; +import { + Button, + Carousel, + CarouselContent, + CarouselItem, + SimpleLayout, + useCarousel, +} from '@/shared/ui'; import { cn } from '@/shared/utils'; const Onboarding = () => { @@ -45,56 +52,58 @@ const OnboardingContent = () => { const [, setIsCompleted] = useLocalStorage(LOCAL_STORAGE_KEY.ONBOARDING_COMPLETED, false); return ( -
-
- - {contents.map(({ title, description, imageSrc }, index) => ( - -
- + +
+
+ + {contents.map(({ title, description, imageSrc }, index) => ( + +
+ -
-

{title}

-

{description}

+
+

{title}

+

{description}

+
-
-
- ))} -
+ + ))} + -
    - {contents.map((_, index) => ( -
  • - ))} -
-
+
    + {contents.map((_, index) => ( +
  • + ))} +
+
-
- +
+ +
-
+ ); }; diff --git a/src/renderer/pages/pomodoro.tsx b/src/renderer/pages/pomodoro.tsx index 473c0c5..70ff98a 100644 --- a/src/renderer/pages/pomodoro.tsx +++ b/src/renderer/pages/pomodoro.tsx @@ -9,7 +9,7 @@ import { useFocusNotification } from '@/features/time'; import { useUser } from '@/features/user'; import { MINUTES_GAP } from '@/shared/constants'; import { useDisclosure } from '@/shared/hooks'; -import { useToast } from '@/shared/ui'; +import { SidebarLayout, SimpleLayout, useToast } from '@/shared/ui'; import { createIsoDuration, isoDurationToMs, @@ -140,63 +140,69 @@ const Pomodoro = () => { if (mode === 'focus') return ( - { - startRestWait(); - }} - handleEnd={() => { - endPomodoro(); - }} - /> + + { + startRestWait(); + }} + handleEnd={() => { + endPomodoro(); + }} + /> + ); if (mode === 'rest-wait') return ( - { - updateCategoryTime('focusTime', currentFocusMinutes); - startRest(); - }} - handleEnd={() => { - updateCategoryTime('focusTime', currentFocusMinutes); - endPomodoro(); - }} - /> + + { + updateCategoryTime('focusTime', currentFocusMinutes); + startRest(); + }} + handleEnd={() => { + updateCategoryTime('focusTime', currentFocusMinutes); + endPomodoro(); + }} + /> + ); if (mode === 'rest') return ( - { - updateCategoryTime('restTime', currentRestMinutes); - startFocus(); - }} - handleEnd={() => { - updateCategoryTime('restTime', currentRestMinutes); - endPomodoro(); - }} - /> + + { + updateCategoryTime('restTime', currentRestMinutes); + startFocus(); + }} + handleEnd={() => { + updateCategoryTime('restTime', currentRestMinutes); + endPomodoro(); + }} + /> + ); return ( - <> + { description={timeoutMessageMap[timeoutMode].description} /> )} - + ); }; diff --git a/src/renderer/pages/selection.tsx b/src/renderer/pages/selection.tsx index 702b6df..a6aed4c 100644 --- a/src/renderer/pages/selection.tsx +++ b/src/renderer/pages/selection.tsx @@ -9,7 +9,15 @@ import appIconImage from '@/shared/assets/images/app-icon.png'; import catSelectMotionRiveFile from '@/shared/assets/rivs/cat_select_ver2.0.riv'; import { PATH } from '@/shared/constants'; import { useNotification } from '@/shared/hooks'; -import { Button, Frame, Icon, IconName, SelectGroup, SelectGroupItem } from '@/shared/ui'; +import { + Button, + Frame, + Icon, + IconName, + SimpleLayout, + SelectGroup, + SelectGroupItem, +} from '@/shared/ui'; import { cn } from '@/shared/utils'; const adjectiveMap: Record = { @@ -83,75 +91,77 @@ const Selection = () => { }; return ( - - - -
-
-

어떤 고양이와 함께할까요?

-

언제든지 다른 고양이와 함께할 수 있어요

-
- -
- {!selectedCatId && } - {cats.map((cat) => ( - - {selectedCatId === cat.id && } - - ))} - - {/* TODO: 아래를 선택한 고양이 이미지 에셋으로 변경 */} - -
- - { - setSelectedCatId((prevCatId) => { - const prevCat = cats.find((cat) => cat.id === prevCatId); - const nextCat = cats.find((cat) => cat.id === nextCatId); - - // 다음 고양이 선택이 있으면 해당 input을 fire - // 없으면 처음으로 돌아가기 위해 이전 고양이의 input을 fire - if (nextCat) { - catTypeInputMap[nextCat.type]?.fire(); - } else if (prevCat) { - catTypeInputMap[prevCat.type]?.fire(); - } - - return nextCatId; - }); - }} - > - {cats.map((cat) => ( - - - {cat.adjective} - - + + + +
+
+

어떤 고양이와 함께할까요?

+

언제든지 다른 고양이와 함께할 수 있어요

+
+ +
+ {!selectedCatId && } + {cats.map((cat) => ( + + {selectedCatId === cat.id && } + + ))} + + {/* TODO: 아래를 선택한 고양이 이미지 에셋으로 변경 */} + +
+ + { + setSelectedCatId((prevCatId) => { + const prevCat = cats.find((cat) => cat.id === prevCatId); + const nextCat = cats.find((cat) => cat.id === nextCatId); + + // 다음 고양이 선택이 있으면 해당 input을 fire + // 없으면 처음으로 돌아가기 위해 이전 고양이의 input을 fire + if (nextCat) { + catTypeInputMap[nextCat.type]?.fire(); + } else if (prevCat) { + catTypeInputMap[prevCat.type]?.fire(); + } + + return nextCatId; + }); + }} + > + {cats.map((cat) => ( + - {cat.name} - - - ))} - -
+ + {cat.adjective} + + + {cat.name} + +
+ ))} +
+
- - - - + + + + + ); }; diff --git a/src/renderer/shared/assets/svgs/clock-line.svg b/src/renderer/shared/assets/svgs/clock-line.svg new file mode 100644 index 0000000..7a1b751 --- /dev/null +++ b/src/renderer/shared/assets/svgs/clock-line.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/shared/ui/icon.tsx b/src/renderer/shared/ui/icon.tsx index 48c4472..ab78031 100644 --- a/src/renderer/shared/ui/icon.tsx +++ b/src/renderer/shared/ui/icon.tsx @@ -8,10 +8,11 @@ import CategoryWorkIcon from '@/shared/assets/svgs/category-work.svg'; import CheckIcon from '@/shared/assets/svgs/check.svg?react'; import CheerIcon from '@/shared/assets/svgs/cheer.svg'; import ChevronRightIcon from '@/shared/assets/svgs/chevron-right.svg'; +import ClockLineIcon from '@/shared/assets/svgs/clock-line.svg?react'; import ClockIcon from '@/shared/assets/svgs/clock.svg'; import CloseIcon from '@/shared/assets/svgs/close.svg'; import FocusTimeIcon from '@/shared/assets/svgs/focus-time.svg'; -import MenuIcon from '@/shared/assets/svgs/menu.svg'; +import MenuIcon from '@/shared/assets/svgs/menu.svg?react'; import MinusIcon from '@/shared/assets/svgs/minus.svg'; import MinusSvgIcon from '@/shared/assets/svgs/minus.svg?react'; import PenIcon from '@/shared/assets/svgs/pen.svg'; @@ -48,6 +49,7 @@ const icons = { pen: PenIcon, clock: ClockIcon, readyForStat: ReadyForStatIcon, + clockLine: ClockLineIcon, } as const; const sizes = { xs: 16, diff --git a/src/renderer/shared/ui/index.ts b/src/renderer/shared/ui/index.ts index adc1dfb..858b2eb 100644 --- a/src/renderer/shared/ui/index.ts +++ b/src/renderer/shared/ui/index.ts @@ -11,3 +11,4 @@ export * from './toggle'; export * from './frame'; export * from './guide'; export * from './dialog'; +export * from './layouts'; diff --git a/src/renderer/shared/ui/layouts.tsx b/src/renderer/shared/ui/layouts.tsx new file mode 100644 index 0000000..fb351a0 --- /dev/null +++ b/src/renderer/shared/ui/layouts.tsx @@ -0,0 +1,63 @@ +import { useLocation, useNavigate } from 'react-router-dom'; + +import { PATH } from '../constants'; +import { cn } from '../utils'; + +import { Icon } from './icon'; + +export type SimpleLayoutProps = { + children: React.ReactNode; +}; + +export const SimpleLayout = ({ children }: SimpleLayoutProps) => { + return
{children}
; +}; + +export type SidebarLayoutProps = { + title?: string; + children: React.ReactNode; +}; + +export const SidebarLayout = ({ title, children }: SidebarLayoutProps) => { + return ( +
+
+ +
+
+

{title}

+
+
+ {children} +
+
+ ); +}; + +const DesktopSidebar = () => { + const location = useLocation(); + const navigate = useNavigate(); + + return ( +
+ + +
+ ); +}; diff --git a/src/renderer/widgets/pomodoro/ui/home-screen.tsx b/src/renderer/widgets/pomodoro/ui/home-screen.tsx index 89af9cb..92b14ab 100644 --- a/src/renderer/widgets/pomodoro/ui/home-screen.tsx +++ b/src/renderer/widgets/pomodoro/ui/home-screen.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; import { useLocalStorage } from 'usehooks-ts'; import { CatType } from '@/entities/cat'; @@ -8,7 +7,7 @@ import { useCategories, useUpdateCategory, ChangeCategoryDrawer } from '@/featur import { ChangeTimeDialog } from '@/features/time'; import { useUser } from '@/features/user'; import catHomeMotionRiveFile from '@/shared/assets/rivs/cat_home.riv'; -import { LOCAL_STORAGE_KEY, PATH } from '@/shared/constants'; +import { LOCAL_STORAGE_KEY } from '@/shared/constants'; import { useDisclosure, useRiveCat } from '@/shared/hooks'; import { Button, Guide, Icon, Tooltip, useToast } from '@/shared/ui'; import { getCategoryIconName, createIsoDuration } from '@/shared/utils'; @@ -42,8 +41,6 @@ export const HomeScreen = ({ currentFocusMinutes, currentRestMinutes, }: HomeScreenProps) => { - const navigate = useNavigate(); - const [clickedMode, setClickedMode] = useState<'focus' | 'rest'>('focus'); const [showGuide, setShowGuide] = useLocalStorage(LOCAL_STORAGE_KEY.GUIDE_SHOWN, true); @@ -77,16 +74,6 @@ export const HomeScreen = ({ return ( <>
-
- -