diff options
Diffstat (limited to 'VegaData/wwwroot')
| -rw-r--r-- | VegaData/wwwroot/17.png | bin | 5334 -> 0 bytes | |||
| -rw-r--r-- | VegaData/wwwroot/framework.js | 166 | ||||
| -rw-r--r-- | VegaData/wwwroot/index.html | 140 | ||||
| -rw-r--r-- | VegaData/wwwroot/index.js | 152 | ||||
| -rw-r--r-- | VegaData/wwwroot/version.txt | 1 |
5 files changed, 0 insertions, 459 deletions
diff --git a/VegaData/wwwroot/17.png b/VegaData/wwwroot/17.png Binary files differdeleted file mode 100644 index 7895530..0000000 --- a/VegaData/wwwroot/17.png +++ /dev/null diff --git a/VegaData/wwwroot/framework.js b/VegaData/wwwroot/framework.js deleted file mode 100644 index d1e6cc6..0000000 --- a/VegaData/wwwroot/framework.js +++ /dev/null @@ -1,166 +0,0 @@ -const targetMap = new WeakMap(); -let activeEffect = null; - -const root = document.getElementById("root"); - -function createElement(tagName, props = {}, children = []) { - const el = document.createElement(tagName); - - for (const [key, value] of Object.entries(props || {})) { - if (key.startsWith("on") && typeof value === "function") { - el.addEventListener(key.substring(2).toLowerCase(), value); - } else if (key === "style" && typeof value === "object") { - Object.assign(el.style, value); - } else { - el.setAttribute(key, value); - } - } - - const appendChild = (child) => { - if (Array.isArray(child)) { - child.forEach(appendChild); - } else if (typeof child === "function") { - const placeholder = document.createTextNode(""); - el.appendChild(placeholder); - e(() => { - placeholder.textContent = child() ?? ""; - }); - } else if (child instanceof Node) { - el.appendChild(child); - } else if (child != null) { - el.appendChild(document.createTextNode(String(child))); - } - }; - - children.forEach(appendChild); - return el; -} - -function track(target, key) { - if (!activeEffect) { - return; - } - let depsMap = targetMap.get(target); - if (!depsMap) { - depsMap = new Map(); - targetMap.set(target, depsMap); - } - - let dep = depsMap.get(key); - if (!dep) { - dep = new Set(); - depsMap.set(key, dep); - } - - dep.add(activeEffect); -} - -function trigger(target, key) { - const depsMap = targetMap.get(target); - if (!depsMap) { - return; - } - - const dep = depsMap.get(key); - if (dep) { - dep.forEach((effect) => effect()); - } -} - -//** -// Create a reactive value, the value is at .value. -// To use this in element props you need to supply the .value read as a function. -// */ -export function r(target) { - target = { value: target }; - return new Proxy(target, { - get(obj, key, receiver) { - track(obj, key); - return Reflect.get(obj, key, receiver); - }, - set(obj, key, value, receiver) { - const result = Reflect.set(obj, key, value, receiver); - trigger(obj, key); - return result; - }, - }); -} - -//** -// Run code when value changes -// */ -export function e(fn) { - let active = true; - - const runner = () => { - if (active) { - activeEffect = runner; - fn(); - activeEffect = null; - } - }; - - runner(); - - runner.stop = () => { - active = false; - }; - - return runner; -} - -export function gqp(key) { - return new URLSearchParams(location.search).get(key) -} - -export function sqp(query) { - if ('URLSearchParams' in window) { - const url = new URL(window.location) - for (const key of Object.keys(query)) { - const value = encodeURIComponent(query[key]) - if (!value || value === "") url.searchParams.delete(key) - else url.searchParams.set(key, value) - } - history.pushState(null, '', url); - } -} - -//** -// Combine elements -// */ -export function c(a, b) { - const normalize = (x) => (x == null ? [] : Array.isArray(x) ? x : [x]); - - return [...normalize(a), ...normalize(b)]; -} - -//** -// Mount element to a target (target is #root by default) -// */ -export async function m(component, target = root) { - if (typeof component === "function") { - component = await component(); - } - if (Array.isArray(component)) { - target.append(...component); - } else { - target.appendChild(component); - } -} - -export function css(styleObject) { - return Object.entries(styleObject).map(([key, value]) => { - const kebabKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); - return `${kebabKey}: ${value}`; - }).join("; "); -} - -//** -// Create element -// */ -export function t(name, props, ...children) { - if (typeof name === "function") { - return name({ ...props, children }); - } - return createElement(name, props, children); -} diff --git a/VegaData/wwwroot/index.html b/VegaData/wwwroot/index.html deleted file mode 100644 index a47b9e2..0000000 --- a/VegaData/wwwroot/index.html +++ /dev/null @@ -1,140 +0,0 @@ -<!doctype html> -<html lang="nb"> - -<head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <style> - * { - box-sizing: border-box; - } - - :root { - --bg: beige; - } - - #search { - padding: 10px 12px; - min-width: 300px; - } - - html, - body { - margin: 0; - padding: 0; - background: var(--bg); - font-family: Palatino, Georgia, serif; - } - - li:target, - .activeShow { - padding-block: 2rem; - padding-inline: 1rem; - background-image: url("./17.png"); - - div:first-of-type { - padding-block: .4rem; - padding-inline-start: .5rem; - background-color: var(--bg); - } - } - - #ulShows { - height: 80vh; - overflow-x: auto; - } - - #times { - padding-left: 15px; - } - - main { - padding-inline: 10px; - } - - .show { - margin-bottom: 1rem; - width: 100%; - - .title { - position: sticky; - top: 0; - width: 100%; - display: flex; - align-items: baseline; - justify-content: space-between; - background: bisque; - padding-inline: 3px; - padding-bottom: 5px; - - h2 { - font-weight: 600; - overflow-wrap: break-word; - hyphens: manual; - margin-top: 0; - margin-bottom: 0; - } - } - } - - .time { - font-style: normal; - font-size: 1rem; - text-decoration: none; - font-weight: 400; - margin-bottom: 15px; - - .date::first-letter { - border-left: 2px solid gold; - padding-left: 2px; - } - - div { - display: flex; - flex-direction: column; - - span:first-of-type { - font-size: 1.2rem; - } - } - - .actions { - display: flex; - flex-direction: row; - gap: 1rem; - } - } - - h1 { - margin: 0; - padding: 10px; - } - - ul { - list-style: none; - margin: 0; - padding: 0; - margin-top: 10px; - } - </style> - <title>Vega eller</title> -</head> - -<body> - <h1>Bli med på vega?</h1> - <main> - <button id="renderShowsBtn">tilbakestill</button> <br> - <input type="search" name="q1" id="search" placeholder="søk"> - <ul id="ulShows"></ul> - </main> - <script type="importmap"> - { - "imports": { - "temporal-polyfill": "https://esm.sh/temporal-polyfill@0.3.0" - } - } - </script> - <script type="module" src="index.js"></script> -</body> - -</html>
\ No newline at end of file diff --git a/VegaData/wwwroot/index.js b/VegaData/wwwroot/index.js deleted file mode 100644 index 45af7f2..0000000 --- a/VegaData/wwwroot/index.js +++ /dev/null @@ -1,152 +0,0 @@ -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 diff --git a/VegaData/wwwroot/version.txt b/VegaData/wwwroot/version.txt deleted file mode 100644 index a97cee7..0000000 --- a/VegaData/wwwroot/version.txt +++ /dev/null @@ -1 +0,0 @@ -v29 |
