added search bar + platform select + refresh btn
This commit is contained in:
parent
acb585b47a
commit
8cc2c7b019
151
index.css
151
index.css
@ -10,8 +10,11 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--blue: #2D327D;
|
--blue: #2D327D;
|
||||||
|
--granite: #686868;
|
||||||
|
--graphite: #B7B7B7;
|
||||||
--cloud: #E5E5E5;
|
--cloud: #E5E5E5;
|
||||||
--white: #FFFFFF;
|
--white: #FFFFFF;
|
||||||
|
--black: #000000;
|
||||||
--red: #EB0000;
|
--red: #EB0000;
|
||||||
--red125: #C60018;
|
--red125: #C60018;
|
||||||
--red150: #A20013;
|
--red150: #A20013;
|
||||||
@ -35,7 +38,48 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#station {
|
#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 {
|
#grid {
|
||||||
@ -210,4 +254,109 @@ body {
|
|||||||
-webkit-mask-repeat: no-repeat;
|
-webkit-mask-repeat: no-repeat;
|
||||||
mask-position: center;
|
mask-position: center;
|
||||||
-webkit-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;
|
||||||
}
|
}
|
17
index.html
17
index.html
@ -15,7 +15,22 @@
|
|||||||
<div class="services"></div>
|
<div class="services"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 id="station">St-Maurice</h1>
|
<form id="search">
|
||||||
|
<input type="text" id="search-input" placeholder="Station...">
|
||||||
|
<button id="search-btn">Search</button>
|
||||||
|
</form>
|
||||||
|
<div id="stations"></div>
|
||||||
|
<div id="station">
|
||||||
|
<h1 class="name">St-Maurice</h1>
|
||||||
|
<div class="field">
|
||||||
|
<label for="platforms">Platform</label>
|
||||||
|
<div class="select-wrapper">
|
||||||
|
<select id="platforms"></select>
|
||||||
|
<span class="select-arrow"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="refresh"></button>
|
||||||
|
</div>
|
||||||
<div id="grid">
|
<div id="grid">
|
||||||
<div id="type-time">
|
<div id="type-time">
|
||||||
<img id="train-type" src="icons/ic-61.svg" alt="InterCity 61">
|
<img id="train-type" src="icons/ic-61.svg" alt="InterCity 61">
|
||||||
|
97
index.js
97
index.js
@ -1,12 +1,93 @@
|
|||||||
const MAX_DISPLAYED_VIAS = 4
|
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) {
|
function searchStation(query) {
|
||||||
return fetch(`https://displays.api.sbb.ch/internal/api/v1/betriebspunkt?query=${query}`, {
|
return fetch(`https://displays.api.sbb.ch/internal/api/v1/betriebspunkt?query=${query}`, {
|
||||||
headers: {
|
headers: {
|
||||||
"X-API-Key": API_KEY
|
"X-API-Key": API_KEY
|
||||||
}
|
}
|
||||||
}).then(res => {
|
}).then(async (res) => {
|
||||||
return res.json()
|
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
|
zeitAbKb: "2024-04-08T18:32:00", // heure de départ prévue
|
||||||
zeitAbErw: "2024-04-08T18:33:00", // heure de départ réelle
|
zeitAbErw: "2024-04-08T18:33:00", // heure de départ réelle
|
||||||
gleisAbKb: 1, // voie prévue
|
gleisAbKb: "1", // voie prévue
|
||||||
gleisAbIst: 1, // voie réelle
|
gleisAbIst: "1", // voie réelle
|
||||||
verspaetungsminutenAb: 0, // au moins n minutes de retard
|
verspaetungsminutenAb: 0, // au moins n minutes de retard
|
||||||
verspaetungsminutenAn: 0, // au plus n minutes de retard
|
verspaetungsminutenAn: 0, // au plus n minutes de retard
|
||||||
ziele: [
|
ziele: [
|
||||||
@ -204,8 +285,6 @@ function buildComposition(formation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateDisplay(result, idx=0, platform=null) {
|
function updateDisplay(result, idx=0, platform=null) {
|
||||||
document.getElementById("station").innerText = result.config.stationName
|
|
||||||
|
|
||||||
let trains = result.contents[0].verkehrsmittels
|
let trains = result.contents[0].verkehrsmittels
|
||||||
if (platform !== null) {
|
if (platform !== null) {
|
||||||
trains = trains.filter(t => t.gleisAbIst === platform)
|
trains = trains.filter(t => t.gleisAbIst === platform)
|
||||||
@ -235,4 +314,8 @@ function updateDisplay(result, idx=0, platform=null) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
buildComposition(train.formation)
|
buildComposition(train.formation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
initSearch()
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user