feat: add controls to pomodoro

This commit is contained in:
MAZE 2024-02-25 15:04:25 +03:30
parent 9f7de336e5
commit 7ed016d855
7 changed files with 147 additions and 11 deletions

View file

@ -0,0 +1,19 @@
.button {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
font-size: var(--font-xsm);
color: var(--color-foreground);
cursor: pointer;
background-color: var(--color-neutral-100);
border: 1px solid var(--color-neutral-200);
border-radius: 4px;
outline: none;
transition: 0.2s;
&:hover {
background-color: var(--color-neutral-200);
}
}

View file

@ -0,0 +1,19 @@
import { Tooltip } from '@/components/tooltip';
import styles from './button.module.css';
interface ButtonProps {
icon: React.ReactElement;
onClick: () => void;
tooltip: string;
}
export function Button({ icon, onClick, tooltip }: ButtonProps) {
return (
<Tooltip content={tooltip} hideDelay={0} placement="bottom" showDelay={0}>
<button className={styles.button} onClick={onClick}>
{icon}
</button>
</Tooltip>
);
}

View file

@ -0,0 +1 @@
export { Button } from './button';

View file

@ -1 +1,17 @@
/* TODO */
.control {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
& .completed {
font-size: var(--font-xsm);
color: var(--color-foreground-subtle);
}
& .buttons {
display: flex;
column-gap: 4px;
align-items: center;
}
}

View file

@ -1,10 +1,12 @@
import { useState } from 'react';
import { useState, useEffect, useRef, useMemo } from 'react';
import { FaUndo, FaPlay, FaPause } from 'react-icons/fa/index';
import { Modal } from '@/components/modal';
import { Tabs } from './tabs';
import { Timer } from './timer';
import { Button } from './button';
// import styles from './pomodoro.module.css';
import styles from './pomodoro.module.css';
interface PomodoroProps {
onClose: () => void;
@ -13,18 +15,84 @@ interface PomodoroProps {
export function Pomodoro({ onClose, show }: PomodoroProps) {
const [selectedTab, setSelectedTab] = useState('pomodoro');
const [running, setRunning] = useState(false);
const [timer, setTimer] = useState(10);
const interval = useRef<ReturnType<typeof setInterval> | null>(null);
const tabs = [
{ id: 'pomodoro', label: 'Pomodoro' },
{ id: 'short', label: 'Break' },
{ id: 'long', label: 'Long Break' },
];
const tabs = useMemo(
() => [
{ id: 'pomodoro', label: 'Pomodoro', time: 60 },
{ id: 'short', label: 'Break', time: 60 },
{ id: 'long', label: 'Long Break', time: 60 },
],
[],
);
useEffect(() => {
if (running) {
if (interval.current) clearInterval(interval.current);
interval.current = setInterval(() => {
setTimer(prev => prev - 1);
}, 1000);
} else {
if (interval.current) clearInterval(interval.current);
}
}, [running]);
useEffect(() => {
if (timer <= 0) {
if (interval.current) clearInterval(interval.current);
setRunning(false);
}
}, [timer]);
useEffect(() => {
const time = tabs.find(tab => tab.id === selectedTab)?.time || 10;
if (interval.current) clearInterval(interval.current);
setRunning(false);
setTimer(time);
}, [selectedTab, tabs]);
const toggleRunning = () => {
if (running) setRunning(false);
else if (timer <= 0) {
const time = tabs.find(tab => tab.id === selectedTab)?.time || 10;
setTimer(time);
setRunning(true);
} else setRunning(true);
};
const restart = () => {
if (interval.current) clearInterval(interval.current);
const time = tabs.find(tab => tab.id === selectedTab)?.time || 10;
setRunning(false);
setTimer(time);
};
return (
<Modal show={show} onClose={onClose}>
<h1>Pomodoro Timer</h1>
<Tabs selectedTab={selectedTab} tabs={tabs} onSelect={setSelectedTab} />
<Timer />
<Timer timer={timer} />
<div className={styles.control}>
<p className={styles.completed}>0 completed</p>
<div className={styles.buttons}>
<Button icon={<FaUndo />} tooltip="Restart" onClick={restart} />
<Button
icon={running ? <FaPause /> : <FaPlay />}
tooltip={running ? 'Pause' : 'Start'}
onClick={toggleRunning}
/>
</div>
</div>
</Modal>
);
}

View file

@ -1,5 +1,15 @@
import { padNumber } from '@/helpers/number';
import styles from './timer.module.css';
export function Timer() {
return <div className={styles.timer}>25:00</div>;
interface TimerProps {
timer: number;
}
export function Timer({ timer }: TimerProps) {
return (
<div className={styles.timer}>
{padNumber(Math.floor(timer / 60))}:{padNumber(timer % 60)}
</div>
);
}

3
src/helpers/number.ts Normal file
View file

@ -0,0 +1,3 @@
export function padNumber(number: number, maxLength: number = 2): string {
return number.toString().padStart(maxLength, '0');
}