PomodoroTimer
pomodorotimer-1779388706163.tsx
'use client';
import { useState, useEffect, useRef } from 'react';
export default function PomodoroTimer() {
const WORK = 25 * 60, BREAK = 5 * 60;
const [seconds, setSeconds] = useState(WORK);
const [running, setRunning] = useState(false);
const [isWork, setIsWork] = useState(true);
const [sessions, setSessions] = useState(0);
const intervalRef = useRef(null);
useEffect(() => {
if (running) {
intervalRef.current = setInterval(() => {
setSeconds(s => {
if (s <= 1) {
const nextWork = !isWork;
setIsWork(nextWork);
if (!nextWork) setSessions(n => n + 1);
setSeconds(nextWork ? WORK : BREAK);
return nextWork ? WORK : BREAK;
}
return s - 1;
});
}, 1000);
} else clearInterval(intervalRef.current);
return () => clearInterval(intervalRef.current);
}, [running, isWork]);
const min = Math.floor(seconds / 60), sec = seconds % 60;
const total = isWork ? WORK : BREAK;
const pct = 1 - seconds / total;
const r = 72, circ = 2 * Math.PI * r;
const dash = circ * pct;
return (
<div style={{ fontFamily: 'system-ui, sans-serif', textAlign: 'center', padding: '24px' }}>
<div style={{ display: 'flex', gap: '8px', justifyContent: 'center', marginBottom: '20px' }}>
{['Focus', 'Break'].map((m, i) => (
<button key={m} onClick={() => { setIsWork(i === 0); setSeconds(i === 0 ? WORK : BREAK); setRunning(false); }} style={{
background: ((isWork && i === 0) || (!isWork && i === 1)) ? 'rgba(201,168,76,0.15)' : 'transparent',
border: `1px solid ${((isWork && i === 0) || (!isWork && i === 1)) ? 'rgba(201,168,76,0.3)' : 'rgba(255,255,255,0.1)'}`,
borderRadius: '8px', padding: '6px 16px',
color: ((isWork && i === 0) || (!isWork && i === 1)) ? '#C9A84C' : 'rgba(245,245,240,0.4)',
fontSize: '13px', cursor: 'pointer',
}}>{m}</button>
))}
</div>
<svg width="180" height="180" style={{ display: 'block', margin: '0 auto 16px' }}>
<circle cx="90" cy="90" r={r} fill="none" stroke="rgba(255,255,255,0.06)" strokeWidth="8" />
<circle cx="90" cy="90" r={r} fill="none"
stroke={isWork ? '#C9A84C' : '#6366f1'} strokeWidth="8" strokeLinecap="round"
strokeDasharray={`${dash} ${circ}`}
transform="rotate(-90 90 90)"
style={{ transition: 'stroke-dasharray 1s linear', filter: `drop-shadow(0 0 8px ${isWork ? '#C9A84C' : '#6366f1'})` }}
/>
<text x="90" y="85" textAnchor="middle" fill="#F5F5F0" fontSize="32" fontWeight="800" fontFamily="monospace">
{String(min).padStart(2,'0')}:{String(sec).padStart(2,'0')}
</text>
<text x="90" y="110" textAnchor="middle" fill="rgba(245,245,240,0.4)" fontSize="13" fontFamily="system-ui">
{isWork ? 'Focus Time' : 'Break Time'}
</text>
</svg>
<button onClick={() => setRunning(r => !r)} style={{
background: running ? 'rgba(239,68,68,0.15)' : 'linear-gradient(135deg, #C9A84C, #e8c96d)',
border: running ? '1px solid rgba(239,68,68,0.3)' : 'none',
borderRadius: '50px', padding: '12px 40px',
color: running ? '#ef4444' : '#0A0A0A',
fontSize: '15px', fontWeight: 700, cursor: 'pointer', marginBottom: '16px',
}}>{running ? '⏸ Pause' : '▶ Start'}</button>
<div style={{ display: 'flex', justifyContent: 'center', gap: '6px' }}>
{Array.from({ length: 4 }, (_, i) => (
<div key={i} style={{ width: '10px', height: '10px', borderRadius: '50%', background: i < sessions % 4 ? '#C9A84C' : 'rgba(255,255,255,0.1)' }} />
))}
</div>
<p style={{ color: 'rgba(245,245,240,0.35)', fontSize: '12px', marginTop: '8px' }}>{sessions} sessions completed</p>
</div>
);
}Component info
CategoryUtility
Frameworkreact
TierFREE
Views0
Copies0
About
Pomodoro focus timer with sessions counter
More from Utility
'use client'
import { useState } from 'react'
const PRESETS = [
{ name: 'Gold', primary: '#C9A84C', bg: '#0A0A0A', accent: '#6366f1' },
{ name: 'Neon', primary: '#22d3ee', bg: '#030712', accent: '#a78bfa' },
{ name: 'Crimson', primary: '#ef444ThemeCustomizer
Utility
'use client'
import { useState, useCallback } from 'react'
interface UploadedFile {
id: number
name: string
size: number
type: string
progress: number
done: boolean
error?: string
}
const ALLOWED = ['image/png', 'image/jpeg', 'image/wFileUploadZone
Utility
'use client'
import { useState } from 'react'
interface ClipItem {
id: number
content: string
type: 'text' | 'code' | 'url' | 'email'
pinned: boolean
time: number
}
const INITIAL: ClipItem[] = [
{ id: 1, content: 'npx empire-ui-mcp --stClipboardManager
Utility
'use client';
import { useState } from 'react';
export default function NeonToggle({ label = "Enable AI Mode", defaultOn = false, color = "#6366f1" }) {
const [on, setOn] = useState(defaultOn);
const [pressing, setPressing] = useState(false);
NeonToggle
Utility