adds localization, changed frontend

This commit is contained in:
Erwin Sperling 2024-12-22 15:03:43 +01:00
parent 20edaf4d00
commit abde59ff56
8 changed files with 192 additions and 33 deletions

View File

@ -11,6 +11,8 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-i18n": "^10.0.5",
"vue-router": "^4.5.0",
"vuetify": "^3.7.4" "vuetify": "^3.7.4"
}, },
"devDependencies": { "devDependencies": {
@ -1776,6 +1778,50 @@
"deprecated": "Use @eslint/object-schema instead", "deprecated": "Use @eslint/object-schema instead",
"dev": true "dev": true
}, },
"node_modules/@intlify/core-base": {
"version": "10.0.5",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.5.tgz",
"integrity": "sha512-F3snDTQs0MdvnnyzTDTVkOYVAZOE/MHwRvF7mn7Jw1yuih4NrFYLNYIymGlLmq4HU2iIdzYsZ7f47bOcwY73XQ==",
"license": "MIT",
"dependencies": {
"@intlify/message-compiler": "10.0.5",
"@intlify/shared": "10.0.5"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/message-compiler": {
"version": "10.0.5",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.5.tgz",
"integrity": "sha512-6GT1BJ852gZ0gItNZN2krX5QAmea+cmdjMvsWohArAZ3GmHdnNANEcF9JjPXAMRtQ6Ux5E269ymamg/+WU6tQA==",
"license": "MIT",
"dependencies": {
"@intlify/shared": "10.0.5",
"source-map-js": "^1.0.2"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/shared": {
"version": "10.0.5",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.5.tgz",
"integrity": "sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jridgewell/gen-mapping": { "node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5", "version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@ -2768,6 +2814,12 @@
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
"dev": true "dev": true
}, },
"node_modules/@vue/devtools-api": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/@vue/reactivity": { "node_modules/@vue/reactivity": {
"version": "3.5.13", "version": "3.5.13",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz",
@ -10433,6 +10485,26 @@
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
"dev": true "dev": true
}, },
"node_modules/vue-i18n": {
"version": "10.0.5",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.5.tgz",
"integrity": "sha512-9/gmDlCblz3i8ypu/afiIc/SUIfTTE1mr0mZhb9pk70xo2csHAM9mp2gdQ3KD2O0AM3Hz/5ypb+FycTj/lHlPQ==",
"license": "MIT",
"dependencies": {
"@intlify/core-base": "10.0.5",
"@intlify/shared": "10.0.5",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-loader": { "node_modules/vue-loader": {
"version": "17.4.2", "version": "17.4.2",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz",
@ -10471,6 +10543,21 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "url": "https://github.com/chalk/chalk?sponsor=1"
} }
}, },
"node_modules/vue-router": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz",
"integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^6.6.4"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/vue-style-loader": { "node_modules/vue-style-loader": {
"version": "4.1.3", "version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",

View File

@ -11,6 +11,8 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-i18n": "^10.0.5",
"vue-router": "^4.5.0",
"vuetify": "^3.7.4" "vuetify": "^3.7.4"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,15 +1,29 @@
<template> <template>
<search/> <div class="navbar">
<div class="locale-changer">
<select v-model="$i18n.locale">
<option v-for="locale in $i18n.availableLocales" :key="`locale-${locale}`" :value="locale">{{ locale }}</option>
</select>
</div>
<nav>
<RouterLink to="/search">Search</RouterLink>
</nav>
</div>
<main>
<RouterView />
</main>
</template> </template>
<script> <script>
import search from './components/search.vue'
export default { export default {
name: 'App', name: 'App',
components: { components: {
search },
methods: {
showRouter(){
console.log(this.$route);
}
} }
} }
</script> </script>
@ -23,4 +37,11 @@ export default {
color: #2c3e50; color: #2c3e50;
margin-top: 60px; margin-top: 60px;
} }
.navbar {
display:inline-flex;
background-color:grey;
}
.navbar>* {
padding:10px;
}
</style> </style>

View File

@ -8,16 +8,19 @@
<div class="linenameinner" :style="{backgroundColor:getLineColors(leg)[1], color:getLineColors(leg)[0]}">{{ leg.direction }}</div> <div class="linenameinner" :style="{backgroundColor:getLineColors(leg)[1], color:getLineColors(leg)[0]}">{{ leg.direction }}</div>
</div> </div>
<div class="lineinfo"> <div class="lineinfo">
<div class="station" >{{ leg.origin.name }}<br/>{{ toTime(leg.departure) }}<p v-if="leg.departurePlatform"> Gleis {{ leg.departurePlatform }} </p></div> <div class="station" >{{ leg.origin.name }}<br/>{{ timeWithDelay(leg.departure, leg.departureDelay) }}<p v-if="leg.departurePlatform"> Gleis {{ leg.departurePlatform }} </p></div>
<div class="line"> <div class="line">
<p class="zugnummer">{{ leg.line?.fahrtNr }}</p> <p class="zugnummer">{{ leg.line?.fahrtNr }}</p>
<p class="operator" v-if="!getOperatorLogo(leg.line?.operator)">{{ leg.line?.operator?.name }}</p> <p class="operator" v-if="!getOperatorLogo(leg.line?.operator)">{{ leg.line?.operator?.name }}</p>
<img class="operator-logo" :src="getOperatorLogo(leg.line?.operator)" v-if="getOperatorLogo(leg.line?.operator)"> <img class="operator-logo" :src="getOperatorLogo(leg.line?.operator)" v-if="getOperatorLogo(leg.line?.operator)">
</div> </div>
<div class="station">{{ leg.destination.name }}<br/>{{ toTime(leg.arrival) }} <p v-if="leg.arrivalPlatform">Gleis {{ leg.arrivalPlatform }}</p></div> <div class="station">{{ leg.destination.name }}<br/>{{ timeWithDelay(leg.arrival, leg.arrivalDelay) }} <p v-if="leg.arrivalPlatform">Gleis {{ leg.arrivalPlatform }}</p></div>
</div>
<div>
<p v-for="remark in leg.remarks" :key="leg.remarks.indexOf(remark)">{{remark.text}}</p>
</div>
</div> </div>
<hr/> <hr/>
</div>
</div></div> </div></div>
</div> </div>
</template> </template>
@ -48,6 +51,13 @@
toDate(string){ toDate(string){
return new Date(string).toLocaleDateString("de-DE"); return new Date(string).toLocaleDateString("de-DE");
}, },
timeWithDelay(actual, delay){
let time = this.toTime(actual);
if (delay > 30){
return time + " +" + Math.ceil(delay/60.0);
}
return time;
},
toTime(string){ toTime(string){
return new Date(string).toLocaleTimeString("de-DE", {timeStyle: 'short'}); return new Date(string).toLocaleTimeString("de-DE", {timeStyle: 'short'});
}, },
@ -95,7 +105,7 @@
.line { .line {
margin: 4px; margin: 4px;
display: inline-block; display: inline-block;
width:100px; width:120px;
vertical-align: text-top; vertical-align: text-top;
align-content: center; align-content: center;
} }

View File

@ -8,13 +8,13 @@
:items="services" :items="services"
item-title="name" item-title="name"
item-value="id" item-value="id"
label="Service" :label="$t('search.fields.service')"
class="inputTextField" class="inputTextField"
></v-select> ></v-select>
<v-text-field <v-text-field
v-model="date.value" v-model="date.value"
:active="date.menu" :active="date.menu"
label="date" :label="$t('search.fields.date')"
prepend-icon="mdi mdi-calendar-month" prepend-icon="mdi mdi-calendar-month"
readonly readonly
class="inputTextField" class="inputTextField"
@ -37,7 +37,7 @@
<v-text-field <v-text-field
v-model="time.value" v-model="time.value"
:active="time.menu" :active="time.menu"
label="time" :label="$t('search.fields.time')"
prepend-icon="mdi mdi-clock-outline" prepend-icon="mdi mdi-clock-outline"
readonly readonly
class="inputTextField" class="inputTextField"
@ -60,7 +60,7 @@
<v-text-field <v-text-field
prepend-icon="mdi mdi-ray-start-arrow" prepend-icon="mdi mdi-ray-start-arrow"
:active="from.menu" :active="from.menu"
label="from" :label="$t('search.fields.from')"
type="text" type="text"
v-model="fromName" v-model="fromName"
class="inputTextField" class="inputTextField"
@ -82,7 +82,7 @@
<v-text-field <v-text-field
prepend-icon="mdi mdi-bullseye" prepend-icon="mdi mdi-bullseye"
:active="to.menu" :active="to.menu"
label="to" :label="$t('search.fields.to')"
type="text" type="text"
v-model="toName" v-model="toName"
class="inputTextField" class="inputTextField"
@ -109,7 +109,6 @@
import axios from 'axios'; import axios from 'axios';
import { VTimePicker } from 'vuetify/labs/VTimePicker'; import { VTimePicker } from 'vuetify/labs/VTimePicker';
import { VDatePicker } from 'vuetify/components/VDatePicker'; import { VDatePicker } from 'vuetify/components/VDatePicker';
const client = axios.create({ const client = axios.create({
baseURL: process.env.VUE_APP_BASE_URL baseURL: process.env.VUE_APP_BASE_URL
}); });
@ -138,11 +137,11 @@
toName : "", toName : "",
connections: [], connections: [],
showRouting: false, showRouting: false,
time: {value:new Date().toLocaleTimeString(), menu:false}, time: {value:new Date().toLocaleTimeString("de"), menu:false},
date: {value:new Date(), menu:false}, date: {value:new Date(), menu:false},
services: services, services: services,
selectedService: services[0].id, selectedService: services[0].id,
isMobile: false, isMobile: this.$route.query.m,
} }
}, },
methods: { methods: {

View File

@ -0,0 +1,19 @@
{
"global":{
"option":{
"mobile": "mobil"
}
},
"search":{
"fields":{
"service":"Dienst",
"date":"Datum",
"time":"Uhrzeit",
"from":"von",
"to":"nach"
},
"buttons":{
"searchConnection":"Verbindung suchen"
}
}
}

View File

@ -0,0 +1,19 @@
{
"global":{
"option":{
"mobile": "mobile"
}
},
"search":{
"fields":{
"service":"service",
"date":"date",
"time":"time",
"from":"from",
"to":"to"
},
"buttons":{
"searchConnection":"search connection"
}
}
}

View File

@ -1,5 +1,6 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import { createWebHistory, createRouter } from 'vue-router'
// Vuetify // Vuetify
@ -7,29 +8,30 @@ import 'vuetify/styles'
import { createVuetify } from 'vuetify' import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components' import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives' import * as directives from 'vuetify/directives'
//import '@fortawesome/fontawesome-free/css/all.css' // Ensure your project is capable of handling css files import SearchBahn from './components/search.vue'
//import { aliases, fa } from 'vuetify/iconsets/fa-svg' import { createI18n } from 'vue-i18n'
//import { library } from '@fortawesome/fontawesome-svg-core' import de from "./locales/de.json";
//import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import en from "./locales/en.json";
//import { fas } from '@fortawesome/free-solid-svg-icons'
//import { far } from '@fortawesome/free-regular-svg-icons'
const app = createApp(App) const app = createApp(App)
//app.component('font-awesome-icon', FontAwesomeIcon) // Register component globally const routes = [
//library.add(fas) // Include needed solid icons { path: '/search', component: SearchBahn },
//library.add(far) // Include needed regular icons ]
const router = createRouter({
history: createWebHistory(),
routes,
})
const vuetify = createVuetify({ const vuetify = createVuetify({
components, components,
directives, directives,
// icons: { })
// defaultSet: 'fa', const i18n = createI18n({
// aliases, locale: "en",
// sets: { fallbackLocale: "en",
// fa, messages: { de, en },
// },
// },
}) })
app.use(vuetify).mount('#app') app.use(vuetify).use(router).use(i18n).mount('#app')