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}