timelord7000's picture
analyze fix upgrade, prioritize mvp top 3 e2e tested n functional simple but valuable human struggle time minimizers
3e519ec verified
class ToolFocus extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.container {
background: #1e293b;
border-radius: 1rem;
padding: 2.5rem;
text-align: center;
border: 1px solid #334155;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
}
.timer-display {
font-size: 6rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
color: #fff;
margin: 1rem 0;
letter-spacing: -2px;
text-shadow: 0 0 30px rgba(99, 102, 241, 0.3);
}
.controls {
display: flex;
justify-content: center;
gap: 1rem;
margin-top: 2rem;
}
button {
padding: 0.75rem 2rem;
border-radius: 9999px;
border: none;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary {
background: #6366f1;
color: white;
box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4);
}
.btn-primary:hover {
background: #4f46e5;
transform: translateY(-2px);
}
.btn-secondary {
background: #334155;
color: #e2e8f0;
}
.btn-secondary:hover {
background: #475569;
}
.status-badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 999px;
font-size: 0.875rem;
background: #334155;
color: #94a3b8;
margin-bottom: 1rem;
}
.status-badge.active {
background: rgba(99, 102, 241, 0.2);
color: #818cf8;
border: 1px solid rgba(99, 102, 241, 0.3);
}
.presets {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.preset-btn {
background: transparent;
border: 1px solid #334155;
color: #94a3b8;
padding: 0.25rem 0.75rem;
font-size: 0.8rem;
border-radius: 6px;
}
.preset-btn:hover {
border-color: #6366f1;
color: #6366f1;
}
</style>
<div class="container">
<div class="status-badge" id="status">Ready to Focus</div>
<div class="presets">
<button class="preset-btn" onclick="this.getRootNode().host.setTimer(25)">25m</button>
<button class="preset-btn" onclick="this.getRootNode().host.setTimer(15)">15m</button>
<button class="preset-btn" onclick="this.getRootNode().host.setTimer(5)">5m</button>
</div>
<div class="timer-display" id="display">25:00</div>
<div class="controls">
<button class="btn-primary" id="startBtn">
<i data-feather="play" width="18" height="18"></i> Start
</button>
<button class="btn-secondary" id="resetBtn">
<i data-feather="refresh-ccw" width="18" height="18"></i> Reset
</button>
</div>
</div>
`;
this.timeLeft = 25 * 60;
this.timerId = null;
this.isRunning = false;
this.displayEl = this.shadowRoot.getElementById('display');
this.startBtn = this.shadowRoot.getElementById('startBtn');
this.resetBtn = this.shadowRoot.getElementById('resetBtn');
this.statusEl = this.shadowRoot.getElementById('status');
// Bind events
this.startBtn.addEventListener('click', () => this.toggleTimer());
this.resetBtn.addEventListener('click', () => this.resetTimer());
this.updateDisplay();
feather.replace();
}
updateDisplay() {
const m = Math.floor(this.timeLeft / 60).toString().padStart(2, '0');
const s = (this.timeLeft % 60).toString().padStart(2, '0');
this.displayEl.textContent = `${m}:${s}`;
// Update favicon/title dynamically could be a nice touch
document.title = this.isRunning ? `(${m}:${s}) Focus` : 'FlowState OS 🌊';
}
toggleTimer() {
if (this.isRunning) {
this.pauseTimer();
} else {
this.startTimer();
}
}
startTimer() {
if (this.timeLeft === 0) return;
this.isRunning = true;
this.statusEl.textContent = 'Focusing...';
this.statusEl.classList.add('active');
this.startBtn.innerHTML = '<i data-feather="pause" width="18" height="18"></i> Pause';
feather.replace();
this.timerId = setInterval(() => {
this.timeLeft--;
this.updateDisplay();
if (this.timeLeft <= 0) {
this.completeTimer();
}
}, 1000);
}
pauseTimer() {
this.isRunning = false;
clearInterval(this.timerId);
this.statusEl.textContent = 'Paused';
this.statusEl.classList.remove('active');
this.startBtn.innerHTML = '<i data-feather="play" width="18" height="18"></i> Resume';
feather.replace();
}
resetTimer() {
this.pauseTimer();
this.timeLeft = 25 * 60;
this.statusEl.textContent = 'Ready to Focus';
this.startBtn.innerHTML = '<i data-feather="play" width="18" height="18"></i> Start';
this.updateDisplay();
feather.replace();
}
setTimer(minutes) {
this.resetTimer();
this.timeLeft = minutes * 60;
this.updateDisplay();
}
completeTimer() {
this.pauseTimer();
this.timeLeft = 0;
this.updateDisplay();
this.statusEl.textContent = 'Session Complete! πŸŽ‰';
// Simple sound effect simulation via Visual Flash
this.shadowRoot.querySelector('.container').style.borderColor = '#10b981';
setTimeout(() => {
this.shadowRoot.querySelector('.container').style.borderColor = '#334155';
}, 2000);
}
}
customElements.define('tool-focus', ToolFocus);