From 6382d1fe63faf5acdcc07e29b752592bc1b46b21 Mon Sep 17 00:00:00 2001 From: stuforfun Date: Sat, 7 Mar 2026 14:03:07 +0000 Subject: [PATCH 1/6] fix: restore viewport meta + add missing @keyframes flash-dest - Restore accidentally removed in d1ac616 (PR #2); mobile browsers were falling back to ~980px desktop width and scaling down the UI - Add @keyframes flash-dest definition missing from d1ac616; destination card outboxes were referencing the animation but it was never defined, silently breaking flash-on-update feedback Co-authored-by: stuforfun --- index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.html b/index.html index e736dcb..cdff7de 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ + Time Converter @@ -119,6 +120,7 @@ } /* flash on update */ @keyframes flash{0%{background:var(--bluebg);}100%{background:var(--outbg);}} +@keyframes flash-dest{0%{background:var(--redbg);}100%{background:var(--outbg);}} .outbox.flash, .date-display.flash, .time-display.flash{animation:flash .35s ease;} From 0400ada101d8dfa5261466ca836622cea3033148 Mon Sep 17 00:00:00 2001 From: Claude <> Date: Sat, 7 Mar 2026 14:26:36 +0000 Subject: [PATCH 2/6] docs: regenerate README with accurate app details - Verified city count: 1,055 entries, 1,039 unique names, 44 aliases - Documents DST-awareness, fuzzy search, half/quarter-hour offsets - Adds technical reference table and local dev instructions --- README.md | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 783e574..a4fa72f 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,16 @@ Enter a date, time, and origin city — instantly see the equivalent local time ## Features -- **1,055 cities** across every IANA timezone -- **DST-aware** — handles daylight saving transitions correctly, including edge cases (clocks-skip-forward gaps, fall-back ambiguity) -- **Half & quarter-hour offsets** — India (UTC+5:30), Nepal (UTC+5:45), and all other non-whole-hour zones +- **1,055 cities** across every IANA timezone (1,039 unique city names; 16 appear in multiple countries) +- **DST-aware** — handles daylight saving transitions correctly via browser's built-in IANA database +- **Half & quarter-hour offsets** — India (UTC+5:30), Nepal (UTC+5:45), Iran (UTC+3:30), and all other non-whole-hour zones - **Fuzzy city search** — scored ranking so the best match always comes first; accents and diacritics normalised (type "Medellin" to find "Medellín") -- **City aliases** — historical and colloquial names supported: Bombay → Mumbai, Peking → Beijing, Saigon → Ho Chi Minh City, NYC, HK, KL, BKK, and more +- **44 city aliases** — historical and colloquial names: Bombay → Mumbai, Peking → Beijing, Saigon → Ho Chi Minh City, NYC, HK, KL, BKK, and more - **Multiple destinations** — add as many target cities as you need; first card is permanent, additional cards are removable -- **Copy result** — one click copies city, date, time, and timezone to clipboard -- **12h / 24h toggle** per destination card +- **12h / 24h toggle** per card, defaulting to 24h +- **Coherent color system** — origin card in blue, destination cards in burgundy red - **Persistent state** — localStorage auto-saves your last session; reopening the app restores your cities and settings -- **Mobile-friendly** — stacked single-column layout on small screens, 3-column grid on desktop +- **Mobile-friendly** — stacked single-column layout on small screens, side-by-side grid on desktop - **Accessible** — full ARIA attributes, keyboard navigation in dropdowns, screen reader announcements on result updates --- @@ -35,7 +35,6 @@ Enter a date, time, and origin city — instantly see the equivalent local time 3. **Destination** — type the city you want to convert to and select it 4. **Read the result** — date, local time, and UTC offset appear instantly 5. **Add more** — click **+ Add destination** for additional cities -6. **Copy** — hit the **copy** button on any card to copy the result to clipboard --- @@ -46,11 +45,10 @@ Enter a date, time, and origin city — instantly see the equivalent local time | Architecture | Single self-contained HTML file | | Dependencies | None (zero npm, zero CDN at runtime) | | Fonts | Google Fonts (Playfair Display + DM Mono) | -| Data | 1,055 cities, ~50KB inline | +| Cities | 1,055 entries · 1,039 unique names · 44 aliases | | Algorithm | `Intl.DateTimeFormat` + iterative `wallToUTC` for DST correctness | | Storage | `localStorage` key `tc-v2` | | Browser support | Any modern browser (Chrome, Firefox, Safari, Edge) | -| File size | ~80KB | --- @@ -64,7 +62,7 @@ start index.html # Windows xdg-open index.html # Linux ``` -Or serve it with any static server: +Or serve with any static server: ```bash npx serve . @@ -81,20 +79,6 @@ python3 -m http.server 8080 --- -## Test suite - -A separate `test-suite.html` file covers 86 automated tests across: -- Algorithm correctness (offsets, half-hour zones, 12h/24h) -- DST transitions (spring forward, fall back, no-DST zones) -- Date boundaries (year rollover, leap years, midnight edge cases) -- XSS and injection resistance -- Malicious / out-of-range inputs -- Regression cases - -Open `test-suite.html` in a browser to run all tests. - ---- - ## License MIT — do whatever you want with it. From 3f8571195e5b4b3c93fb730971a2104ebc70c4bb Mon Sep 17 00:00:00 2001 From: Claude <> Date: Sat, 7 Mar 2026 15:09:49 +0000 Subject: [PATCH 3/6] docs: fix two README inaccuracies flagged by Codex review - Remove false persistence claim: localStorage is cleared on startup via removeItem() in the init IIFE; app is stateless between visits - Fix CDN claim: Google Fonts is loaded from CDN at runtime; corrected 'zero CDN' to reflect actual behaviour --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a4fa72f..cd91c4c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Enter a date, time, and origin city — instantly see the equivalent local time - **Multiple destinations** — add as many target cities as you need; first card is permanent, additional cards are removable - **12h / 24h toggle** per card, defaulting to 24h - **Coherent color system** — origin card in blue, destination cards in burgundy red -- **Persistent state** — localStorage auto-saves your last session; reopening the app restores your cities and settings +- **Stateless** — no session is saved between visits; the app starts fresh each time - **Mobile-friendly** — stacked single-column layout on small screens, side-by-side grid on desktop - **Accessible** — full ARIA attributes, keyboard navigation in dropdowns, screen reader announcements on result updates @@ -43,7 +43,7 @@ Enter a date, time, and origin city — instantly see the equivalent local time | Detail | Value | |---|---| | Architecture | Single self-contained HTML file | -| Dependencies | None (zero npm, zero CDN at runtime) | +| Dependencies | No npm · Google Fonts loaded from CDN at runtime | | Fonts | Google Fonts (Playfair Display + DM Mono) | | Cities | 1,055 entries · 1,039 unique names · 44 aliases | | Algorithm | `Intl.DateTimeFormat` + iterative `wallToUTC` for DST correctness | From af4541759f51ceda244cc11ad909f8be3e939112 Mon Sep 17 00:00:00 2001 From: Claude <> Date: Sat, 7 Mar 2026 15:14:37 +0000 Subject: [PATCH 4/6] fix: restore localStorage persistence on startup Init IIFE was calling removeItem(STORAGE) unconditionally, wiping any saved state before it could be loaded. loadState() and saveState() were fully implemented but persistence was effectively disabled. Now: attempt loadState() on startup; if a saved session exists, restore origin city, timezone, format, date, time, and all destination cards, then convert. Fall back to fresh start if no saved state found. --- index.html | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index cdff7de..a801d47 100644 --- a/index.html +++ b/index.html @@ -1916,9 +1916,25 @@

Time Converter

INIT ═══════════════════════════════════════════════ */ (function(){ - try{ localStorage.removeItem(STORAGE); }catch(e){} - createCard(null, true); - syncEmpty(); syncDateDisplay(); syncTimeDisplay(); + var s=loadState(); + if(s){ + document.getElementById("from-inp").value=s.cityName||""; + fromTz=s.tz||Intl.DateTimeFormat().resolvedOptions().timeZone; + fromFmt=s.fmt||24; + var b12=document.getElementById("o-btn12"),b24=document.getElementById("o-btn24"); + if(b12&&b24){ + b12.classList.toggle("on",fromFmt===12); b12.setAttribute("aria-pressed",fromFmt===12); + b24.classList.toggle("on",fromFmt===24); b24.setAttribute("aria-pressed",fromFmt===24); + } + if(s.date) document.getElementById("in-date").value=s.date; + if(s.time) document.getElementById("in-time").value=s.time; + (s.dests||[]).forEach(function(d,i){ createCard(d,i===0); }); + syncEmpty(); syncDateDisplay(); syncTimeDisplay(); + convertAll(); + } else { + createCard(null,true); + syncEmpty(); syncDateDisplay(); syncTimeDisplay(); + } })(); From 93ecc95230aa664479b0a99ecec7e6ad0555dba7 Mon Sep 17 00:00:00 2001 From: Claude <> Date: Sat, 7 Mar 2026 15:18:08 +0000 Subject: [PATCH 5/6] docs: restore persistence bullet now that localStorage is fixed The stateless note was added after Codex caught removeItem() wiping state on startup. That bug is now fixed in af45417; README updated to accurately reflect working persistence again. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd91c4c..0d06167 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Enter a date, time, and origin city — instantly see the equivalent local time - **Multiple destinations** — add as many target cities as you need; first card is permanent, additional cards are removable - **12h / 24h toggle** per card, defaulting to 24h - **Coherent color system** — origin card in blue, destination cards in burgundy red -- **Stateless** — no session is saved between visits; the app starts fresh each time +- **Persistent state** — localStorage auto-saves your last session; reopening the app restores your cities, date, time, and format settings - **Mobile-friendly** — stacked single-column layout on small screens, side-by-side grid on desktop - **Accessible** — full ARIA attributes, keyboard navigation in dropdowns, screen reader announcements on result updates From 1140f99f2e852719710d32864df702aebfe6b951 Mon Sep 17 00:00:00 2001 From: Claude <> Date: Sat, 7 Mar 2026 15:35:12 +0000 Subject: [PATCH 6/6] fix: populate origin-tz display on session restore Codex review (PR #3) caught that af45417 restored fromTz correctly but never updated the #origin-tz display element. After reload, the conversion math was correct but the origin timezone field still showed the placeholder text, creating an inconsistent UI. Fix: after restoring fromTz from saved state, set origin-tz.textContent to utcLabel(s.tz) and add the 'live' class, matching what the dropdown select handler does on a fresh city pick. --- index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.html b/index.html index a801d47..8c28c7c 100644 --- a/index.html +++ b/index.html @@ -1921,6 +1921,8 @@

Time Converter

document.getElementById("from-inp").value=s.cityName||""; fromTz=s.tz||Intl.DateTimeFormat().resolvedOptions().timeZone; fromFmt=s.fmt||24; + var otz=document.getElementById("origin-tz"); + if(otz&&s.tz){ otz.textContent=utcLabel(s.tz); otz.classList.add("live"); } var b12=document.getElementById("o-btn12"),b24=document.getElementById("o-btn24"); if(b12&&b24){ b12.classList.toggle("on",fromFmt===12); b12.setAttribute("aria-pressed",fromFmt===12);