diff --git a/index.css b/index.css index ceb594a..e7a2953 100644 --- a/index.css +++ b/index.css @@ -10,8 +10,11 @@ :root { --blue: #2D327D; + --granite: #686868; + --graphite: #B7B7B7; --cloud: #E5E5E5; --white: #FFFFFF; + --black: #000000; --red: #EB0000; --red125: #C60018; --red150: #A20013; @@ -35,7 +38,48 @@ body { } #station { - color: black; + display: flex; + gap: 1em; + align-items: flex-end; + color: var(--black); + margin: 1em 0; +} + +#refresh { + width: 3.4em; + height: 3.4em; + cursor: pointer; + position: relative; + background-color: var(--white); + border: none; + transition: background-color 0.2s; +} + +#refresh::after { + content: ""; + position: absolute; + inset: 0; + width: 100%; + height: 100%; + background-color: var(--granite); + mask-image: url(icons/arrows-circle-medium.svg); + -webkit-mask-image: url(icons/arrows-circle-medium.svg); + mask-size: contain; + -webkit-mask-size: contain; + mask-position: center; + -webkit-mask-position: center; + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + transition: transform 0.2s; + will-change: transform; +} + +#refresh:hover { + background-color: var(--cloud); +} + +#refresh:hover::after { + transform: rotate(90deg); } #grid { @@ -210,4 +254,109 @@ body { -webkit-mask-repeat: no-repeat; mask-position: center; -webkit-mask-position: center; +} + +#search { + display: flex; + gap: 0.5em; +} + +#search-input { + font-family: inherit; + font-size: 80%; + padding: 6px 8px 6px 8px; + border: solid var(--graphite) 1px; +} + +#search-input:focus-visible { + outline: none; + border-color: var(--granite); +} + +#search-btn { + font-family: inherit; + font-size: 80%; + padding: 11px 40px 11px 40px; + background-color: var(--red); + color: var(--white); + border: none; + cursor: pointer; +} + +#search-btn:hover { + background-color: var(--red125); +} + +#stations { + display: flex; + flex-direction: column; +} + +#stations .station { + padding: 0.5em 2em; + border-bottom: solid var(--graphite) 1px; + cursor: pointer; + color: var(--black); +} + +#stations .station:last-child { + border-bottom: none; +} + +#stations .station:hover { + background-color: var(--cloud); +} + +.select-wrapper { + position: relative; + width: 10em; +} +.select-wrapper select { + font-family: inherit; + font-size: inherit; + background-color: var(--white); + border: solid var(--graphite) 1px; + border-radius: 0; + padding: 11px 40px 11px 40px; + color: var(--granite); + text-align: left; + appearance: none; + -webkit-appearance: none; + width: 100%; + cursor: pointer; +} + +.select-wrapper .select-arrow { + width: 2em; + height: 100%; + position: absolute; + right: 0; + background-color: var(--granite); + mask-image: url(icons/chevron-small-down-medium.svg); + -webkit-mask-image: url(icons/chevron-small-down-medium.svg); + mask-size: contain; + -webkit-mask-size: contain; + mask-position: center; + -webkit-mask-position: center; + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + pointer-events: none; +} + +.select-wrapper select:focus-visible { + outline: none; + border-color: var(--granite); +} + +.field { + display: flex; + flex-direction: column; + gap: 0.2em; +} + +.field label { + font-family: inherit; + font-size: 80%; + color: var(--granite); + padding-left: 0.5em; } \ No newline at end of file diff --git a/index.html b/index.html index 255020f..1ff59fd 100644 --- a/index.html +++ b/index.html @@ -15,7 +15,22 @@
-

St-Maurice

+ +
+
+

St-Maurice

+
+ +
+ + +
+
+ +
InterCity 61 diff --git a/index.js b/index.js index 717f24a..e3a5169 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,93 @@ const MAX_DISPLAYED_VIAS = 4 +let currentBpuic = null +let currentPlatform = null +let currentInfo = null + +function initSearch() { + const sInput = document.getElementById("search-input") + const form = document.getElementById("search") + const refresh = document.getElementById("refresh") + const platforms = document.getElementById("platforms") + + form.addEventListener("submit", e => { + e.preventDefault() + searchStation(sInput.value) + .then(stations => updateStationsList(stations)) + }) + + refresh.addEventListener("click", () => { + if (currentBpuic !== null) { + setStation(currentBpuic) + } + }) + + platforms.addEventListener("change", () => { + setPlatform(platforms.value) + }) +} + +function updateStationsList(stations) { + const stationsList = document.getElementById("stations") + stationsList.innerHTML = "" + stations.forEach(station => { + const div = document.createElement("div") + div.classList.add("station") + div.innerText = station.bezeichnungOffiziell + div.addEventListener("click", () => setStation(station.bpuic)) + stationsList.appendChild(div) + }) +} + +function setStation(bpuic) { + if (bpuic !== currentBpuic) { + currentPlatform = null + } + currentBpuic = bpuic + fetchInfo(bpuic).then(res => { + currentInfo = res + document.getElementById("search-input").value = "" + document.getElementById("stations").innerHTML = "" + + const platformsList = document.getElementById("platforms") + platformsList.innerHTML = "" + + let platforms = res.contents[0].verkehrsmittels.map(train => train.gleisAbIst) + platforms = [... new Set(platforms)] + platforms = platforms.sort() + platforms.forEach(platform => { + const opt = document.createElement("option") + opt.value = platform + opt.innerText = platform + if (currentPlatform === platform) { + opt.selected = true + } + platformsList.appendChild(opt) + }) + + const station = document.getElementById("station") + station.querySelector(".name").innerText = res.contents[0].betriebspunkt.bezeichnungOffiziell + updateDisplay(res, 0, currentPlatform) + }) +} + +function setPlatform(platform) { + const platforms = document.getElementById("platforms") + currentPlatform = platforms.value + if (currentInfo === null) return + updateDisplay(currentInfo, 0, platform) +} function searchStation(query) { return fetch(`https://displays.api.sbb.ch/internal/api/v1/betriebspunkt?query=${query}`, { headers: { "X-API-Key": API_KEY } - }).then(res => { - return res.json() + }).then(async (res) => { + let stations = [] + if (res.status === 200) { + stations = await res.json() + } + return stations }) } @@ -47,8 +128,8 @@ const example = { }, zeitAbKb: "2024-04-08T18:32:00", // heure de départ prévue zeitAbErw: "2024-04-08T18:33:00", // heure de départ réelle - gleisAbKb: 1, // voie prévue - gleisAbIst: 1, // voie réelle + gleisAbKb: "1", // voie prévue + gleisAbIst: "1", // voie réelle verspaetungsminutenAb: 0, // au moins n minutes de retard verspaetungsminutenAn: 0, // au plus n minutes de retard ziele: [ @@ -204,8 +285,6 @@ function buildComposition(formation) { } function updateDisplay(result, idx=0, platform=null) { - document.getElementById("station").innerText = result.config.stationName - let trains = result.contents[0].verkehrsmittels if (platform !== null) { trains = trains.filter(t => t.gleisAbIst === platform) @@ -235,4 +314,8 @@ function updateDisplay(result, idx=0, platform=null) { }) buildComposition(train.formation) -} \ No newline at end of file +} + +window.addEventListener("load", () => { + initSearch() +}) \ No newline at end of file