diff options
| author | ivar <i@oiee.no> | 2025-10-26 11:33:38 +0100 |
|---|---|---|
| committer | ivar <i@oiee.no> | 2025-10-26 11:33:38 +0100 |
| commit | 2e8ad7dc6d49361c6ee00dc628e119c0c06e2779 (patch) | |
| tree | becc4cde99eff6ed1d168f9e9c454c0f2bbbee9d /VegaData/wwwroot/index.js | |
| parent | 8de1187b627625b94ef8088de3e9255ccd17baf4 (diff) | |
| download | vegadata-2e8ad7dc6d49361c6ee00dc628e119c0c06e2779.tar.xz vegadata-2e8ad7dc6d49361c6ee00dc628e119c0c06e2779.zip | |
.
Diffstat (limited to 'VegaData/wwwroot/index.js')
| -rw-r--r-- | VegaData/wwwroot/index.js | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/VegaData/wwwroot/index.js b/VegaData/wwwroot/index.js new file mode 100644 index 0000000..45af7f2 --- /dev/null +++ b/VegaData/wwwroot/index.js @@ -0,0 +1,152 @@ +import { Temporal } from "temporal-polyfill"; +import { gqp, sqp, t } from "./framework.js"; + +let _; + +async function getShows() { + if (_) return _; + const response = await fetch("/shows"); + _ = await response.json(); + return _; +} + +const ulShows = document.getElementById("ulShows"); +const search = document.getElementById("search"); +const renderShowsBtn = document.getElementById("renderShowsBtn"); + +renderShowsBtn.addEventListener("click", () => { + renderShows(""); + search.value = ""; +}); + +function dateString(date, small = false) { + const instant = Temporal.Instant.from(`${date}Z`) + const stringOptions = { + weekday: "long", + hour: "2-digit", + timeZone: "UTC", + minute: "2-digit", + month: "long", + calendar: "gregory", + day: "numeric" + } + + if (small) { + return instant.toLocaleString("nb-NO", stringOptions); + } + + return instant.toLocaleString("nb-NO", { + year: "numeric", + era: "long", + ...stringOptions + }); +} + +function copyLink(t, e) { + const initialInnerText = t.target.innerText; + if ("clipboard" in navigator) { + navigator.clipboard.writeText(`${location.origin}/index.html#${urlId(e)}`) + t.target.innerText = `${initialInnerText} ✓` + setTimeout(() => { + t.target.innerText = initialInnerText + }, 1000) + } +} + +function vegascene(showing) { + if (showing.movieMainVersion.startsWith("KUL")) return `https://www.vegascene.no/teater/${showing.movieMainVersion}` + return `https://www.vegascene.no/film/${showing.movieMainVersion}` +} + +function urlId(e) { + return `${e.movieVersion}${e.startDateTime}`.replaceAll("-", "").replaceAll(" ", "").replaceAll(":", "") +} + +async function renderShows(query, rendered) { + query = query?.trim(); + sqp({ q: query ?? "" }) + + const shows = (await getShows()).reduce((acc, curr) => { + const key = curr.title; + if (!acc[key]) { + acc[key] = []; + } + acc[key].push(curr); + return acc; + }, {}); + + async function share(show) { + const shareData = { + title: `${show.title} ${dateString(show.startDateTime, true)} på vega`, + url: `${location.origin}/index.html#${urlId(show)}`, + } + await navigator.share(shareData); + } + + const lis = []; + + for (const showKey of Object.keys(shows).sort((a, b) => a.localeCompare(b))) { + const times = shows[showKey].sort((a, b) => Temporal.PlainDate.compare(Temporal.PlainDate.from(a.startDateTime), Temporal.PlainDate.from(b.startDateTime))) + if (query) { + const words = [showKey.toLowerCase()] + for (const time of times) { + words.push(dateString(time.startDateTime)) + words.push(time.scene) + words.push(time.tags.join(" ")) + } + if (!words.some((word) => word.match(query.toLowerCase()))) continue; + } + + lis.push( + t("li", { class: "show", id: showKey }, [ + t("div", { class: "title" }, [ + t("h2", { class: "italic" }, showKey), + t("a", { href: vegascene(shows[showKey][0]) }, "(Åpne på vegascene.no)") + ]), + t("ul", { id: "times" }, [ + t("li", undefined, + times.filter(e => e.ticketUrl !== "").map(e => { + let tagLine = `${e.scene} - ${[e.type, ...e.tags].join(", ")}` + tagLine = tagLine[0].toUpperCase() + tagLine.slice(1) + let dateLine = dateString(e.startDateTime) + dateLine = dateLine[0].toUpperCase() + dateLine.slice(1) + return t("li", { class: `time time-${e.id}`, id: urlId(e) }, [ + t("div", undefined, [ + t("span", { title: e.startDateTime, class: "date" }, dateLine), + t("span", undefined, tagLine), + t("div", { class: "actions" }, [ + t("a", { href: e.ticketUrl }, "Billetter"), + "share" in navigator ? t("button", { onclick: () => share(e) }, "Del tid") : null, + t("button", { onclick: (t) => copyLink(t, e) }, "Kopier lenke") + ]) + ]) + ]) + })) + ]) + ]) + ) + } + + if (!lis.length) ulShows.replaceChildren(...[t("i", undefined, "Dessverre")]) + else ulShows.replaceChildren(...lis); + + const interval = setInterval(() => { + const element = document.querySelector("#ulShows"); + if (element.childNodes.length > 0) { + clearInterval(interval); + rendered(); + } + }, 50); +} + +renderShows(search.value, () => { + if (gqp("q")) search.value = gqp("q") + search.addEventListener("input", e => renderShows(e.currentTarget.value)); + const id = location.href.indexOf("#") !== -1 ? location.href.substring(location.href.indexOf("#")) : "" + if (id !== "") { + const target = document.querySelector(id) + target.scrollIntoView({ behavior: "smooth", block: "center" }) + target.classList.add("activeShow") + document.querySelectorAll(".time").forEach(el => el.id !== id.slice(1) && el.classList.remove("activeShow")) + } +});
\ No newline at end of file |
