From 181efee0e6a448b2cb6098ee81215608c7ba6205 Mon Sep 17 00:00:00 2001 From: Ty Clifford Date: Tue, 30 Jun 2026 19:56:36 -0400 Subject: [PATCH] =?UTF-8?q?-=20added=20a=20persistent=2012=20hour=20/=2024?= =?UTF-8?q?=20hour=20segmented=20control=20under=20the=20sidebar=E2=80=99s?= =?UTF-8?q?=20Time=20preferences.=20Updated:=20[public/index.php](/Users/t?= =?UTF-8?q?yemeclifford/Documents/GH/weather/public/index.php)=20[public/a?= =?UTF-8?q?ssets/js/app.js](/Users/tyemeclifford/Documents/GH/weather/publ?= =?UTF-8?q?ic/assets/js/app.js)=20[public/assets/css/styles.css](/Users/ty?= =?UTF-8?q?emeclifford/Documents/GH/weather/public/assets/css/styles.css)?= =?UTF-8?q?=20[README.md](/Users/tyemeclifford/Documents/GH/weather/README?= =?UTF-8?q?.md)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- public/assets/css/styles.css | 25 +++++++++++++++++++++++++ public/assets/js/app.js | 29 +++++++++++++++++++++++++++-- public/index.php | 8 ++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a0c8ab2..f749fe4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A PHP, SQLite, HTML5, and JavaScript weather dashboard that uses public weather - RainViewer radar tiles on an interactive Leaflet map. - Local SQLite API cache with a five minute weather refresh window. - Hourly and daily archive snapshots with search and JSON detail export. -- Cookie-backed display preferences, map layer toggles, dark/light theme, and import/export. +- Cookie-backed display preferences, map layer toggles, 12/24 hour time format, dark/light theme, and import/export. - Current-date history facts comparing the projection to the same date last year. ## Run diff --git a/public/assets/css/styles.css b/public/assets/css/styles.css index 006479e..4b7bc7c 100644 --- a/public/assets/css/styles.css +++ b/public/assets/css/styles.css @@ -302,6 +302,31 @@ body.light .status-line { accent-color: var(--pink); } +.segmented { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0; + min-height: var(--control-h); + overflow: hidden; + border: 1px solid var(--line); + border-radius: var(--radius); +} + +.segmented button { + min-height: var(--control-h); + border: 0; + border-radius: 0; + background: transparent; + color: var(--muted); + padding: 0 10px; +} + +.segmented button[aria-pressed="true"] { + background: linear-gradient(135deg, rgba(57, 168, 255, 0.28), rgba(255, 90, 165, 0.24)); + color: var(--text); + font-weight: 800; +} + .control-actions { display: grid; gap: 10px; diff --git a/public/assets/js/app.js b/public/assets/js/app.js index 94007f5..34e3cab 100644 --- a/public/assets/js/app.js +++ b/public/assets/js/app.js @@ -3,6 +3,7 @@ const DEFAULT_PREFS = { theme: "dark", + timeFormat: "12", locationQuery: "New York, NY", sections: { current: true, @@ -110,6 +111,17 @@ $("refreshButton").addEventListener("click", () => loadWeather(true)); $("themeButton").addEventListener("click", toggleTheme); + document.querySelectorAll("[data-time-format]").forEach((button) => { + button.addEventListener("click", () => { + state.prefs.timeFormat = button.dataset.timeFormat === "24" ? "24" : "12"; + savePrefs(); + applyPreferences(); + if (state.dashboard) { + renderDashboard(); + renderArchives(); + } + }); + }); $("exportPrefs").addEventListener("click", exportPreferences); $("importPrefsButton").addEventListener("click", () => $("importPrefsFile").click()); $("importPrefsFile").addEventListener("change", importPreferences); @@ -635,11 +647,17 @@ function applyPreferences() { document.body.classList.toggle("light", state.prefs.theme === "light"); $("themeLabel").textContent = state.prefs.theme === "light" ? "Dark" : "Light"; + state.prefs.timeFormat = state.prefs.timeFormat === "24" ? "24" : "12"; document.querySelectorAll("[data-pref]").forEach((input) => { input.checked = Boolean(getPath(state.prefs, input.dataset.pref)); }); + document.querySelectorAll("[data-time-format]").forEach((button) => { + const isActive = button.dataset.timeFormat === state.prefs.timeFormat; + button.setAttribute("aria-pressed", isActive ? "true" : "false"); + }); + Object.entries(state.prefs.sections).forEach(([name, visible]) => { document.querySelectorAll(`[data-section="${name}"]`).forEach((section) => { section.classList.toggle("is-hidden", !visible); @@ -827,7 +845,8 @@ month: "short", day: "numeric", hour: "numeric", - minute: "2-digit" + minute: "2-digit", + hour12: useTwelveHourClock() }).format(date); } @@ -841,10 +860,16 @@ } return new Intl.DateTimeFormat(undefined, { weekday: "short", - hour: "numeric" + hour: "numeric", + minute: "2-digit", + hour12: useTwelveHourClock() }).format(date); } + function useTwelveHourClock() { + return state.prefs.timeFormat !== "24"; + } + function formatDay(value) { if (!value) { return "--"; diff --git a/public/index.php b/public/index.php index 1fe4675..1cb0402 100644 --- a/public/index.php +++ b/public/index.php @@ -87,6 +87,14 @@ declare(strict_types=1); +
+

Time

+
+ + +
+
+