Introduction
Managing attention and productivity can be difficult, especially for people with ADHD. Long to‑do lists often feel overwhelming, and big tasks can be discouraging. To solve this, I built a PHP web application that breaks work into micro‑steps, adds a Pomodoro‑style focus timer, and tracks progress visually.
This project demonstrates how simple code can create meaningful tools that support better daily routines.
🎯 Core Features
- Micro-step task management: Break tasks into tiny, actionable steps.
- Pomodoro-style focus timer: 25‑minute focus sessions with 5‑minute breaks.
- Visual progress tracking: Progress bars show completed steps at a glance.
-
Lightweight persistence: Uses a JSON file (
data.json) instead of a database.
🛠️ The Code
Here’s the heart of the application — a single index.php file that handles tasks, steps, and the timer:
<?php
// Simple ADHD-friendly Task + Focus Timer app (no framework, JSON storage)
// Save as index.php, create data.json with [] and run via PHP's built-in server: php -S localhost:8000
$dataFile = __DIR__ . '/data.json';
if (!file_exists($dataFile)) file_put_contents($dataFile, json_encode([]));
function readData() {
global $dataFile;
$json = file_get_contents($dataFile);
$data = json_decode($json, true);
return is_array($data) ? $data : [];
}
function writeData($data) {
global $dataFile;
file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT));
}
// Handle actions
$action = $_POST['action'] ?? $_GET['action'] ?? null;
$data = readData();
if ($action === 'add_task') {
$title = trim($_POST['title'] ?? '');
if ($title !== '') {
$data[] = [
'id' => uniqid('t_', true),
'title' => $title,
'steps' => [],
'done' => false,
'createdAt' => time()
];
writeData($data);
}
header('Location: ./'); exit;
}
if ($action === 'add_step') {
$taskId = $_POST['taskId'] ?? '';
$stepText = trim($_POST['step'] ?? '');
foreach ($data as &$task) {
if ($task['id'] === $taskId && $stepText !== '') {
$task['steps'][] = [
'id' => uniqid('s_', true),
'text' => $stepText,
'done' => false
];
}
}
unset($task);
writeData($data);
header('Location: ./'); exit;
}
if ($action === 'toggle_step') {
$taskId = $_POST['taskId'] ?? '';
$stepId = $_POST['stepId'] ?? '';
foreach ($data as &$task) {
if ($task['id'] === $taskId) {
foreach ($task['steps'] as &$step) {
if ($step['id'] === $stepId) {
$step['done'] = !$step['done'];
break;
}
}
unset($step);
}
}
unset($task);
writeData($data);
header('Location: ./'); exit;
}
if ($action === 'toggle_task') {
$taskId = $_POST['taskId'] ?? '';
foreach ($data as &$task) {
if ($task['id'] === $taskId) {
$task['done'] = !$task['done'];
break;
}
}
unset($task);
writeData($data);
header('Location: ./'); exit;
}
if ($action === 'delete_task') {
$taskId = $_POST['taskId'] ?? '';
$data = array_values(array_filter($data, fn($t) => $t['id'] !== $taskId));
writeData($data);
header('Location: ./'); exit;
}
// Helper
function progress($task) {
$total = count($task['steps']);
if ($total === 0) return 0;
$done = count(array_filter($task['steps'], fn($s) => $s['done']));
return round(($done / $total) * 100);
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ADHD-friendly Task + Focus Timer</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root { --bg:#0f172a; --card:#111827; --text:#e5e7eb; --accent:#22c55e; --muted:#94a3b8; --danger:#ef4444; }
body { background:var(--bg); color:var(--text); font-family:system-ui,-apple-system,Segoe UI,Roboto; margin:0; }
.container { max-width:900px; margin:24px auto; padding:0 16px; }
.grid { display:grid; grid-template-columns: 1fr 320px; gap:16px; }
.card { background:var(--card); border-radius:12px; padding:16px; box-shadow:0 10px 25px rgba(0,0,0,0.25); }
h1,h2 { margin:0 0 12px; }
.row { display:flex; gap:8px; }
input[type="text"] { width:100%; padding:10px; border-radius:8px; border:1px solid #334155; background:#0b1220; color:var(--text); }
button { padding:10px 12px; border:none; border-radius:8px; cursor:pointer; background:#1f2937; color:var(--text); }
button.primary { background:var(--accent); color:#062a12; font-weight:600; }
button.danger { background:var(--danger); }
.task { border:1px solid #334155; border-radius:10px; padding:12px; margin-bottom:10px; }
.progress { height:8px; background:#1f2937; border-radius:999px; overflow:hidden; margin:8px 0; }
.bar { height:100%; background:var(--accent); width:0%; transition:width .25s ease; }
.steps { margin-top:8px; }
.step { display:flex; align-items:center; gap:8px; padding:6px 0; }
.muted { color:var(--muted); font-size:12px; }
.pill { font-size:12px; padding:6px 8px; border:1px dashed #334155; border-radius:999px; display:inline-block; color:var(--muted); }
.timer { text-align:center; }
.big { font-size:52px; font-weight:700; letter-spacing:1px; margin:10px 0; }
.center { display:flex; justify-content:center; gap:8px; }
.success { color:var(--accent); }
</style>
</head>
<body>
<div class="container">
<h1>ADHD-friendly Task + Focus Timer</h1>
<p class="muted">Break work into tiny steps, timebox with short focus sessions, and celebrate quick wins.</p>
<div class="grid">
<div class="card">
<h2>Tasks</h2>
<form method="post" class="row" style="margin-bottom:12px;">
<input type="hidden" name="action" value="add_task">
<input type="text" name="title" placeholder="Add a task (keep it small)" required>
<button class="primary" type="submit">Add</button>
</form>
<?php if (empty($data)): ?>
<p class="muted">No tasks yet. Start with something you can finish in under 25 minutes.</p>
<?php endif; ?>
<?php foreach ($data as $task): ?>
<div class="task">
<div class="row" style="justify-content:space-between;">
<div>
<strong><?php echo htmlspecialchars($task['title']); ?></strong>
<?php if ($task['done']): ?>
<span class="pill success">Done</span>
<?php endif; ?>
</div>
<div class="row">
<form method="post">
<input type="hidden" name="action" value="toggle_task">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<button type="submit"><?php echo $task['done'] ? 'Mark Undone' : 'Mark Done'; ?></button>
</form>
<form method="post">
<input type="hidden" name="action" value="delete_task">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<button class="danger" type="submit">Delete</button>
</form>
</div>
</div>
<div class="progress">
<div class="bar" style="width: <?php echo progress($task); ?>%;"></div>
</div>
<span class="muted"><?php echo progress($task); ?>% micro-steps complete</span>
<div class="steps">
<?php foreach ($task['steps'] as $step): ?>
<div class="step">
<form method="post">
<input type="hidden" name="action" value="toggle_step">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<input type="hidden" name="stepId" value="<?php echo $step['id']; ?>">
<button type="submit"><?php echo $step['done'] ? '✅' : '⬜'; ?></button>
</form>
<span><?php echo htmlspecialchars($step['text']); ?></span>
</div>
<?php endforeach; ?>
<form method="post" class="row">
<input type="hidden" name="action" value="add_step">
<input type="hidden" name="taskId" value="<?php echo $task['id']; ?>">
<input type="text" name="step" placeholder="Add a tiny step (2–5 min)" required>
<button type="submit">Add step</button>
</form>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="card timer">
<h2>Focus timer</h2>
<div id="mode" class="pill">Focus: 25:00</div>
<div class="big" id="clock">25:00</div>
<div class="center">
<button class="primary" onclick="startTimer()">Start</button>
<button onclick="resetTimer()">Reset</button>
</div>
<p class="muted" id="tip">Tip: Close extra tabs. Put phone away. Pick the smallest next step.</p>
</div>
</div>
</div>
<script>
let mode = 'focus'; // 'focus' or 'break'
let remaining = 25*60; // seconds
let timerId = null;
function render() {
const m = Math.floor(remaining / 60).toString().padStart(2,'0');
const s = (remaining % 60).toString().padStart(2,'0');
document.getElementById('clock').textContent = `${m}:${s}`;
document.getElementById('mode').textContent = (mode === 'focus')
? `Focus: ${m}:${s}` : `Break: ${m}:${s}`;
document.getElementById('tip').textContent = (mode === 'focus')
? 'Tip: Pick one tiny step and do only that.'
: 'Tip: Stand, stretch, sip water. Eyes off screens.';
}
function startTimer() {
if (timerId) return;
timerId = setInterval(() => {
remaining--;
if (remaining <= 0) {
new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YQAAAAA=').play();
if (mode === 'focus') {
mode = 'break'; remaining = 5*60;
} else {
mode = 'focus'; remaining = 25*60;
}
}
render();
}, 1000);
}
function resetTimer() {
clearInterval(timerId); timerId = null;
mode = 'focus'; remaining = 25*60; render();
}
render();
</script>
</body>
</html>
?>
The script uses:
-
readData()andwriteData()to manage JSON storage. -
POST actions (
add_task,add_step,toggle_step, etc.) to update tasks. - JavaScript for the timer logic, switching between focus and break modes.
📊 Workflow Example
- Add a task: “Prepare project report.”
- Break it into micro‑steps: Draft outline → Write intro → Add charts → Review.
- Start the 25‑minute timer and focus only on the first step.
- Check off completed steps and watch the progress bar grow.
- Take a 5‑minute break when the timer signals.
🚀 Why This Matters
For people with ADHD—or anyone struggling with productivity—this app provides:
- Structure without rigidity: Tasks can be broken down endlessly.
- Encouragement through feedback: Progress bars and checkmarks make achievements visible.
-
Simplicity: No database or complex setup, just run
php -S localhost:8000.
💡 Future Enhancements
- Add sound alerts for timer completion.
- Sync tasks with Google Calendar.
- Provide weekly statistics dashboards.
- Enable multi-user support with authentication.
Conclusion
This PHP script application is more than just code — it’s a supportive tool for managing attention and productivity. By combining micro‑step task management with a Pomodoro‑style timer, it helps users stay focused, reduce overwhelm, and celebrate progress.
For developers, it’s also a great portfolio project: practical, lightweight, and impactful.
Top comments (0)