ui: convert jst to local time

This commit is contained in:
2026-04-10 22:40:52 +02:00
parent 71a38fb866
commit bb5be54c26
4 changed files with 116 additions and 2 deletions

View File

@@ -149,7 +149,7 @@ templ AnimeDetails(anime jikan.Anime, currentStatus string) {
if anime.Broadcast.String != "" {
<div class="sidebar-row">
<span class="sidebar-label">Broadcast</span>
<span class="sidebar-value">{ anime.Broadcast.String }</span>
<span class="sidebar-value" data-jst-text={ anime.Broadcast.String }>{ anime.Broadcast.String }</span>
</div>
}
if len(anime.Streaming) > 0 {

View File

@@ -14,6 +14,7 @@ templ Layout(title string) {
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
<script src="/static/js/discover.js" defer></script>
<script src="/static/js/anime.js" defer></script>
<script src="/static/js/timezone.js" defer></script>
</head>
<body>
<header>

View File

@@ -124,7 +124,7 @@ templ NotificationCard(item WatchingAnimeWithDetails) {
</div>
<div class="notification-meta">
if item.Anime.Broadcast.String != "" {
<span class="notification-broadcast">{ item.Anime.Broadcast.String }</span>
<span class="notification-broadcast" data-jst-text={ item.Anime.Broadcast.String }>{ item.Anime.Broadcast.String }</span>
}
if item.Anime.Episodes > 0 {
<span class="notification-progress">

113
static/js/timezone.js Normal file
View File

@@ -0,0 +1,113 @@
;(function () {
const jstOffsetMinutes = 9 * 60
const parseBroadcast = (text) => {
const match = text.match(/^(.*) at (\d{1,2}):(\d{2}) \(JST\)$/i)
if (!match) {
return null
}
const day = match[1].trim()
const hour = Number.parseInt(match[2], 10)
const minute = Number.parseInt(match[3], 10)
if (Number.isNaN(hour) || Number.isNaN(minute)) {
return null
}
return { day, hour, minute }
}
const normalizeDay = (day) => {
const key = day.trim().toLowerCase().replace(/s$/, '')
const days = {
mon: 1,
monday: 1,
tue: 2,
tues: 2,
tuesday: 2,
wed: 3,
wednesday: 3,
thu: 4,
thur: 4,
thurs: 4,
thursday: 4,
fri: 5,
friday: 5,
sat: 6,
saturday: 6,
sun: 0,
sunday: 0,
}
if (typeof days[key] !== 'number') {
return null
}
return days[key]
}
const convertToLocal = (parsed, localOffsetMinutes) => {
const sourceMinutes = parsed.hour * 60 + parsed.minute
const diff = jstOffsetMinutes - localOffsetMinutes
const localTotal = sourceMinutes - diff
const dayShift = Math.floor(localTotal / 1440)
const normalizedMinutes = ((localTotal % 1440) + 1440) % 1440
const localHour = Math.floor(normalizedMinutes / 60)
const localMinute = normalizedMinutes % 60
const sourceDayIndex = normalizeDay(parsed.day)
if (sourceDayIndex === null) {
return null
}
const localDayIndex = ((sourceDayIndex + dayShift) % 7 + 7) % 7
const localDay = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][localDayIndex]
const time = `${localHour.toString().padStart(2, '0')}:${localMinute.toString().padStart(2, '0')}`
return `${localDay} at ${time} (Local)`
}
const updateNode = (node, localOffsetMinutes) => {
const source = node.getAttribute('data-jst-text')
if (!source) {
return
}
const parsed = parseBroadcast(source)
if (!parsed) {
return
}
const converted = convertToLocal(parsed, localOffsetMinutes)
if (!converted) {
return
}
node.textContent = converted
}
const hideJstSuffix = () => {
document.querySelectorAll('.notification-broadcast, [data-jst-text]').forEach((node) => {
if (!(node instanceof HTMLElement)) {
return
}
const text = node.textContent || ''
if (text.includes('(JST)')) {
node.textContent = text.replace(/\s*\(JST\)/gi, ' (Local)')
}
})
}
const updateAll = () => {
const localOffsetMinutes = -new Date().getTimezoneOffset()
const nodes = document.querySelectorAll('[data-jst-text]')
nodes.forEach((node) => updateNode(node, localOffsetMinutes))
hideJstSuffix()
}
document.addEventListener('DOMContentLoaded', updateAll)
document.body.addEventListener('htmx:afterSwap', updateAll)
})()