» React创建番茄工作法Pomodoro Web应用 » 2. 开发 » 2.4 休息间隔

休息间隔

定义定时器的两种阶段:PHASE_POMODORO (工作阶段,25 分钟) and PHASE_BREAK (休息阶段,5 分钟)。

你可以通过药丸按钮直接跳转到对应的阶段。或者,你也可以点击 “skip” 按钮跳过当前阶段

@@ -3,10 +3,14 @@ import "./App.css";
 import { formatTime } from "./util";
 
 const POMODORO_SECONDS = 25 * 60;
+const BREAK_SECONDS = 5 * 60;
+const PHASE_POMODORO = 0;
+const PHASE_BREAK = 1;
 
 function App() {
   const [seconds, setSeconds] = useState(POMODORO_SECONDS);
   const [ticking, setTicking] = useState(false);
+  const [phase, setPhase] = useState(PHASE_POMODORO);
 
   useEffect(() => {
     if (seconds === 0) {
@@ -32,23 +36,47 @@ function App() {
     }
   };
 
-  const resetTimer = () => {
+  const resetTimer = (phase) => {
     stopTimer();
-    setSeconds(POMODORO_SECONDS);
+    setSeconds(phase === PHASE_POMODORO ? POMODORO_SECONDS : BREAK_SECONDS);
   };
 
   const toggleTimer = () => {
     if (ticking) {
+      // Clicked "Pause"
       stopTimer();
     } else {
-      startTimer();
+      if (seconds === 0) {
+        // Clicked "Next"
+        skipPhase();
+      } else {
+        // Clicked "Start"
+        startTimer();
+      }
     }
   };
 
+  const pickPhase = (phase) => {
+    const secBg = "secondary-bg";
+    if (phase === PHASE_POMODORO) {
+      document.body.classList.remove(secBg);
+    } else {
+      document.body.classList.add(secBg);
+    }
+    setPhase(phase);
+    resetTimer(phase);
+  };
+
+  const skipPhase = () => {
+    const newPhase = (phase + 1) % 2;
+    pickPhase(newPhase);
+  };
+
   const alarm = () => {
     // TODO: 播放音效
     console.log("Time's up!");
   };
+
   return (
     <div className="app">
       <h1 className="app-name">
@@ -57,17 +85,41 @@ function App() {
         Pomodoro
       </h1>
       <div className="segments">
-        <span className="segment left-seg picked">Pomodoro</span>
-        <span className="segment right-seg">Break</span>
+        <span
+          className={`segment left-seg ${
+            phase === PHASE_POMODORO ? "picked" : ""
+          }`}
+          onClick={() => pickPhase(PHASE_POMODORO)}
+        >
+          Pomodoro
+        </span>
+        <span
+          className={`segment right-seg ${
+            phase === PHASE_BREAK ? "picked" : ""
+          }`}
+          onClick={() => pickPhase(PHASE_BREAK)}
+        >
+          Break
+        </span>
       </div>
       <div className="card">
         <h1 className="timer">{formatTime(seconds)}</h1>
-        <button className="control-btn" onClick={toggleTimer}>
-          {ticking ? "Pause" : "Start"}
-        </button>
+        <div>
+          <button
+            className={`control-btn ${
+              phase === PHASE_BREAK ? "secondary-control-btn" : ""
+            }`}
+            onClick={toggleTimer}
+          >
+            {ticking ? "Pause" : seconds === 0 ? "Next" : "Start"}
+          </button>
+        </div>
+        <span className="skip-btn" onClick={skipPhase}>
+          skip
+        </span>
       </div>
       <div className="settings">
-        <span className="setting-btn" onClick={resetTimer}>
+        <span className="setting-btn" onClick={() => resetTimer(phase)}>
           Reset
         </span>
         <span className="setting-btn">Settings</span>

为 “skip” 按钮添加样式,并为“休息”阶段添加主题色。

@@ -1,8 +1,17 @@
+:root {
+  --primary-color: #F28585;
+  --secondary-color: #FFA447;
+}
+
 body {
-  background-color: #F28585;
+  background-color: var(--primary-color);
   font-family: Geneva, Verdana, Tahoma, sans-serif;
 }
 
+.secondary-bg {
+  background-color: var(--secondary-color);
+}
+
 .app {
   margin: 15vh auto;
   width: 24rem;
@@ -73,5 +82,17 @@ body {
   border-bottom: solid 5px lightcoral;
   border-radius: 0.5rem;
   cursor: pointer;
-  color: #F28585;
+  color: var(--primary-color);
+}
+
+.skip-btn {
+  font-size: small;
+  cursor: pointer;
+  float: right;
+  margin-top: -1.5rem;
+}
+
+.secondary-control-btn {
+  color: var(--secondary-color);
+  border-bottom-color: goldenrod;
 }

现在,界面效果如下:

Break Timer