"use client"; import { useState, useEffect, useRef } from "react"; import { Timer, Play, Pause, RotateCcw, Coffee, Zap } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { cn } from "@/lib/utils"; import { toast } from "sonner"; type Mode = "WORK" | "SHORT_BREAK" | "LONG_BREAK"; const CONFIG = { WORK: { time: 25 * 60, label: "工作", color: "text-rose-500", bg: "bg-rose-500" }, SHORT_BREAK: { time: 5 * 60, label: "短休", color: "text-emerald-500", bg: "bg-emerald-500" }, LONG_BREAK: { time: 15 * 60, label: "长休", color: "text-blue-500", bg: "bg-blue-500" } }; export default function PomodoroPage() { const [mode, setMode] = useState("WORK"); const [timeLeft, setTimeLeft] = useState(CONFIG.WORK.time); const [isActive, setIsActive] = useState(false); const timerRef = useRef(null); useEffect(() => { if (isActive && timeLeft > 0) { timerRef.current = setInterval(() => { setTimeLeft((prev) => prev - 1); }, 1000); } else if (timeLeft === 0) { setIsActive(false); handleFinished(); } else { clearInterval(timerRef.current); } return () => clearInterval(timerRef.current); }, [isActive, timeLeft]); const handleFinished = () => { const icon = mode === "WORK" ? : ; const msg = mode === "WORK" ? "工作结束,休息一下吧!" : "休息结束,开始专注吧!"; toast.success(msg, { icon, duration: 5000 }); // Play sound try { const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)(); const oscillator = audioCtx.createOscillator(); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(523.25, audioCtx.currentTime); // C5 oscillator.connect(audioCtx.destination); oscillator.start(); oscillator.stop(audioCtx.currentTime + 0.5); } catch {} }; const toggleTimer = () => setIsActive(!isActive); const resetTimer = () => { setIsActive(false); setTimeLeft(CONFIG[mode].time); }; const changeMode = (newMode: Mode) => { setMode(newMode); setIsActive(false); setTimeLeft(CONFIG[newMode].time); }; const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; const progress = timeLeft / CONFIG[mode].time; return (

番茄钟

专注工作,科学休息 (Pomodoro Technique)

changeMode("WORK")} /> changeMode("SHORT_BREAK")} /> changeMode("LONG_BREAK")} />
{formatTime(timeLeft)} {CONFIG[mode].label}ING
{/* Spacer */}
); } function ModeButton({ active, label, onClick }: { active: boolean, label: string, onClick: () => void }) { return ( ); }