diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeTodoCard.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeTodoCard.tsx index b6f5dbcd..e19edb94 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeTodoCard.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeTodoCard.tsx @@ -49,6 +49,7 @@ export interface HomeTodoCardProps { hasMemo: boolean; isRepeated: boolean; timerStatus: TodoTimerStatusTypes; + isPlayHighlighted: boolean; subtaskTitle?: string; isSubtaskCompleted?: boolean; onClickTodo?: () => void; @@ -67,6 +68,7 @@ export const HomeTodoCard = ({ hasMemo, isRepeated, timerStatus, + isPlayHighlighted, subtaskTitle, isSubtaskCompleted = false, onClickTodo, @@ -131,6 +133,7 @@ export const HomeTodoCard = ({ variant={isRunning ? "stop" : "play"} size="sm" disabled={isCompleted} + active={isPlayHighlighted} onClick={handlePlayClick} onPointerDown={stopInteractiveEvent} > @@ -138,8 +141,10 @@ export const HomeTodoCard = ({ ) : isRunning ? ( - ) : ( + ) : isPlayHighlighted ? ( + ) : ( + )} diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx index 8c7f75f0..83ba1415 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx @@ -138,6 +138,8 @@ export const HomeTodoContainer = () => { const timerStatus = isActiveTodo ? activeTimer.status : todo.timerStatus; + const isPlayHighlighted = + !activeTimer || Boolean(isActiveTodo); const todoTagLabelKey = todo.tag ? getDefaultTagLabelKey(todo.tag.tagId) @@ -172,6 +174,7 @@ export const HomeTodoContainer = () => { hasMemo={todo.hasMemo} isRepeated={todo.isRepeated} timerStatus={timerStatus} + isPlayHighlighted={isPlayHighlighted} subtaskTitle={firstSubtask?.content} isSubtaskCompleted={firstSubtask?.completed} onClickTodo={openDetailTodoModal} diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx index e222ec28..ab6afa60 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx @@ -17,6 +17,7 @@ export interface TodayTodoCardContainerProps { subTodos: SubTodo[]; toolbar: TodayTodoCardToolbar; timerStatus: TodoTimerStatusTypes; + isPlayHighlighted: boolean; icon?: ReactNode; onCardClick?: () => void; onToggleCompleted?: (completed: boolean) => void; @@ -31,6 +32,7 @@ export const TodayTodoCardContainer = ({ subTodos, toolbar, timerStatus, + isPlayHighlighted, onCardClick, onToggleCompleted, onTogglePlay, @@ -47,6 +49,7 @@ export const TodayTodoCardContainer = ({ isDone={isCompleted} isDimmed={isDimmed} isPlaying={isPlaying} + isPlayHighlighted={isPlayHighlighted} icon={icon} subTodos={subTodos} toolbar={toolbar} diff --git a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx index 6f973645..360de333 100644 --- a/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx +++ b/apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx @@ -92,6 +92,7 @@ export const TodayTodoListContainer = () => { const timerStatus = isActiveTodo ? activeTimer.status : todo.timerStatus; + const isPlayHighlighted = !activeTimer || Boolean(isActiveTodo); return ( { isCompleted={todo.completed} icon={renderTodoIcon(todo.icon)} timerStatus={timerStatus} + isPlayHighlighted={isPlayHighlighted} toolbar={{ date: formatDate(todo.date), dateValue: new Date(todo.date), diff --git a/apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx b/apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx index 6003adc2..f8d279a5 100644 --- a/apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx +++ b/apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx @@ -49,6 +49,7 @@ export interface TodayTodoCardProps { isDone: boolean; isDimmed: boolean; isPlaying: boolean; + isPlayHighlighted: boolean; icon?: ReactNode; subTodos: SubTodo[]; toolbar: TodayTodoCardToolbar; @@ -68,6 +69,7 @@ export const TodayTodoCard = ({ isDone, isDimmed, isPlaying, + isPlayHighlighted, icon, subTodos, toolbar, @@ -123,14 +125,17 @@ export const TodayTodoCard = ({ variant={isPlaying ? "stop" : "play"} size="lg" disabled={isDone} + active={isPlayHighlighted} onClick={onPlay} > {isDone ? ( ) : isPlaying ? ( - ) : ( + ) : isPlayHighlighted ? ( + ) : ( + )} diff --git a/apps/timo-web/components/todo-modal/detail/DetailTodoModalContent.tsx b/apps/timo-web/components/todo-modal/detail/DetailTodoModalContent.tsx index dad126c1..9d4f162c 100644 --- a/apps/timo-web/components/todo-modal/detail/DetailTodoModalContent.tsx +++ b/apps/timo-web/components/todo-modal/detail/DetailTodoModalContent.tsx @@ -40,6 +40,7 @@ export interface DetailTodoModalContentProps { onClose: () => void; onExited: () => void; todo: TodoDetailResponse; + isPlayHighlighted: boolean; onTogglePlay: () => void; onToggleCompleted: (completed: boolean) => void; onDelete: () => void; @@ -51,6 +52,7 @@ export const DetailTodoModalContent = ({ onClose, onExited, todo, + isPlayHighlighted, onTogglePlay, onToggleCompleted, onDelete, @@ -227,6 +229,7 @@ export const DetailTodoModalContent = ({ isCompleted={todo.completed} disabled={!canUpdateTodo} timerStatus={todo.timerStatus} + isPlayHighlighted={isPlayHighlighted} subtaskInputs={detailTodoForm.subtaskInputs} onTitleChange={detailTodoForm.changeTitle} onToggleCompleted={onToggleCompleted} diff --git a/apps/timo-web/components/todo-modal/detail/DetailTodoTaskFields.tsx b/apps/timo-web/components/todo-modal/detail/DetailTodoTaskFields.tsx index e4a5f676..a3e1db31 100644 --- a/apps/timo-web/components/todo-modal/detail/DetailTodoTaskFields.tsx +++ b/apps/timo-web/components/todo-modal/detail/DetailTodoTaskFields.tsx @@ -20,6 +20,7 @@ export interface DetailTodoTaskFieldsProps { isCompleted: boolean; disabled?: boolean; timerStatus: TodoDetailResponseTimerStatus; + isPlayHighlighted: boolean; subtaskInputs: DetailTodoSubtaskInput[]; onTitleChange: (value: string) => void; onToggleCompleted: (completed: boolean) => void; @@ -40,6 +41,7 @@ export const DetailTodoTaskFields = ({ isCompleted, disabled = false, timerStatus, + isPlayHighlighted, subtaskInputs, onTitleChange, onToggleCompleted, @@ -72,14 +74,17 @@ export const DetailTodoTaskFields = ({ variant={timerStatus === "RUNNING" ? "stop" : "play"} size="lg" disabled={isCompleted} + active={isPlayHighlighted} onClick={onTogglePlay} > {isCompleted ? ( ) : timerStatus === "RUNNING" ? ( - ) : ( + ) : isPlayHighlighted ? ( + ) : ( + )} diff --git a/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx b/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx index c506c341..ee442775 100644 --- a/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx +++ b/apps/timo-web/containers/todo-modal/detail/DetailTodoModalContainer.tsx @@ -11,6 +11,7 @@ import { AnimatedToast } from "@/components/toast/AnimatedToast"; import { DetailTodoModalContent } from "@/components/todo-modal/detail/DetailTodoModalContent"; import { useDeleteTodoSubmit } from "@/hooks/todo-modal/detail/use-delete-todo-submit"; import { useUpdateTodoSubmit } from "@/hooks/todo-modal/detail/use-update-todo-submit"; +import { useActiveTimer } from "@/hooks/use-active-timer"; export interface DetailTodoModalContainerProps { todoId: number; @@ -42,7 +43,9 @@ export const DetailTodoModalContainer = ({ ); const { handleDelete } = useDeleteTodoSubmit(); const { handleUpdate } = useUpdateTodoSubmit(); + const { data: activeTimer } = useActiveTimer(); const todo = data?.data; + const isPlayHighlighted = !activeTimer || activeTimer.todoId === todoId; const openDetailTodoModal = () => { setIsMounted(true); @@ -89,6 +92,7 @@ export const DetailTodoModalContainer = ({ onClose={closeDetailTodoModal} onExited={() => setIsMounted(false)} todo={todo} + isPlayHighlighted={isPlayHighlighted} onTogglePlay={onTogglePlay} onToggleCompleted={onToggleCompleted} onDelete={deleteTodo} diff --git a/packages/timo-design-system/src/components/button/play-button/PlayButton.tsx b/packages/timo-design-system/src/components/button/play-button/PlayButton.tsx index 67097b3c..ce3f2af9 100644 --- a/packages/timo-design-system/src/components/button/play-button/PlayButton.tsx +++ b/packages/timo-design-system/src/components/button/play-button/PlayButton.tsx @@ -2,7 +2,6 @@ import { cn } from "../../../lib"; import type { MouseEventHandler, PointerEventHandler, ReactNode } from "react"; - export type PlayButtonVariant = "play" | "stop"; export type PlayButtonSize = "sm" | "lg"; @@ -10,18 +9,17 @@ export interface PlayButtonProps { variant: PlayButtonVariant; size?: PlayButtonSize; disabled?: boolean; + /** 다른 항목에 활성 타이머가 있어 이 버튼을 시각적으로 낮춰야 할 때 false로 준다 (클릭은 계속 가능) */ + active?: boolean; onClick?: MouseEventHandler; onPointerDown?: PointerEventHandler; children?: ReactNode; ariaLabel?: string; } -const VARIANT_MAP: Record< - PlayButtonVariant, - { className: string; label: string } -> = { - play: { className: "cursor-pointer bg-timo-blue-50", label: "재생" }, - stop: { className: "cursor-pointer bg-timo-blue-50", label: "정지" }, +const VARIANT_LABEL: Record = { + play: "재생", + stop: "정지", }; const SIZE_CLASS: Record = { @@ -33,6 +31,7 @@ export const PlayButton = ({ variant, size = "sm", disabled = false, + active = true, onClick, onPointerDown, children, @@ -46,16 +45,16 @@ export const PlayButton = ({ disabled={disabled} aria-label={ ariaLabel ?? - (disabled - ? `${VARIANT_MAP[variant].label} 불가` - : VARIANT_MAP[variant].label) + (disabled ? `${VARIANT_LABEL[variant]} 불가` : VARIANT_LABEL[variant]) } className={cn( - "inline-flex items-center justify-center rounded-full", + "inline-flex cursor-pointer items-center justify-center rounded-full", SIZE_CLASS[size], disabled ? "bg-timo-gray-500 cursor-not-allowed" - : VARIANT_MAP[variant].className, + : active + ? "bg-timo-blue-50" + : "bg-timo-gray-500", )} > {children}