惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
博客园 - 司徒正美
Last Week in AI
Last Week in AI
爱范儿
爱范儿
罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
雷峰网
雷峰网
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
量子位
V
V2EX
博客园 - 叶小钗
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How I Built a Free Online Time Toolkit with Next.js 16 (P...
tani · 2026-05-04 · via DEV Community

tani

A story about building Clock-Tani — 9 free time-management tools in a single PWA, written with Next.js 16 App Router. Live at https://clock-tani.com

Why I Built This

I needed a pomodoro timer at work, but every option was either ad-heavy, app-only, or just ugly. Same story for world clocks, countdown timers, and interval timers. So I built them all into one place.

That place is now Clock-Tani — 9 small but useful tools, no ads in the core experience, no signup required.

What's Inside

  • World Clock — 70+ cities, drag to reorder
  • Timer / Pomodoro / Interval (Tabata, HIIT) / Multi-Timer
  • Stopwatch with lap times
  • Alarm Clock with 15 sounds
  • Server Time (NTP) — for ticketing precision
  • D-Day Counter — supports the Korean lunar calendar

Tech Stack

Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS 4 · next-intl (KR/EN) · PWA (Service Worker) · @dnd-kit · korean-lunar-calendar

Five Implementation Highlights

1. App Router i18n with next-intl

I used the /[locale]/[tool] structure with localePrefix: 'always' so even /clock redirects to /ko/clock. This kept canonical URLs clean.

// src/middleware.ts
import createMiddleware from 'next-intl/middleware';
export default createMiddleware({
  locales: ['ko', 'en'],
  defaultLocale: 'ko',
  localePrefix: 'always',
});

Enter fullscreen mode Exit fullscreen mode

2. Making it Installable as a PWA

Just public/manifest.json + public/sw.js. Next.js doesn't need extra config. The service worker uses stale-while-revalidate so tools work offline.

<link rel="manifest" href="/manifest.json" />

Enter fullscreen mode Exit fullscreen mode

3. Web Audio API for Reliable Alarm Sounds

The classic <audio> tag often gets blocked by mobile autoplay policies. After the user has clicked once, Web Audio API plays consistently:

const audioCtx = new AudioContext();
async function playSound(url: string) {
  const res = await fetch(url);
  const buffer = await audioCtx.decodeAudioData(await res.arrayBuffer());
  const source = audioCtx.createBufferSource();
  source.buffer = buffer;
  source.connect(audioCtx.destination);
  source.start();
}

Enter fullscreen mode Exit fullscreen mode

4. Wake Lock API to Keep the Screen On

If the screen sleeps mid-timer, alarms get delayed. Wake Lock fixes it:

const wakeLock = await navigator.wakeLock.request('screen');
// release when timer ends

Enter fullscreen mode Exit fullscreen mode

iOS Safari has supported it since 16.4, so this works almost everywhere now.

5. Auto-Generated OG Images for SEO

Each tool page has its own opengraph-image.tsx. Next.js generates the OG image at build time, which I reuse for Pinterest and social cards.

Lessons Learned

  • There's a real demand for ad-free utility tools — organic traffic grows steadily.
  • Almost no one installs the PWA. Most people just bookmark, so I now nudge "save to bookmarks" instead of "install app".
  • i18n is much easier when designed up front than retrofitted.

Closing

It's funny — building time-management tools doesn't actually make me less distracted. But it has made me more thoughtful about how a small piece of software can quietly support someone's day.

Try it: clock-tani.com/en
Pomodoro: clock-tani.com/en/pomodoro

Originally posted on Medium and velog. Feedback welcome — especially from fellow indie makers building small useful things.