pomo-tui
Version:
> A beautiful terminal-based Pomodoro timer built with React Ink
102 lines (101 loc) • 4.49 kB
JavaScript
import React, { useState } from 'react';
import { Box, Text, useInput } from 'ink';
import TextInput from 'ink-text-input';
import SelectInput from 'ink-select-input';
import { Timer } from './timer.js';
export function Pomodoro({ onActiveChange }) {
const [inputValue, setInputValue] = useState('');
const [sessionName, setSessionName] = useState('');
const [sessionDuration, setSessionDuration] = useState(null);
const [activeSession, setActiveSession] = useState(null);
const [callbackList, setCallbackList] = useState([]);
const handleNameChange = (value) => {
setInputValue(value);
};
const handleNameSubmit = (value) => {
if (value.trim()) {
setSessionName(value.trim());
setInputValue('');
}
};
const startSession = (duration) => {
const breakDuration = duration === 25 ? 5 : 10;
setSessionDuration(duration);
setActiveSession({
name: sessionName,
sessionDuration: duration,
breakDuration,
remainingTime: duration * 60,
isBreak: false,
});
onActiveChange(true);
};
useInput(input => {
if (sessionName && !sessionDuration) {
if (input === 'i') {
startSession(25);
}
else if (input === 'j') {
startSession(50);
}
}
});
const handlePause = (remainingTime) => {
if (activeSession) {
setCallbackList([...callbackList, { ...activeSession, remainingTime }]);
setActiveSession(null);
onActiveChange(false);
}
};
const handleSessionComplete = () => {
if (activeSession) {
setActiveSession({
...activeSession,
remainingTime: activeSession.breakDuration * 60,
isBreak: true,
});
}
};
const handleBreakComplete = () => {
setActiveSession(null);
setSessionName('');
setSessionDuration(null);
onActiveChange(false);
};
const handleSessionResume = (session) => {
setActiveSession(session);
setCallbackList(callbackList.filter(s => s.name !== session.name));
onActiveChange(true);
};
if (activeSession) {
return (React.createElement(Box, { flexDirection: "column", alignItems: "center" },
React.createElement(Text, null,
activeSession.name,
" -",
' ',
activeSession.isBreak ? 'Break Time' : 'Focus Time'),
React.createElement(Timer, { initialSeconds: activeSession.remainingTime, onPause: handlePause, onComplete: activeSession.isBreak ? handleBreakComplete : handleSessionComplete, onActiveChange: onActiveChange, isCountdown: true }),
activeSession.isBreak && React.createElement(Text, null, "Time for a break!")));
}
return (React.createElement(Box, { flexDirection: "column", alignItems: "center" },
!sessionName && (React.createElement(Box, { flexDirection: "column", alignItems: "center" },
React.createElement(Text, null, "Enter session name and press Enter:"),
React.createElement(TextInput, { value: inputValue, onChange: handleNameChange, onSubmit: handleNameSubmit }))),
sessionName && !sessionDuration && (React.createElement(Box, { flexDirection: "column", alignItems: "center" },
React.createElement(Text, null, "Select session duration:"),
React.createElement(Text, null,
"Press ",
React.createElement(Text, { color: "blue" }, "i"),
" for 25 minutes (5 min break)"),
React.createElement(Text, null,
"Press ",
React.createElement(Text, { color: "blue" }, "j"),
" for 50 minutes (10 min break)"))),
callbackList.length > 0 && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
React.createElement(Text, null, "Callback List:"),
React.createElement(Box, null,
React.createElement(SelectInput, { items: callbackList.map(session => ({
label: `${session.name} (${Math.floor(session.remainingTime / 60)}:${String(session.remainingTime % 60).padStart(2, '0')})`,
value: session,
})), onSelect: item => handleSessionResume(item.value) }))))));
}