diff --git a/apps/timo-web/app/[locale]/onboarding/_components/.gitkeep b/apps/timo-web/app/[locale]/onboarding/_components/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/timo-web/app/[locale]/onboarding/_components/OnboardingButton.tsx b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingButton.tsx new file mode 100644 index 00000000..7f4251ab --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingButton.tsx @@ -0,0 +1,71 @@ +import { + ChevronLeftIcon, + ChevronSmallRightIcon, + ChevronSmallRightWhiteIcon, +} from "@repo/timo-design-system/icons"; +import { cn } from "@repo/timo-design-system/utils"; + +export interface OnboardingButtonProps { + variant: "next" | "prev" | "start"; + label: string; + isActive?: boolean; + disabled?: boolean; + onClick?: () => void; +} + +export const OnboardingButton = ({ + variant, + label, + isActive = false, + disabled = false, + onClick, +}: OnboardingButtonProps) => { + if (variant === "prev") { + return ( + + ); + } + + if (variant === "start") { + return ( + + ); + } + + const isDisabled = disabled || !isActive; + + return ( + + ); +}; diff --git a/apps/timo-web/app/[locale]/onboarding/_components/OnboardingGoogleButton.tsx b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingGoogleButton.tsx new file mode 100644 index 00000000..c898324b --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingGoogleButton.tsx @@ -0,0 +1,38 @@ +import googleLogo from "@repo/timo-design-system/assets/images/google-logo.svg"; +import { cn } from "@repo/timo-design-system/utils"; +import Image from "next/image"; + +type OnboardingGoogleButtonVariant = "login" | "connectCalendar"; + +interface OnboardingGoogleButtonProps { + variant: OnboardingGoogleButtonVariant; + label: string; + isSelected?: boolean; + onClick?: () => void; +} + +export const OnboardingGoogleButton = ({ + label, + isSelected = false, + onClick, +}: OnboardingGoogleButtonProps) => { + return ( + + ); +}; diff --git a/apps/timo-web/app/[locale]/onboarding/_components/OnboardingStepButton.tsx b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingStepButton.tsx new file mode 100644 index 00000000..d2be88f1 --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingStepButton.tsx @@ -0,0 +1,32 @@ +import { cn } from "@repo/timo-design-system/utils"; + +interface OnboardingStepButtonProps { + step: 1 | 2 | 3 | 4; +} + +const STEPS = [1, 2, 3, 4] as const; + +export const OnboardingStepButton = ({ step }: OnboardingStepButtonProps) => { + return ( +
    + {STEPS.map((s) => ( +
  1. + + {s} + +
  2. + ))} +
+ ); +}; diff --git a/apps/timo-web/app/[locale]/onboarding/_components/OnboardingTimeDropdown.tsx b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingTimeDropdown.tsx new file mode 100644 index 00000000..196a2507 --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_components/OnboardingTimeDropdown.tsx @@ -0,0 +1,64 @@ +import { + ChevronDownGrayIcon, + ChevronUpGrayIcon, +} from "@repo/timo-design-system/icons"; +import { Dropdown } from "@repo/timo-design-system/ui"; +import { cn } from "@repo/timo-design-system/utils"; + +import { getAmPm } from "@/utils/get-am-pm"; + +const TIME_OPTIONS = Array.from( + { length: 25 }, + (_, i) => `${String(i).padStart(2, "0")}:00`, +); + +interface OnboardingTimeDropdownProps { + value: string; + placeholder?: string; + onChange: (time: string) => void; +} + +export const OnboardingTimeDropdown = ({ + value, + placeholder, + onChange, +}: OnboardingTimeDropdownProps) => { + return ( + + + {value ? ( +
+ {value} + + {getAmPm(value)} + +
+ ) : ( + + {placeholder} + + )} + + +
+ + +
+ {TIME_OPTIONS.map((time) => ( + onChange(time)} + className={cn( + "typo-headline-b-16 flex w-full justify-between rounded-none", + value === time ? "text-timo-blue-300" : "text-timo-gray-700", + )} + > + {time} + {getAmPm(time)} + + ))} +
+
+
+ ); +}; diff --git a/apps/timo-web/app/[locale]/onboarding/_containers/.gitkeep b/apps/timo-web/app/[locale]/onboarding/_containers/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingButtonContainer.tsx b/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingButtonContainer.tsx new file mode 100644 index 00000000..368e18c1 --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingButtonContainer.tsx @@ -0,0 +1,31 @@ +"use client"; + +import { useTranslations } from "next-intl"; + +import { OnboardingButton } from "@/app/[locale]/onboarding/_components/OnboardingButton"; + +interface OnboardingButtonContainerProps { + variant: "next" | "prev" | "start"; + isActive?: boolean; + disabled?: boolean; + onClick?: () => void; +} + +export const OnboardingButtonContainer = ({ + variant, + isActive, + disabled, + onClick, +}: OnboardingButtonContainerProps) => { + const t = useTranslations("Onboarding"); + + return ( + + ); +}; diff --git a/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingGoogleButtonContainer.tsx b/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingGoogleButtonContainer.tsx new file mode 100644 index 00000000..821d5cb6 --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingGoogleButtonContainer.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { useTranslations } from "next-intl"; + +import { OnboardingGoogleButton } from "@/app/[locale]/onboarding/_components/OnboardingGoogleButton"; + +interface OnboardingGoogleButtonContainerProps { + variant: "login" | "connectCalendar"; + isSelected?: boolean; + onClick?: () => void; +} + +export const OnboardingGoogleButtonContainer = ({ + variant, + isSelected, + onClick, +}: OnboardingGoogleButtonContainerProps) => { + const t = useTranslations("Onboarding"); + + return ( + + ); +}; diff --git a/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingTimeContainer.tsx b/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingTimeContainer.tsx new file mode 100644 index 00000000..3bf7f761 --- /dev/null +++ b/apps/timo-web/app/[locale]/onboarding/_containers/OnboardingTimeContainer.tsx @@ -0,0 +1,17 @@ +"use client"; + +import { useState } from "react"; + +import { OnboardingTimeDropdown } from "@/app/[locale]/onboarding/_components/OnboardingTimeDropdown"; + +export const OnboardingTimeContainer = () => { + const [time, setTime] = useState(""); + + return ( + + ); +}; diff --git a/apps/timo-web/messages/en.json b/apps/timo-web/messages/en.json index 649a0486..342501de 100644 --- a/apps/timo-web/messages/en.json +++ b/apps/timo-web/messages/en.json @@ -40,5 +40,16 @@ "tagLimit": "You can create up to 8 tags, and to add more, please delete existing tags.", "todoLimitLine1": "You can add up to 20 incomplete to-dos.", "todoLimitLine2": "To add a new to-do, please complete an existing one." + }, + "Onboarding": { + "button": { + "next": "Next", + "prev": "Previous", + "start": "Get Started" + }, + "onboardingGoogleButton": { + "login": "Continue with your Google account", + "connectCalendar": "Connect Google Calendar" + } } } diff --git a/apps/timo-web/messages/ko.json b/apps/timo-web/messages/ko.json index cf175e99..ee4fa36c 100644 --- a/apps/timo-web/messages/ko.json +++ b/apps/timo-web/messages/ko.json @@ -40,5 +40,16 @@ "tagLimit": "태그는 최대 8개까지 만들 수 있으며, 추가하려면 기존 태그를 삭제해 주세요.", "todoLimitLine1": "완료되지 않은 투두는 최대 20개까지 추가할 수 있어요.", "todoLimitLine2": "새로운 투두를 추가하려면 기존 투두를 완료해주세요." + }, + "Onboarding": { + "button": { + "next": "다음", + "prev": "이전", + "start": "시작하기" + }, + "onboardingGoogleButton": { + "login": "Google 계정으로 계속하기", + "connectCalendar": "Google 캘린더 연결하기" + } } } diff --git a/apps/timo-web/utils/get-am-pm.ts b/apps/timo-web/utils/get-am-pm.ts new file mode 100644 index 00000000..ccae4dbc --- /dev/null +++ b/apps/timo-web/utils/get-am-pm.ts @@ -0,0 +1,13 @@ +const HOURS_IN_DAY = 24; + +/** + * "HH:MM" 형식의 시간 문자열에서 오전/오후를 판별합니다. + * 24시("24:00")는 다음날 자정(오전)으로 취급합니다. + * + * @param time - "HH:MM" 형식의 시간 문자열 + * @returns "AM" 또는 "PM" + */ +export const getAmPm = (time: string): "AM" | "PM" => { + const hour = parseInt(time.split(":")[0] ?? "0", 10); + return hour >= 12 && hour < HOURS_IN_DAY ? "PM" : "AM"; +}; diff --git a/packages/tailwind-config/scrollbar.css b/packages/tailwind-config/scrollbar.css index 94bd10b5..1b07c7fd 100644 --- a/packages/tailwind-config/scrollbar.css +++ b/packages/tailwind-config/scrollbar.css @@ -4,8 +4,8 @@ } *::-webkit-scrollbar { - width: 6px; - height: 6px; + width: 8px; + height: 8px; } *::-webkit-scrollbar-track { diff --git a/packages/timo-design-system/src/assets/images/google-logo.svg b/packages/timo-design-system/src/assets/images/google-logo.svg new file mode 100644 index 00000000..8869c6c0 --- /dev/null +++ b/packages/timo-design-system/src/assets/images/google-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-down-gray.svg b/packages/timo-design-system/src/icons/source/chevron-down-gray.svg new file mode 100644 index 00000000..21f4c88f --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-down-gray.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-small-down.svg b/packages/timo-design-system/src/icons/source/chevron-small-down.svg new file mode 100644 index 00000000..2b76ab00 --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-small-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-small-left.svg b/packages/timo-design-system/src/icons/source/chevron-small-left.svg new file mode 100644 index 00000000..7ef41ae7 --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-small-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-small-right-white.svg b/packages/timo-design-system/src/icons/source/chevron-small-right-white.svg new file mode 100644 index 00000000..b2ddad4b --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-small-right-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-small-right.svg b/packages/timo-design-system/src/icons/source/chevron-small-right.svg new file mode 100644 index 00000000..6354043b --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-small-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-small-up.svg b/packages/timo-design-system/src/icons/source/chevron-small-up.svg new file mode 100644 index 00000000..6f46161e --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-small-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/timo-design-system/src/icons/source/chevron-up-gray.svg b/packages/timo-design-system/src/icons/source/chevron-up-gray.svg new file mode 100644 index 00000000..6a574c1d --- /dev/null +++ b/packages/timo-design-system/src/icons/source/chevron-up-gray.svg @@ -0,0 +1,3 @@ + + +