UNPKG

pomo-tui

Version:

> A beautiful terminal-based Pomodoro timer built with React Ink

108 lines (107 loc) 4.11 kB
import React, { useState, useEffect } from 'react'; import { Box, Text, useInput } from 'ink'; import Gradient from 'ink-gradient'; import BigText from 'ink-big-text'; import { cycleGradient, cyclePreviousGradient } from './colors.js'; const StopWatch = ({ onActiveChange, initialTheme = 'rainbow', }) => { const [seconds, setSeconds] = useState(0); const [isActive, setIsActive] = useState(false); const [stopTime, setStopTime] = useState(300); // Default 5 minutes const [theme, setTheme] = useState(initialTheme); useEffect(() => { let interval = null; if (isActive && seconds > 0) { interval = setInterval(() => { setSeconds(seconds => { const newSeconds = seconds - 1; if (newSeconds === 0) { setIsActive(false); onActiveChange?.(false); } return newSeconds; }); }, 1000); } return () => { if (interval) clearInterval(interval); }; }, [isActive, onActiveChange]); const formatTime = () => { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; return [ hours.toString().padStart(2, '0'), minutes.toString().padStart(2, '0'), secs.toString().padStart(2, '0'), ].join(':'); }; const toggle = () => { const newActive = !isActive; if (newActive && seconds === 0) { setSeconds(stopTime); } setIsActive(newActive); if (onActiveChange) { onActiveChange(newActive); } }; const reset = () => { setSeconds(stopTime); setIsActive(false); onActiveChange?.(false); }; useInput((input, key) => { if (input === 'p') { toggle(); } if (input === 'r') { reset(); } if (!isActive && (key.leftArrow || key.rightArrow)) { const step = 60; // Change by 1 minute const newTime = key.leftArrow ? Math.max(60, stopTime - step) : stopTime + step; setStopTime(newTime); setSeconds(newTime); } if (input === '[' || input === ']') { setTheme(input === '[' ? cyclePreviousGradient(theme) : cycleGradient(theme)); } }); return (React.createElement(Box, { flexDirection: "column", padding: 1, alignItems: "center", justifyContent: "center" }, React.createElement(Box, { marginBottom: 1, alignItems: "center" }, React.createElement(Text, null, "Set Time: ", Math.floor(stopTime / 60), " minutes (\u2190 \u2192)")), React.createElement(Box, { marginBottom: 1, alignItems: "center" }, React.createElement(Text, null, "Theme: ", theme, " ([ ])")), React.createElement(Box, { marginBottom: 1, alignItems: "center" }, React.createElement(Gradient, { name: theme }, React.createElement(BigText, { font: "chrome", text: formatTime() }))), React.createElement(Box, { alignItems: "center" }, React.createElement(Text, null, "Status:", ' ', React.createElement(Text, { color: isActive ? 'green' : 'yellow' }, isActive ? 'Running' : 'Paused'))), React.createElement(Box, { marginTop: 1, alignItems: "center" }, React.createElement(Text, null, "Press", ' ', React.createElement(Text, { bold: true, color: "blue" }, "p"), ' ', "to ", isActive ? 'pause' : 'start', ",", ' ', React.createElement(Text, { bold: true, color: "red" }, "r"), ' ', "to reset")))); }; export default StopWatch;