diff --git a/what-time-is-it-for-me.html b/what-time-is-it-for-me.html index 22f0346..46ce806 100644 --- a/what-time-is-it-for-me.html +++ b/what-time-is-it-for-me.html @@ -22,6 +22,38 @@ padding: clamp(1.25rem, 3vw, 2rem); } + .card-header { + display: flex; + justify-content: space-between; + align-items: baseline; + gap: 0.5rem; + flex-wrap: wrap; + } + + .shared-label { + margin: 0 0 0.5rem; + font-size: 1rem; + color: var(--text-muted); + } + + .shared-target { + margin: 0; + font-size: clamp(1.4rem, 4vw, 2.4rem); + font-weight: 700; + } + + .zone-note { + color: var(--text-muted); + margin-top: 0.35rem; + font-size: 0.95rem; + } + + .inline-fields { + display: grid; + gap: 0.75rem; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + } + .tool-actions { display: flex; flex-wrap: wrap; @@ -105,6 +137,11 @@ text-decoration: none; } + .comparison-empty { + margin: 0; + color: var(--text-muted); + } + @media (max-width: 720px) { body { padding: 20px 16px 40px; @@ -121,20 +158,39 @@

What time is it for me?

-
-

Your inferred timezone: Detecting…

+ + +
+
+

Base timezone

+ +
+

Your detected time zone: Detecting…

+
+ + +

Pick a moment

-
- - -
-
- - +
+
+ + +
+
+ + +
@@ -143,8 +199,21 @@

Pick a moment

+
+

Shareable link

+

Use the button above to copy a link that includes this moment as URL parameters. Anyone who opens the + link will see what that time looks like from their own timezone.

+
+ + +
+
+
-

Comparison

+
+

Preview across time zones

+

Add time zones to see how this moment appears elsewhere.

+

Choose a date, time, and timezone to see how it translates to your current timezone.

- -
-

Shareable link

-

Use the button above to copy a link that includes this moment as URL parameters. Anyone who opens the - link will see what that time looks like from their own timezone.

-
- - -
-
@@ -190,13 +249,20 @@

Shareable link

const copyStatus = document.getElementById('copy-status'); const shareableUrlInput = document.getElementById('shareable-url'); const inferredTimezoneValue = document.getElementById('inferred-timezone-value'); + const baseTimezoneSelect = document.getElementById('base-timezone-select'); + const timezoneSourceNote = document.getElementById('timezone-source-note'); + const sharedMomentCard = document.getElementById('shared-moment-card'); + const sharedSource = document.getElementById('shared-source'); + const sharedTarget = document.getElementById('shared-target'); + const sharedOrigin = document.getElementById('shared-origin'); + const comparisonHint = document.getElementById('comparison-hint'); const resolvedZone = Intl.DateTimeFormat().resolvedOptions().timeZone; const fallbackZone = resolvedZone || DateTime.local().zoneName || 'UTC'; - let localZone = fallbackZone; - let localRowEntry = null; + let baseZone = fallbackZone; let timezoneManuallySet = false; const comparisonRows = []; + let sharedMoment = null; function ensureOptionForZone(zone) { const exists = Array.from(timezoneSelect.options).some(option => option.value === zone); @@ -204,7 +270,8 @@

Shareable link

const option = document.createElement('option'); option.value = zone; option.textContent = zone; - timezoneSelect.append(option); + timezoneSelect.append(option.cloneNode(true)); + baseTimezoneSelect.append(option); } } @@ -230,10 +297,11 @@

Shareable link

const option = document.createElement('option'); option.value = zone; option.textContent = zone; - timezoneSelect.append(option); + timezoneSelect.append(option.cloneNode(true)); + baseTimezoneSelect.append(option); } - ensureOptionForZone(localZone); + ensureOptionForZone(baseZone); } function createTimezoneSelectElement() { @@ -247,35 +315,6 @@

Shareable link

inferredTimezoneValue.textContent = zone || 'Unavailable'; } - function addLocalComparisonRow() { - const row = document.createElement('tr'); - row.className = 'comparison-row comparison-row-fixed'; - row.dataset.rowType = 'local'; - - const labelCell = document.createElement('th'); - labelCell.scope = 'row'; - labelCell.innerHTML = `
Your timezone
${localZone}
`; - - const timeCell = document.createElement('td'); - timeCell.className = 'comparison-time'; - - const actionCell = document.createElement('td'); - actionCell.className = 'comparison-actions-cell'; - - row.append(labelCell, timeCell, actionCell); - comparisonRowsContainer.append(row); - - localRowEntry = { - getZone: () => localZone, - timeCell, - updateLabel(zone) { - labelCell.innerHTML = `
Your timezone
${zone}
`; - } - }; - - comparisonRows.push(localRowEntry); - } - function addCustomComparisonRow(initialZone) { ensureOptionForZone(initialZone); const row = document.createElement('tr'); @@ -330,28 +369,32 @@

Shareable link

return row; } - function updateLocalZone(zone, { updateSelect = true, updateComparison = true } = {}) { + function updateBaseZone(zone, note = '', { updateSelect = true, updateComparison: shouldUpdateComparison = true } = {}) { if (!zone) { updateInferredTimezoneDisplay('Unavailable'); return; } - const previousZone = localZone; - const zoneChanged = zone !== localZone; - localZone = zone; - - if (localRowEntry) { - localRowEntry.updateLabel(zone); - } - + const previousZone = baseZone; + const zoneChanged = zone !== baseZone; + baseZone = zone; updateInferredTimezoneDisplay(zone); + timezoneSourceNote.textContent = note || ''; ensureOptionForZone(zone); + if (updateSelect) { + baseTimezoneSelect.value = zone; + } + if (updateSelect && !timezoneManuallySet && (timezoneSelect.value === previousZone || !timezoneSelect.value)) { timezoneSelect.value = zone; } - if (updateComparison && (zoneChanged || !comparisonTable.hidden)) { + if (zoneChanged) { + updateSharedMomentCard(); + } + + if (shouldUpdateComparison && (zoneChanged || !comparisonTable.hidden)) { updateComparison(); } } @@ -401,7 +444,8 @@

Shareable link

if (!datetimeValue || !selectedZone) { comparisonOutput.textContent = 'Choose a date, time, and timezone to see how it translates to your current timezone.'; - comparisonTable.hidden = true; + comparisonTable.hidden = comparisonRows.length === 0; + comparisonHint.hidden = comparisonRows.length > 0; shareableUrlInput.value = location.href; return; } @@ -410,7 +454,8 @@

Shareable link

if (!momentInSelectedZone.isValid) { comparisonOutput.textContent = 'The selected date or timezone could not be parsed. Please check your inputs.'; - comparisonTable.hidden = true; + comparisonTable.hidden = comparisonRows.length === 0; + comparisonHint.hidden = comparisonRows.length > 0; shareableUrlInput.value = location.href; return; } @@ -419,7 +464,8 @@

Shareable link

const sourceText = `${formatDateTime(momentInSelectedZone)} in ${momentInSelectedZone.zoneName} (${selectedOffset})`; comparisonOutput.textContent = `${sourceText}. Here's how that moment translates across the selected timezones:`; - comparisonTable.hidden = false; + comparisonTable.hidden = comparisonRows.length === 0; + comparisonHint.hidden = comparisonRows.length > 0; for (const entry of comparisonRows) { const zoneName = entry.getZone(); @@ -499,6 +545,14 @@

Shareable link

datetimeInput.value = combined; } + if (dateParam && timeParam && timezoneParam) { + sharedMoment = DateTime.fromISO(`${dateParam}T${timeParam}`, { zone: timezoneParam }); + } + + if (dateParam && timeParam) { + sharedOrigin.textContent = 'Loaded from URL parameters'; + } + if (timezoneParam) { ensureOptionForZone(timezoneParam); timezoneSelect.value = timezoneParam; @@ -508,6 +562,8 @@

Shareable link

if (datetimeInput.value && timezoneSelect.value) { updateComparison(true); } + + updateSharedMomentCard(); } async function detectTimezoneFromIp() { @@ -525,15 +581,28 @@

Shareable link

} if (detectedZone) { - updateLocalZone(detectedZone); + updateBaseZone(detectedZone, 'Inferred from your IP address (worldtimeapi.org).'); } else { - updateLocalZone(fallbackZone, { updateSelect: false, updateComparison: false }); + updateBaseZone(fallbackZone, 'Using your browser-reported time zone.', { updateSelect: false, updateComparison: false }); + } + } + + function updateSharedMomentCard() { + if (!sharedMoment || !sharedMoment.isValid) { + sharedMomentCard.hidden = true; + return; } + + const baseZoneMoment = sharedMoment.setZone(baseZone); + const sourceLine = `${sharedMoment.toFormat('HH:mm')} on the ${sharedMoment.toFormat('dd')} of ${sharedMoment.toFormat('LL')}, ${sharedMoment.toFormat('yyyy')} ${sharedMoment.zoneName} is`; + sharedSource.textContent = sourceLine; + sharedTarget.textContent = baseZoneMoment.isValid ? `${baseZoneMoment.toFormat('HH:mm')} on ${baseZoneMoment.toFormat('dd LLL yyyy')} (${baseZoneMoment.offsetNameShort})` : 'Unable to convert to your base time zone.'; + sharedMomentCard.hidden = false; } populateTimezones(); - addLocalComparisonRow(); - timezoneSelect.value = localZone; + timezoneSelect.value = baseZone; + baseTimezoneSelect.value = baseZone; datetimeInput.value = DateTime.now().toISO({ suppressSeconds: true, suppressMilliseconds: true }).slice(0, 16); updateComparison(true); @@ -546,9 +615,12 @@

Shareable link

timezoneManuallySet = true; updateComparison(); }); + baseTimezoneSelect.addEventListener('change', () => { + updateBaseZone(baseTimezoneSelect.value, 'Manually selected base time zone.'); + }); copyButton.addEventListener('click', copyLink); addComparisonRowButton.addEventListener('click', () => { - const defaultZone = timezoneSelect.value || localZone; + const defaultZone = timezoneSelect.value || baseZone; addCustomComparisonRow(defaultZone); updateComparison(); });