A refactor of closerintime that replaces the curated event database with real-time Wikidata search.
Search for any number of historical events and see them on a proportional timeline. Give your timeline a custom title, share it as a link, or export it as a PNG image.
- Next.js 16 (App Router, SSR, TypeScript)
- next-intl for i18n (6 locales: en, fr, de, es, it, pt)
- Wikidata for real-time event search (REST API:
wbsearchentities+wbgetentities) - CSS Modules with responsive horizontal/vertical timeline layout
- MUI Icons for event category icons
- PWA via @ducanh2912/next-pwa (service worker, offline support)
Requires Node.js 22+.
npm install
npm run dev:next # starts Next.js dev serverOpen http://localhost:3000.
| Command | Description |
|---|---|
npm run dev |
Start dev server via netlify dev |
npm run dev:next |
Start Next.js dev server directly (uses --webpack for PWA) |
npm run build |
Production build (uses --webpack for PWA service worker) |
npm run build:watch |
Re-runs production build on source file changes |
npm test |
Run all tests once |
npm run test:watch |
Run tests in watch mode (re-runs on file changes) |
npm run lint |
Run ESLint |
npm run buildThe build uses --webpack to enable PWA service worker generation (Turbopack does not support the PWA plugin). Event pages use ISR with a 1-hour revalidation window.
- Real-time Wikidata search — search for any historical event, person, or milestone in Wikidata's knowledge base. Results are fetched on demand with debounced queries.
- Multilanguage — available in English, French, German, Spanish, Italian, and Portuguese. Switch language in Settings; locale is reflected in the URL (
/fr/,/de/, etc.). - Dark mode — automatic via system preference, or manually toggle between System / Light / Dark in Settings. Choice persists across sessions.
- Unlimited events — add as many events as you want. For people, choose between birth and death dates directly from the dropdown.
- Editable title — click the pencil icon to name your timeline; the title is used in the page title, OG image, and share dialog.
- Zoom mode — toggle zoom on crowded timelines. The width scales based on the smallest gap between markers so info cards never overlap.
- Removable "Today" marker — when you have 2+ events, you can hide the present-day marker and re-add it later.
- Smart overlap detection — marker info cards that would overlap are automatically flipped above the timeline line.
- Dynamic OG images — shared links generate branded Open Graph images with the timeline title, rendered server-side via
next/og. - Image export — download the timeline as a PNG image with a "wiki:closerintime" watermark. Disabled while zoomed to avoid cropped output.
- Random event — add a random Wikidata event to your timeline with one click.
src/
app/
layout.tsx # Root layout (fonts, theme script)
[locale]/
layout.tsx # Locale layout, metadata, providers
page.tsx # Home (empty state)
[...ids]/page.tsx # ISR for /Q42, /Q42/Q107, etc.
api/
search/route.ts # GET /api/search?q=... → Wikidata search proxy
og/route.tsx # Dynamic Open Graph image generation
components/
Chooser/ # Single search input with Wikidata autocomplete
Timeline/ # Proportional horizontal/vertical timeline with interactive markers
EditableTitle.tsx # Editable timeline title with auto-resize
ShareToolbar.tsx # Copy link, share, export, zoom, edit-title, and show-Today buttons
HelpModal.tsx # Instructions modal
SettingsModal.tsx # Theme, timespan format, and language settings
CategoryIcon.tsx # Maps event type to MUI icon
i18n/
config.ts # Locale list and names
routing.ts # next-intl routing config
request.ts # Server-side locale resolution
messages/ # Translation JSON files (en, fr, de, es, it, pt)
lib/
wikidata.ts # Wikidata REST API: search + fetch by Q-ID
date-utils.ts # UTC date creation, precise diffs, formatting
event-label.ts # Locale-aware event display names
timeline-math.ts # Proportional segment computation
url-params.ts # URL segment parsing (Q-IDs)
custom-event-url.ts # Shareable path builder
types.ts # TypeScript interfaces + EVENT_TYPES constant
hooks/
useWikidataSearch.ts # Debounced search hook (300ms, AbortController)
useSettings.ts # localStorage for theme + display preferences
useExport.ts # Image export logic (html2canvas)
middleware.ts # next-intl locale detection and routing
styles/ # CSS Modules
npm test # run all tests once
npm run test:watch # watch modeTests use Vitest with jsdom. Coverage includes:
- Library tests — date utils, timeline math, URL building, event labels
- Component tests — SettingsModal, ShareToolbar, TimelineMarker
- i18n tests — locale-aware date formatting, timespans, and event labels
- Events are sourced from Wikidata in real time. The search uses the
wbsearchentitiesAPI for fast text matching, thenwbgetentitiesto fetch dates, types, and Wikipedia links. Multiple date properties are checked (P585, P580, P571, P577, P569, P619, P620, P1191, P606) to cover different kinds of events. - URLs like
/Q43653/Q107or/fr/Q43653/Q107use Wikidata Q-IDs with an optional locale prefix. Append~dfor death dates (e.g./Q42~d). They are server-rendered withgenerateMetadata()so link previews show the timeline title and a dynamically generated OG image. The custom title and "hide Today" preference are stored as query params (?t=...&now=0). - Q-IDs in the URL are always sorted; out-of-order URLs redirect to the canonical form.
- The timeline switches from horizontal to vertical layout below 640px.
GPL-3.0