Compare commits
339 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 621bb1ad55 | |||
| 154ae2ddac | |||
| d9da49a867 | |||
| 826d51f66c | |||
| 1d7fc2955f | |||
| c550e7598a | |||
| d5168ce59d | |||
| 380c97655c | |||
| e4ed24de80 | |||
| 8de03b9210 | |||
| 12ece46089 | |||
| 085238fada | |||
| 45c1d83512 | |||
| af9073ab98 | |||
| 800fc35e63 | |||
| d5649d221b | |||
| 5b35fac512 | |||
| d5bc90f668 | |||
| 6d663886f0 | |||
| 85a1a0216e | |||
| 4ac054e947 | |||
| ba70fa1316 | |||
| 77e6b20d0c | |||
| f60263c923 | |||
| 6aec1a75c9 | |||
| d28d600833 | |||
| a353eb3185 | |||
| c5735a6953 | |||
| 7930f7fc8a | |||
| 68f4d54619 | |||
| c4f9738589 | |||
| dd916afd1d | |||
| ea5c9e0028 | |||
| eb7c2d7132 | |||
| ee7c50f59b | |||
| 439f59fedc | |||
| c47d839ce3 | |||
| f77c13cbcf | |||
| dbbbd33100 | |||
| 14d13360a8 | |||
| dc862252ba | |||
| e5fe727ccd | |||
| e836bbed0c | |||
| d4438fd215 | |||
| 1550849360 | |||
| 9d1dc4ffca | |||
| 0397fa788d | |||
| 6e5696b0a6 | |||
| 4537341a57 | |||
| c35c74bd4a | |||
| 25735c5e6e | |||
| 41e60bc69e | |||
| 933bdecb3c | |||
| 10e183d96b | |||
| 5429d39f5e | |||
| ff31e7f903 | |||
| 91f4c6bc57 | |||
| c133eb060b | |||
| 7ffc169d8a | |||
| 1b85cc5f58 | |||
| 72ff857fff | |||
| 96d64e77fc | |||
| 6ceae3f161 | |||
| 8e8e27658c | |||
| 9b6ace394a | |||
| 6cfeaa91bf | |||
| 08b208aeaa | |||
| a089b5275b | |||
| 8425cd4371 | |||
| dbdc517b87 | |||
| e271358a27 | |||
| 66262e3fcd | |||
| 5b2b6bdea2 | |||
| c8587de6d9 | |||
| 1f376085f2 | |||
| f28600a7fa | |||
| d59ead87e6 | |||
| 34d91bc800 | |||
| cf9991d8a0 | |||
| 4ffb79d62b | |||
| d9f5edb4fe | |||
| 1b2112430a | |||
| 0a972a23ef | |||
| 6d52724d06 | |||
| 99415c35d3 | |||
| c3f687d439 | |||
| 266edfd6e6 | |||
| d32d5ad91b | |||
| c3481470cb | |||
| 57e88b9abc | |||
| 44ebf53798 | |||
| 145dc72b6b | |||
| b7f3761940 | |||
| ea7c49dfb3 | |||
| 5d6785813a | |||
| a0054aed14 | |||
| 471e6f5216 | |||
| a617eef00e | |||
| 38e700ecd6 | |||
| da1be0e10a | |||
| f49bb12948 | |||
| 02673a3d70 | |||
| 4ddc7345df | |||
| 5d822684c0 | |||
| 69fa15c70a | |||
| 9192067388 | |||
| 2b41e5b857 | |||
| 674680ff14 | |||
| 475bd2ff10 | |||
| 074d1eb155 | |||
| 378393de89 | |||
| 03e61083a7 | |||
| 0b746fce8c | |||
| 5883e710be | |||
| 3d0695a17b | |||
| 4adb76eeb0 | |||
| 4c41076519 | |||
| 77f61d17fd | |||
| 032a84cbcf | |||
| de9851ebcc | |||
| ff78eba927 | |||
| e4c5f6a322 | |||
| 0a78761928 | |||
| 4843043c29 | |||
| 9e1df1fb61 | |||
| 021474cfb0 | |||
| 7d0e68862c | |||
| 653d45dfc6 | |||
| 4a4e1240a4 | |||
| 14ca48a90d | |||
| a02f9804b1 | |||
| c5efc6fbac | |||
| cacd0a1e4e | |||
| 50375099ab | |||
| 6af67ec741 | |||
| c64112c86a | |||
| 0434702d3b | |||
| dd7d1b0bb0 | |||
| 68934a89a4 | |||
| b88a240ec1 | |||
| eaa34f3359 | |||
| febb22e1bc | |||
| 500f3c1223 | |||
| 221e0c7e82 | |||
| ca19f7e397 | |||
| a71ccd3e1a | |||
| d496c70fa8 | |||
| b9868ba52e | |||
| 59bd3fa2ef | |||
| e14d328ed9 | |||
| 36d71292bc | |||
| 2f6e2e7402 | |||
| e959eac6c5 | |||
| 8bedc4dfc6 | |||
| 73563d5db7 | |||
| 3f818069cd | |||
| cdf0b2a426 | |||
| c29ddeb78c | |||
| b81d98cab7 | |||
| 0e45bca5da | |||
| 715e66879f | |||
| 1747e15dc8 | |||
| 6a923a8e1d | |||
| 25a248e95e | |||
| aa7a6b220e | |||
| deb7b68985 | |||
| 633f05f690 | |||
| 73828867da | |||
| 75685c1e0e | |||
| 496ff95236 | |||
| 7e25327832 | |||
| 272c9f50f8 | |||
| 255e07372e | |||
| 279bbfa4db | |||
| a5c829faf5 | |||
| 5fdfaeac5e | |||
| 9beb30e3d5 | |||
| 48582e2eea | |||
| 2e721fb8bf | |||
| f93c1fbfec | |||
| c06e7b6468 | |||
| 22a6d266cb | |||
| 5f8a16401b | |||
| c9be01aa29 | |||
| 4ec058b33c | |||
| 27a5d2a406 | |||
| 58169e26f6 | |||
| fee1f4bbd5 | |||
| 240817acc3 | |||
| db3be87dd8 | |||
| 1665134d6f | |||
| df289ab734 | |||
| f74440ba6f | |||
| a25dbe9fd5 | |||
| 4fff136d6b | |||
| d06f2d5d2e | |||
| 9f68d628d0 | |||
| d64b906dac | |||
| f3e193e68a | |||
| 5640ce9f2b | |||
| 50100eb2f9 | |||
| e478c510b2 | |||
| 7ea558642f | |||
| 493145f7f2 | |||
| 4f72535365 | |||
| 8e3bf80715 | |||
| 6da586d08a | |||
| be53b9c7fb | |||
| 94ed1160a1 | |||
| 859d8d2631 | |||
| 5f3abd73c5 | |||
| d71c8bb6f9 | |||
| a3db13d79c | |||
| 8cb3da66f2 | |||
| 6e07897ac0 | |||
| 726b859f5c | |||
| 651c60707a | |||
| d4fee84603 | |||
| 86539cdf23 | |||
| 69772460b8 | |||
| 6988a83355 | |||
| b6425564c8 | |||
| caf0a9b4c5 | |||
| bd5f433d6e | |||
| 8d9cc721d6 | |||
| cceeffe49d | |||
| fcb8357489 | |||
| ceffd8e675 | |||
| 5aa53521f7 | |||
| d8b559694b | |||
| c82ac04a91 | |||
| 284bdcbf2a | |||
| 7f4df98349 | |||
| aecbcf62df | |||
| 2a817365a6 | |||
| ecf3a00cab | |||
| beb2f3c0d4 | |||
| a65b09981b | |||
| 4ec544e8a9 | |||
| 7e108c5183 | |||
| 72361b157e | |||
| 1cc4d76e4d | |||
| 846d4d0547 | |||
| 751cadd218 | |||
| 3b44adff44 | |||
| 29a02dd98f | |||
| c5e68c4d03 | |||
| 95f7c2a4d9 | |||
| 84412822ff | |||
| 42bb056e66 | |||
| 053e9d2b6a | |||
| c729d75541 | |||
| a9b72d0b7a | |||
| 95a027f284 | |||
| dbba83b28b | |||
| 65abe550f5 | |||
| 531108c25a | |||
| bcf750d451 | |||
| 0a8bfe4c52 | |||
| 0f19bc767a | |||
| 8eb0266874 | |||
| ae5b5ff965 | |||
| 3a0c4bc151 | |||
| 4f5fcb3189 | |||
| 3a2978bbe3 | |||
| a81cc4559b | |||
| 065143c359 | |||
| 1661881127 | |||
| 93aa889414 | |||
| 2a131ab1fb | |||
| 387f42985a | |||
| 6c83ce90bf | |||
| 3d519e874f | |||
| 99cdb3442a | |||
| a6c0fe86c8 | |||
| 828421efe0 | |||
| 21bacb1c95 | |||
| 0d9a3f4b4f | |||
| 76b8534d63 | |||
| 0821fd708e | |||
| b0a9939446 | |||
| 2a64b8f10d | |||
| dc1c457ea4 | |||
| 1f95bc5230 | |||
| 5a06920e5b | |||
| ee0d9e7ed4 | |||
| 30ad3ad4f2 | |||
| c2bd5a8a1b | |||
| 7101d0972d | |||
| 82bbfcdf70 | |||
| b90ac6c09e | |||
| 76d0ff88f1 | |||
| 951afcedeb | |||
| 96de3f0dcc | |||
| 03950eef66 | |||
| 6dd8cb2dad | |||
| aae51d4139 | |||
| 9994a541b1 | |||
| bc3a603ba2 | |||
| 7857377cab | |||
| 0034f43be4 | |||
| c09fc81886 | |||
| 30f72d518d | |||
| 9b86e07152 | |||
| 4e0fb5dc01 | |||
| a392991030 | |||
| ff7ca27fe6 | |||
| 94cd7aaa60 | |||
| 843289d8d7 | |||
| 66cae68e19 | |||
| b38e50396a | |||
| 7888e59117 | |||
| 46e700583d | |||
| fc56c38c45 | |||
| 9594e2c21a | |||
| a8bab5283b | |||
| 1cc799706c | |||
| 5ee8f72652 | |||
| 942f883b91 | |||
| 54b47d44e5 | |||
| f9aaf21f7a | |||
| d79705ca5c | |||
| 55c64d5f0a | |||
| 4ca1c7bb9c | |||
| abc8fda98e | |||
| aaec23d210 | |||
| 0af7b68138 | |||
| ae24eaf8e4 | |||
| f73a07daee | |||
| 89f5bf2e95 | |||
| 8137c1ff95 | |||
| 4b0d9b887e | |||
| 506064cf9a | |||
| 825e25434a | |||
| 32c601d50a | |||
| b88a96237e | |||
| 6c724440d7 | |||
| 71016e63bb | |||
| fb85352ce3 |
@@ -0,0 +1,18 @@
|
|||||||
|
/* eslint-env node */
|
||||||
|
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
extends: [
|
||||||
|
'plugin:vue/vue3-essential',
|
||||||
|
'eslint:recommended',
|
||||||
|
'@vue/eslint-config-typescript',
|
||||||
|
'@vue/eslint-config-prettier/skip-formatting'
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'vue/multi-word-component-names': 'off'
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# This file was auto-generated by the Firebase CLI
|
||||||
|
# https://github.com/firebase/firebase-tools
|
||||||
|
|
||||||
name: Deploy to Firebase Hosting on PR
|
name: Deploy to Firebase Hosting on PR
|
||||||
'on': pull_request
|
'on': pull_request
|
||||||
jobs:
|
jobs:
|
||||||
@@ -11,4 +14,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_STACJOWNIK_TD2 }}'
|
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_STACJOWNIK_TD2 }}'
|
||||||
projectId: stacjownik-td2
|
projectId: stacjownik-td2
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
|
/dev-dist
|
||||||
/dist
|
/dist
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
@@ -30,6 +31,7 @@ node_modules
|
|||||||
.firebase
|
.firebase
|
||||||
.firebaserc
|
.firebaserc
|
||||||
|
|
||||||
|
# Env
|
||||||
.env
|
.env
|
||||||
|
|
||||||
.fake
|
.fake
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/prettierrc",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 100,
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
presets: [
|
|
||||||
'@vue/cli-plugin-babel/preset'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
"hosting": {
|
"hosting": {
|
||||||
"public": "dist",
|
"public": "dist",
|
||||||
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
|
"ignore": [
|
||||||
|
"firebase.json",
|
||||||
|
"**/.*",
|
||||||
|
"**/node_modules/**"
|
||||||
|
],
|
||||||
"rewrites": [
|
"rewrites": [
|
||||||
{
|
{
|
||||||
"source": "**",
|
"source": "**",
|
||||||
@@ -10,4 +14,3 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pl">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
|
|
||||||
|
<meta name="keywords" content="Stacjownik, TD2, Train Driver 2, stacjownik-td2, stacjownik, td2.info.pl" />
|
||||||
|
<meta name="description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
||||||
|
|
||||||
|
<title>Stacjownik</title>
|
||||||
|
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||||
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||||
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
|
<meta name="theme-color" content="#222222" />
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon-64.png" sizes="64x64" type="image/png" />
|
||||||
|
<link rel="icon" href="favicon-62.png" sizes="62x62" type="image/png" />
|
||||||
|
<link rel="icon" href="favicon-32.png" sizes="32x32" type="image/png" />
|
||||||
|
<link rel="icon" href="favicon-16.png" sizes="16x16" type="image/png" />
|
||||||
|
<link rel="icon" href="favicon.ico" />
|
||||||
|
|
||||||
|
<!-- Static OpenGraph meta -->
|
||||||
|
<meta name="description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
||||||
|
<meta property="og:url" content="https://stacjownik-td2.web.app/" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="Stacjownik" />
|
||||||
|
<meta property="og:description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
||||||
|
<meta property="og:image" content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg" />
|
||||||
|
<meta property="og:image:width" content="1200" />
|
||||||
|
<meta property="og:image:height" content="630" />
|
||||||
|
<meta property="og:site_name" content="Stacjownik" />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content="Stacjownik" />
|
||||||
|
<meta name="twitter:description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
||||||
|
<meta name="twitter:image" content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg" />
|
||||||
|
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500;700&display=swap" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,37 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.9.9",
|
"version": "1.18.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"dev": "vite",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
"deploy-prod": "npm run build && firebase deploy --only hosting:prod",
|
"deploy": "yarn build && firebase deploy --only hosting",
|
||||||
"deploy-dev": "npm run build && firebase deploy --only hosting:dev"
|
"preview": "yarn build && vite preview",
|
||||||
|
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
|
||||||
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||||
|
"format": "prettier --write src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.12.1",
|
"core-js": "^3.32.2",
|
||||||
"dotenv": "^8.6.0",
|
"dotenv": "^16.3.1",
|
||||||
"firebase": "^9.8.1",
|
"firebase": "^10.4.0",
|
||||||
"howler": "^2.2.1",
|
"howler": "^2.2.4",
|
||||||
"pinia": "^2.0.14",
|
"pinia": "^2.1.6",
|
||||||
"socket.io-client": "^4.4.1",
|
"sass": "^1.67.0",
|
||||||
"vue": "^3.2.34",
|
"socket.io-client": "^4.7.2",
|
||||||
"vue-i18n": "^9.1.6",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.0.0-0",
|
"vue-i18n": "^9.4.1",
|
||||||
"vuex": "^4.0.2"
|
"vue-router": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^17.0.35",
|
"@types/node": "^20.6.2",
|
||||||
"@vue/cli-plugin-babel": "^5.0.4",
|
"@vite-pwa/assets-generator": "^0.0.10",
|
||||||
"@vue/cli-plugin-router": "^5.0.4",
|
"@vitejs/plugin-vue": "^4.3.4",
|
||||||
"@vue/cli-plugin-typescript": "^5.0.4",
|
"axios": "^1.5.0",
|
||||||
"@vue/cli-plugin-vuex": "^5.0.4",
|
"prettier": "^3.0.3",
|
||||||
"@vue/cli-service": "^5.0.4",
|
"typescript": "^5.2.2",
|
||||||
"@vue/compiler-sfc": "^3.1.0",
|
"vite": "^4.4.9",
|
||||||
"axios": "^0.21.1",
|
"vite-plugin-pwa": "^0.16.5",
|
||||||
"sass": "^1.32.13",
|
"vue-tsc": "^1.8.11",
|
||||||
"sass-loader": "^8.0.2",
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
"typescript": "^4.7.3"
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
|
"@vue/tsconfig": "^0.4.0",
|
||||||
|
"eslint": "^8.49.0",
|
||||||
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
|
"@rushstack/eslint-patch": "^1.3.3"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
|||||||
|
After Width: | Height: | Size: 951 B |
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
|
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
|
Before Width: | Height: | Size: 482 B After Width: | Height: | Size: 482 B |
|
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
|
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 170 B After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 932 B |
|
After Width: | Height: | Size: 953 B |
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 582 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 256 B After Width: | Height: | Size: 256 B |
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
@@ -0,0 +1,20 @@
|
|||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect y="-0.00012207" width="60" height="60" fill="#898989"/>
|
||||||
|
<path d="M29.0126 32.4897V10.2511V9.52028H30.4337V10.2511V57.234H29.0126V32.4897Z" fill="#BFBFBF"/>
|
||||||
|
<path d="M26.955 29.3992V32.9949L29.7672 36.9105" stroke="black" stroke-width="0.61183"/>
|
||||||
|
<rect x="29.0051" y="34.0686" width="1.42857" height="22.8196" fill="white"/>
|
||||||
|
<rect x="29.0051" y="34.0686" width="1.42857" height="5.18627" fill="#FF0000"/>
|
||||||
|
<rect x="29.0051" y="54.8137" width="1.42857" height="5.18627" fill="#FF0000"/>
|
||||||
|
<rect x="29.0051" y="44.4412" width="1.42857" height="5.18627" fill="#FF0000"/>
|
||||||
|
<rect x="27.8749" y="31.8649" width="3.75" height="2.17823" fill="white"/>
|
||||||
|
<path d="M33.5 28.5111V8.61545V8.11176H26V28.5111H33.5Z" fill="black"/>
|
||||||
|
<path d="M29.6364 5.00276C27.1289 5.09112 26.2239 7.044 26 8.11176H33.5C33.3134 6.97036 32.1438 4.91439 29.6364 5.00276Z" fill="black"/>
|
||||||
|
<path d="M29.8636 31.6201C32.3711 31.5317 33.2761 29.5789 33.5 28.5111H26C26.1865 29.6525 27.3561 31.7085 29.8636 31.6201Z" fill="black"/>
|
||||||
|
<ellipse cx="29.887" cy="11.8168" rx="1.38696" ry="1.28474" fill="#212121"/>
|
||||||
|
<ellipse cx="29.887" cy="8.0135" rx="1.38696" ry="1.28474" fill="#212121"/>
|
||||||
|
<ellipse cx="29.887" cy="15.6151" rx="1.38696" ry="1.28474" fill="#212121"/>
|
||||||
|
<ellipse cx="29.887" cy="19.6834" rx="1.38696" ry="1.28474" fill="#212121"/>
|
||||||
|
<ellipse cx="29.887" cy="23.7518" rx="1.38696" ry="1.28474" fill="#212121"/>
|
||||||
|
<ellipse cx="29.887" cy="27.8201" rx="1.38696" ry="1.28474" fill="#00FF0A"/>
|
||||||
|
<ellipse cx="29.887" cy="19.769" rx="1.38696" ry="1.28474" fill="#00FF0A"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 632 B |
|
Before Width: | Height: | Size: 398 B After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 938 B After Width: | Height: | Size: 938 B |
|
Before Width: | Height: | Size: 356 B After Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1020 B |
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 369 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 252 B |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 199 B |
|
Before Width: | Height: | Size: 384 B After Width: | Height: | Size: 384 B |
|
After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
@@ -0,0 +1,18 @@
|
|||||||
|
<svg width="144" height="147" viewBox="0 0 144 147" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_1343_19)">
|
||||||
|
<path d="M115.039 101.247C116.397 98.6665 115.405 95.4739 112.824 94.1167C110.243 92.7594 107.05 93.7514 105.693 96.3323L115.039 101.247ZM89.4447 44.0402L94.1179 46.4977L99.0329 37.1513L94.3597 34.6938L89.4447 44.0402ZM105.693 96.3323C95.7398 115.259 72.3278 122.534 53.4008 112.581L48.4858 121.927C72.5746 134.595 102.372 125.336 115.039 101.247L105.693 96.3323ZM53.4008 112.581C34.4739 102.627 27.1993 79.2155 37.1525 60.2885L27.8061 55.3735C15.1383 79.4623 24.397 109.259 48.4858 121.927L53.4008 112.581ZM37.1525 60.2885C47.1057 41.3616 70.5177 34.087 89.4447 44.0402L94.3597 34.6938C70.2709 22.026 40.4738 31.2846 27.8061 55.3735L37.1525 60.2885Z" fill="white"/>
|
||||||
|
<path d="M91.2258 38.7627L101.056 20.0698L116.15 51.8695L81.3956 57.4555L91.2258 38.7627Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_1343_19" x="18.1328" y="20.0698" width="102.017" height="115.531" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="4"/>
|
||||||
|
<feGaussianBlur stdDeviation="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1343_19"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1343_19" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 476 B After Width: | Height: | Size: 476 B |
|
Before Width: | Height: | Size: 863 B After Width: | Height: | Size: 863 B |
|
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" ?><svg enable-background="new 0 0 32 32" id="Glyph" version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M27.414,24.586l-5.077-5.077C23.386,17.928,24,16.035,24,14c0-5.514-4.486-10-10-10S4,8.486,4,14 s4.486,10,10,10c2.035,0,3.928-0.614,5.509-1.663l5.077,5.077c0.78,0.781,2.048,0.781,2.828,0 C28.195,26.633,28.195,25.367,27.414,24.586z M7,14c0-3.86,3.14-7,7-7s7,3.14,7,7s-3.14,7-7,7S7,17.86,7,14z" id="XMLID_223_" fill="white" /></svg>
|
||||||
|
After Width: | Height: | Size: 546 B |
|
Before Width: | Height: | Size: 230 B After Width: | Height: | Size: 230 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 199 B |
|
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 268 B |
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 478 B After Width: | Height: | Size: 478 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23.75 3.75H22.5V1.25H20V3.75H10V1.25H7.5V3.75H6.25C4.875 3.75 3.75 4.875 3.75 6.25V23.75C3.75 25.125 4.875 26.25 6.25 26.25H23.75C25.125 26.25 26.25 25.125 26.25 23.75V6.25C26.25 4.875 25.125 3.75 23.75 3.75ZM23.75 23.75H6.25V11.25H23.75V23.75ZM6.25 8.75V6.25H23.75V8.75H6.25ZM8.75 13.75H21.25V16.25H8.75V13.75ZM8.75 18.75H17.5V21.25H8.75V18.75Z" fill="#F2E147"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 477 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23.75 3.75H22.5V1.25H20V3.75H10V1.25H7.5V3.75H6.25C4.875 3.75 3.75 4.875 3.75 6.25V23.75C3.75 25.125 4.875 26.25 6.25 26.25H23.75C25.125 26.25 26.25 25.125 26.25 23.75V6.25C26.25 4.875 25.125 3.75 23.75 3.75ZM23.75 23.75H6.25V11.25H23.75V23.75ZM6.25 8.75V6.25H23.75V8.75H6.25ZM8.75 13.75H21.25V16.25H8.75V13.75ZM8.75 18.75H17.5V21.25H8.75V18.75Z" fill="#66FF6C"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 477 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23.75 3.75H22.5V1.25H20V3.75H10V1.25H7.5V3.75H6.25C4.875 3.75 3.75 4.875 3.75 6.25V23.75C3.75 25.125 4.875 26.25 6.25 26.25H23.75C25.125 26.25 26.25 25.125 26.25 23.75V6.25C26.25 4.875 25.125 3.75 23.75 3.75ZM23.75 23.75H6.25V11.25H23.75V23.75ZM6.25 8.75V6.25H23.75V8.75H6.25ZM8.75 13.75H21.25V16.25H8.75V13.75ZM8.75 18.75H17.5V21.25H8.75V18.75Z" fill="#898989"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 477 B |
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 285 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -1,54 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="pl">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
|
||||||
|
|
||||||
<meta name="keywords" content="Stacjownik, TD2, Train Driver 2, stacjownik-td2" />
|
|
||||||
<meta name="description" content="Automatycznie odświeżana strona wyświetlająca stacje w Train Driver 2!" />
|
|
||||||
|
|
||||||
<title>Stacjownik</title>
|
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
|
||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
|
||||||
<meta name="msapplication-TileColor" content="#da532c" />
|
|
||||||
<meta name="theme-color" content="#ffffff" />
|
|
||||||
|
|
||||||
<link rel="icon" href="favicon-64.png" sizes="64x64" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon-32.png" sizes="32x32" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon-62.png" sizes="62x62" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon-16.png" sizes="16x16" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon.ico" />
|
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;700&display=swap" rel="stylesheet" />
|
|
||||||
|
|
||||||
<script src="https://www.gstatic.com/firebasejs/8.1.1/firebase-app.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const firebaseConfig = {
|
|
||||||
apiKey: 'AIzaSyBI36X2-p7vU1flxoJdCEc0noByyTe1mpw',
|
|
||||||
authDomain: 'stacjownik-td2.firebaseapp.com',
|
|
||||||
databaseURL: 'https://stacjownik-td2.firebaseio.com',
|
|
||||||
projectId: 'stacjownik-td2',
|
|
||||||
storageBucket: 'stacjownik-td2.appspot.com',
|
|
||||||
};
|
|
||||||
|
|
||||||
firebase.initializeApp(firebaseConfig);
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<noscript>
|
|
||||||
<strong
|
|
||||||
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please
|
|
||||||
enable it to continue.</strong
|
|
||||||
>
|
|
||||||
</noscript>
|
|
||||||
<div id="app"></div>
|
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "",
|
"name": "Stacjownik TD2",
|
||||||
"short_name": "",
|
"short_name": "Stacjownik",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/android-chrome-192x192.png",
|
"src": "/android-chrome-192x192.png",
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"theme_color": "#ffffff",
|
"theme_color": "#ffc014",
|
||||||
"background_color": "#ffffff",
|
"background_color": "#4d4d4d",
|
||||||
"display": "standalone"
|
"display": "standalone",
|
||||||
|
"start_url": "."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,240 +1,106 @@
|
|||||||
@import './styles/responsive.scss';
|
@import './styles/responsive.scss';
|
||||||
@import './styles/variables.scss';
|
@import './styles/variables.scss';
|
||||||
@import './styles/global.scss';
|
@import './styles/global.scss';
|
||||||
@import './styles/scenery_status.scss';
|
|
||||||
|
// VUE ROUTE CHANGE ANIMATION
|
||||||
// VUE ROUTE CHANGE ANIMATION
|
.view-anim {
|
||||||
.view-anim {
|
&-enter-from,
|
||||||
&-enter-from,
|
&-leave-to {
|
||||||
&-leave-to {
|
opacity: 0.02;
|
||||||
opacity: 0.02;
|
}
|
||||||
}
|
|
||||||
|
&-enter-active,
|
||||||
&-enter-active,
|
&-leave-active {
|
||||||
&-leave-active {
|
transition: all $animDuration $animType;
|
||||||
transition: all $animDuration $animType;
|
min-height: 100%;
|
||||||
min-height: 100%;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.modal-anim {
|
||||||
.route {
|
&-enter-active,
|
||||||
margin: 0 0.2em;
|
&-leave-active {
|
||||||
|
transition: all $animDuration $animType;
|
||||||
&-active {
|
}
|
||||||
color: $accentCol;
|
|
||||||
font-weight: bold;
|
&-enter-from,
|
||||||
}
|
&-leave-to {
|
||||||
}
|
transform: translateY(-25%);
|
||||||
|
opacity: 0;
|
||||||
// APP
|
}
|
||||||
.app {
|
}
|
||||||
color: white;
|
|
||||||
font-size: 1rem;
|
.route {
|
||||||
|
margin: 0 0.2em;
|
||||||
@include smallScreen() {
|
|
||||||
font-size: calc(0.4rem + 1.4vw);
|
&-active,
|
||||||
}
|
&[data-active='true'] {
|
||||||
}
|
color: $accentCol;
|
||||||
|
font-weight: bold;
|
||||||
// CONTAINER
|
}
|
||||||
.app_container {
|
}
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
// APP
|
||||||
height: 100vh;
|
#app {
|
||||||
min-height: 800px;
|
color: white;
|
||||||
|
font-size: 1rem;
|
||||||
header {
|
overflow-x: hidden;
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
@include smallScreen() {
|
||||||
|
font-size: calc(0.65rem + 0.8vw);
|
||||||
main {
|
}
|
||||||
flex: 1 1 auto;
|
|
||||||
|
@include screenLandscape() {
|
||||||
padding: 0 0.5em;
|
font-size: calc(0.45rem + 0.8vw);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
footer {
|
|
||||||
flex: 0 1 0.2em;
|
// CONTAINER
|
||||||
}
|
.app_container {
|
||||||
}
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
.warning {
|
|
||||||
background-color: firebrick;
|
min-height: 100vh;
|
||||||
text-align: center;
|
|
||||||
padding: 0.5em 0.4em;
|
header {
|
||||||
max-width: 1100px;
|
flex: 0 0 auto;
|
||||||
margin: 0 auto;
|
}
|
||||||
|
|
||||||
border-radius: 0 0 1em 1em;
|
main {
|
||||||
}
|
flex: 1 1 auto;
|
||||||
|
|
||||||
// Error icon
|
padding: 0 0.5em;
|
||||||
.wip-alert {
|
}
|
||||||
padding: 0 0.5em;
|
|
||||||
text-align: center;
|
footer {
|
||||||
}
|
flex: 0 1 0.2em;
|
||||||
|
}
|
||||||
.icon-error {
|
}
|
||||||
width: 13em;
|
|
||||||
margin: 0.5em 0;
|
.warning {
|
||||||
}
|
background-color: firebrick;
|
||||||
|
text-align: center;
|
||||||
// HEADER
|
padding: 0.5em 0.4em;
|
||||||
.app_header {
|
max-width: 1100px;
|
||||||
display: flex;
|
margin: 0 auto;
|
||||||
justify-content: center;
|
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
position: relative;
|
}
|
||||||
background-color: $primaryCol;
|
|
||||||
}
|
// FOOTER
|
||||||
|
footer.app_footer {
|
||||||
.header {
|
max-width: 100%;
|
||||||
&_body {
|
padding: 0.5em;
|
||||||
max-width: 21em;
|
|
||||||
}
|
img {
|
||||||
|
width: 1.1em;
|
||||||
&_container {
|
vertical-align: text-bottom;
|
||||||
display: flex;
|
}
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
z-index: 10;
|
||||||
|
|
||||||
width: 1350px;
|
background: #111;
|
||||||
padding: 0.5em 0.3em 0 0.3em;
|
color: white;
|
||||||
border-radius: 0 0 1em 1em;
|
|
||||||
}
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
&_brand {
|
}
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_info {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
|
||||||
max-width: 100%;
|
|
||||||
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_links {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
border-radius: 0.7em;
|
|
||||||
|
|
||||||
font-size: 1.25em;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_icons {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: flex-end;
|
|
||||||
padding: 0.5em 0.5em;
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
right: auto;
|
|
||||||
left: 0.75em;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ICONS
|
|
||||||
.icons {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&-top {
|
|
||||||
img {
|
|
||||||
width: 2.5em;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-bottom {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
a {
|
|
||||||
margin-left: 0.6em;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 1.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
a {
|
|
||||||
margin: 0.25em 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// COUNTER
|
|
||||||
.info_counter {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin: 0 0.15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 1.35em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// REGION SELECTION
|
|
||||||
.info_region {
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
.select-box_content button {
|
|
||||||
background-color: transparent;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0.1em 0.5em;
|
|
||||||
color: paleturquoise;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FOOTER
|
|
||||||
footer.app_footer {
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
background: #111;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,227 +1,162 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="app_container">
|
||||||
<div class="app_container">
|
<transition name="modal-anim">
|
||||||
<!-- <div class="wip-alert">
|
<keep-alive>
|
||||||
<img class="icon-error" :src="iconError" alt="error" />
|
<TrainModal v-if="store.chosenModalTrainId" />
|
||||||
<h2>Stacjownik tymczasowo nieaktywny!</h2>
|
</keep-alive>
|
||||||
<p>Absolutny zakaz wjazdu!</p>
|
</transition>
|
||||||
</div> -->
|
|
||||||
<header class="app_header">
|
<AppHeader :current-lang="currentLang" @change-lang="changeLang" />
|
||||||
<div class="header_container">
|
|
||||||
<div class="header_icons">
|
<main class="app_main">
|
||||||
<span class="icons-top">
|
<router-view v-slot="{ Component }">
|
||||||
<img :src="icons.pl" alt="icon-pl" @click="changeLang('en')" v-if="currentLang == 'pl'" />
|
<keep-alive exclude="JournalView">
|
||||||
<img :src="icons.en" alt="icon-en" @click="changeLang('pl')" v-else />
|
<component :is="Component" :key="$route.name" />
|
||||||
</span>
|
</keep-alive>
|
||||||
<span class="icons-bottom">
|
</router-view>
|
||||||
<a href="https://www.paypal.com/paypalme/spythere" target="_blank">
|
</main>
|
||||||
<img :src="icons.dollar" alt="icon paypal" />
|
|
||||||
</a>
|
<footer class="app_footer">
|
||||||
|
©
|
||||||
<a href="https://discord.gg/x2mpNN3svk" target="_blank">
|
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||||
<img :src="icons.discord" alt="icon discord" />
|
{{ new Date().getUTCFullYear() }} |
|
||||||
</a>
|
<a :href="releaseURL" target="_blank">v{{ VERSION }}{{ isOnProductionHost ? '' : 'dev' }}</a>
|
||||||
</span>
|
<br />
|
||||||
</div>
|
<a href="https://discord.gg/x2mpNN3svk">
|
||||||
|
<img src="/images/icon-discord.png" alt="" /> <b>{{ $t('footer.discord') }}</b>
|
||||||
<div class="header_body">
|
</a>
|
||||||
<status-indicator />
|
|
||||||
<span class="header_brand">
|
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
||||||
<img :src="brand_logo" alt="Stacjownik" />
|
</footer>
|
||||||
</span>
|
</div>
|
||||||
|
</template>
|
||||||
<span class="header_info">
|
|
||||||
<Clock />
|
<script lang="ts">
|
||||||
|
import { defineComponent, watch } from 'vue';
|
||||||
<div class="info_counter">
|
|
||||||
<img src="@/assets/icon-dispatcher.svg" alt="icon dispatcher" />
|
import Clock from './components/App/Clock.vue';
|
||||||
<span class="text--primary">{{ onlineDispatchers.length }}</span>
|
|
||||||
<span class="text--grayed"> / </span>
|
import packageInfo from '.././package.json';
|
||||||
<span class="text--primary">{{ trainList.length }}</span>
|
import { regions } from './data/options.json';
|
||||||
<img src="@/assets/icon-train.svg" alt="icon train" />
|
|
||||||
</div>
|
import { useStore } from './store/store';
|
||||||
|
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||||
<span class="info_region">
|
import TrainModal from './components/Global/TrainModal.vue';
|
||||||
<SelectBox :itemList="computedRegions" :defaultItemIndex="0" @selected="changeRegion" />
|
import StorageManager from './scripts/managers/storageManager';
|
||||||
</span>
|
import AppHeader from './components/App/AppHeader.vue';
|
||||||
</span>
|
import axios from 'axios';
|
||||||
|
|
||||||
<span class="header_links">
|
export default defineComponent({
|
||||||
<router-link class="route" active-class="route-active" to="/" exact>
|
components: {
|
||||||
{{ $t('app.sceneries') }}
|
Clock,
|
||||||
</router-link>
|
StatusIndicator,
|
||||||
/
|
TrainModal,
|
||||||
<router-link class="route" active-class="route-active" to="/trains">{{ $t('app.trains') }}</router-link>
|
AppHeader
|
||||||
/
|
},
|
||||||
<router-link class="route" active-class="route-active" to="/journal">
|
|
||||||
{{ $t('app.journal') }}
|
data: () => ({
|
||||||
</router-link>
|
VERSION: packageInfo.version,
|
||||||
</span>
|
store: useStore(),
|
||||||
</div>
|
|
||||||
</div>
|
currentLang: 'pl',
|
||||||
</header>
|
releaseURL: '',
|
||||||
|
isOnProductionHost: location.hostname == 'stacjownik-td2.web.app'
|
||||||
<main class="app_main">
|
}),
|
||||||
<router-view v-slot="{ Component }">
|
|
||||||
<!-- <transition name="view-anim" mode="out-in"> -->
|
created() {
|
||||||
<keep-alive>
|
this.loadLang();
|
||||||
<component :is="Component" :key="$route.path" />
|
this.store.connectToAPI();
|
||||||
</keep-alive>
|
|
||||||
</router-view>
|
this.store.isOffline = !window.navigator.onLine;
|
||||||
</main>
|
|
||||||
|
window.addEventListener('offline', () => {
|
||||||
<footer class="app_footer">
|
this.store.isOffline = true;
|
||||||
©
|
|
||||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
this.store.apiData = {
|
||||||
{{ new Date().getUTCFullYear() }} | v{{ VERSION }}
|
stations: [],
|
||||||
|
dispatchers: [],
|
||||||
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
trains: [],
|
||||||
</footer>
|
connectedSocketCount: 0
|
||||||
</div>
|
};
|
||||||
</div>
|
|
||||||
</template>
|
this.store.setStatuses();
|
||||||
|
});
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, provide, ref } from 'vue';
|
window.addEventListener('online', () => {
|
||||||
|
this.store.isOffline = false;
|
||||||
import Clock from '@/components/App/Clock.vue';
|
});
|
||||||
import StorageManager from '@/scripts/managers/storageManager';
|
},
|
||||||
|
|
||||||
import packageInfo from '.././package.json';
|
async mounted() {
|
||||||
import options from '@/data/options.json';
|
this.setReleaseURL();
|
||||||
|
|
||||||
import StatusIndicator from '@/components/App/StatusIndicator.vue';
|
watch(
|
||||||
import SelectBox from '@/components/Global/SelectBox.vue';
|
() => this.store.blockScroll,
|
||||||
import { useStore } from './store/store';
|
(value) => {
|
||||||
|
if (value) document.body.classList.add('no-scroll');
|
||||||
export default defineComponent({
|
else document.body.classList.remove('no-scroll');
|
||||||
components: {
|
}
|
||||||
Clock,
|
);
|
||||||
StatusIndicator,
|
},
|
||||||
SelectBox,
|
|
||||||
},
|
watch: {
|
||||||
|
'$route.query.region': {
|
||||||
setup() {
|
immediate: true,
|
||||||
const store = useStore();
|
handler(regionQuery: string) {
|
||||||
store.connectToAPI();
|
if (regionQuery) {
|
||||||
|
this.store.region.id =
|
||||||
const isFilterCardVisible = ref(false);
|
regions.find(
|
||||||
|
(reg) =>
|
||||||
provide('isFilterCardVisible', isFilterCardVisible);
|
reg.id == regionQuery.toLocaleLowerCase() ||
|
||||||
|
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
|
||||||
return {
|
)?.id || 'eu';
|
||||||
store,
|
}
|
||||||
isFilterCardVisible,
|
}
|
||||||
onlineDispatchers: computed(() =>
|
}
|
||||||
store.stationList.filter((station) => station.onlineInfo && station.onlineInfo.region == store.region.id)
|
},
|
||||||
),
|
|
||||||
|
methods: {
|
||||||
dispatcherDataStatus: store.dataStatuses.dispatchers,
|
changeLang(lang: string) {
|
||||||
};
|
this.$i18n.locale = lang;
|
||||||
},
|
this.currentLang = lang;
|
||||||
|
|
||||||
computed: {
|
StorageManager.setStringValue('lang', lang);
|
||||||
trainList() {
|
},
|
||||||
return this.store.trainList.filter((train) => train.online);
|
|
||||||
},
|
async setReleaseURL() {
|
||||||
|
try {
|
||||||
computedRegions() {
|
const releaseData = await (
|
||||||
return this.options.regions.map((region) => {
|
await axios.get('https://api.github.com/repos/Spythere/stacjownik/releases/latest')
|
||||||
const regionStationCount =
|
).data;
|
||||||
this.store.apiData.stations?.filter((station) => station.region == region.id && station.isOnline).length || 0;
|
|
||||||
const regionTrainCount = this.store.apiData.trains?.filter((train) => train.region == region.id && train.online).length || 0;
|
if (!releaseData) return;
|
||||||
|
|
||||||
return {
|
this.releaseURL = releaseData.html_url;
|
||||||
id: region.id,
|
} catch (error) {
|
||||||
value: `${region.value} <div class='text--grayed'>${regionStationCount} / ${regionTrainCount}</div>`,
|
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
||||||
selectedValue: region.value,
|
return;
|
||||||
};
|
}
|
||||||
});
|
},
|
||||||
},
|
|
||||||
},
|
loadLang() {
|
||||||
|
const storageLang = StorageManager.getStringValue('lang');
|
||||||
data: () => ({
|
|
||||||
VERSION: packageInfo.version,
|
if (storageLang) {
|
||||||
updateModalVisible: false,
|
this.changeLang(storageLang);
|
||||||
hasReleaseNotes: false,
|
return;
|
||||||
options,
|
}
|
||||||
|
|
||||||
currentLang: 'pl',
|
if (!window.navigator.language) return;
|
||||||
|
|
||||||
brand_logo: require('@/assets/stacjownik-header-logo.svg'),
|
const naviLanguage = window.navigator.language.toString();
|
||||||
|
|
||||||
icons: {
|
if (naviLanguage.includes('en')) {
|
||||||
en: require('@/assets/icon-en.jpg'),
|
this.changeLang('en');
|
||||||
pl: require('@/assets/icon-pl.svg'),
|
return;
|
||||||
error: require('@/assets/icon-error.svg'),
|
}
|
||||||
dollar: require('@/assets/icon-dollar.svg'),
|
}
|
||||||
dispatcher: require('@/assets/icon-dispatcher.svg'),
|
}
|
||||||
train: require('@/assets/icon-train.svg'),
|
});
|
||||||
discord: require('@/assets/icon-discord.png'),
|
</script>
|
||||||
},
|
|
||||||
}),
|
<style lang="scss" src="./App.scss"></style>
|
||||||
|
|
||||||
created() {
|
|
||||||
this.loadLang();
|
|
||||||
},
|
|
||||||
|
|
||||||
async mounted() {
|
|
||||||
if (StorageManager.getStringValue('version') != this.VERSION) {
|
|
||||||
StorageManager.setStringValue('version', this.VERSION);
|
|
||||||
|
|
||||||
if (this.hasReleaseNotes) StorageManager.setBooleanValue('version_notes_read', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateModalVisible = this.hasReleaseNotes && !StorageManager.getBooleanValue('version_notes_read');
|
|
||||||
|
|
||||||
this.updateToNewestVersion();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
toggleUpdateModal() {
|
|
||||||
this.updateModalVisible = !this.updateModalVisible;
|
|
||||||
StorageManager.setBooleanValue('version_notes_read', true);
|
|
||||||
},
|
|
||||||
|
|
||||||
changeRegion(region: { id: string; value: string }) {
|
|
||||||
this.store.changeRegion(region);
|
|
||||||
},
|
|
||||||
|
|
||||||
changeLang(lang: string) {
|
|
||||||
this.$i18n.locale = lang;
|
|
||||||
this.currentLang = lang;
|
|
||||||
|
|
||||||
StorageManager.setStringValue('lang', lang);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateToNewestVersion() {
|
|
||||||
if (!StorageManager.isRegistered('unavailable-status')) {
|
|
||||||
StorageManager.setBooleanValue('unavailable-status', true);
|
|
||||||
StorageManager.setBooleanValue('ending-status', true);
|
|
||||||
StorageManager.setBooleanValue('no-space-status', true);
|
|
||||||
StorageManager.setBooleanValue('afk-status', true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
loadLang() {
|
|
||||||
const storageLang = StorageManager.getStringValue('lang');
|
|
||||||
|
|
||||||
if (storageLang) {
|
|
||||||
this.changeLang(storageLang);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!window.navigator.language) return;
|
|
||||||
|
|
||||||
const naviLanguage = window.navigator.language.toString();
|
|
||||||
|
|
||||||
if (naviLanguage.includes('en')) {
|
|
||||||
this.changeLang('en');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" src="./App.scss"></style>
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect width="60" height="60" fill="#898989"/>
|
|
||||||
<path d="M30.5 6.04878H35.2195" stroke="#BFBFBF"/>
|
|
||||||
<path d="M27.9024 4.00303C25.2115 4.10008 24.2403 6.24494 24 7.41767H32.0488C31.8486 6.16406 30.5934 3.90598 27.9024 4.00303Z" fill="black"/>
|
|
||||||
<path d="M33.0244 29.6688V5.47793V4.68292H34.4878V5.47793V56.5854H33.0244V32.5H27.5V28.5V28.0163L28.5 28V31.5L31.9268 31.5447H33.0244V29.6688Z" fill="#BFBFBF"/>
|
|
||||||
<path d="M28.1463 29.2683C30.8373 29.1712 31.8085 27.0264 32.0488 25.8537H24C24.2002 27.1073 25.4554 29.3654 28.1463 29.2683Z" fill="black"/>
|
|
||||||
<path d="M32.0488 25.8537V7.86993V7.41464H24V25.8537H32.0488Z" fill="black"/>
|
|
||||||
<path d="M25 26V29.5L33.8781 44.9756" stroke="black"/>
|
|
||||||
<rect x="33.0244" y="31.5447" width="1.46341" height="25.0407" fill="white"/>
|
|
||||||
<rect x="33.0244" y="31.5447" width="1.46341" height="5.69106" fill="#FF0000"/>
|
|
||||||
<rect x="33.0244" y="42.9268" width="1.46341" height="5.69106" fill="#FF0000"/>
|
|
||||||
<rect x="33.0244" y="54.3089" width="1.46341" height="5.69106" fill="#FF0000"/>
|
|
||||||
<ellipse cx="27.9024" cy="7.40022" rx="1.46341" ry="1.40022" fill="#212121"/>
|
|
||||||
<ellipse cx="27.9024" cy="11.8343" rx="1.46341" ry="1.40022" fill="#212121"/>
|
|
||||||
<ellipse cx="27.9024" cy="16.2683" rx="1.46341" ry="1.40022" fill="#FF0000"/>
|
|
||||||
<ellipse cx="27.9024" cy="20.7023" rx="1.46341" ry="1.40022" fill="#212121"/>
|
|
||||||
<ellipse cx="27.9024" cy="25.1364" rx="1.46341" ry="1.40022" fill="#212121"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,212 @@
|
|||||||
|
<template>
|
||||||
|
<header class="app_header">
|
||||||
|
<div class="header_container">
|
||||||
|
<div class="header_icons">
|
||||||
|
<span class="icons-top">
|
||||||
|
<img
|
||||||
|
src="/images/icon-pl.svg"
|
||||||
|
alt="icon-pl"
|
||||||
|
@click="changeLang('en')"
|
||||||
|
v-if="currentLang == 'pl'"
|
||||||
|
/>
|
||||||
|
<img src="/images/icon-en.jpg" alt="icon-en" @click="changeLang('pl')" v-else />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="header_body">
|
||||||
|
<StatusIndicator />
|
||||||
|
|
||||||
|
<span class="header_brand">
|
||||||
|
<router-link to="/">
|
||||||
|
<img src="/images/stacjownik-header-logo.svg" alt="Stacjownik" />
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="header_info">
|
||||||
|
<Clock />
|
||||||
|
|
||||||
|
<div class="info_counter">
|
||||||
|
<img src="/images/icon-dispatcher.svg" alt="icon dispatcher" />
|
||||||
|
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
||||||
|
|
||||||
|
<!-- <span class="g-tooltip">
|
||||||
|
<b class="text--primary">{{ factorU }}U</b>
|
||||||
|
<div class="content">Test</div>
|
||||||
|
</span> -->
|
||||||
|
|
||||||
|
<span class="text--grayed"> / </span>
|
||||||
|
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
||||||
|
<img src="/images/icon-train.svg" alt="icon train" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info_region">
|
||||||
|
<RegionDropdown />
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="header_links">
|
||||||
|
<router-link class="route" active-class="route-active" to="/" exact>
|
||||||
|
{{ $t('app.sceneries') }}
|
||||||
|
</router-link>
|
||||||
|
/
|
||||||
|
<router-link class="route" active-class="route-active" to="/trains">{{
|
||||||
|
$t('app.trains')
|
||||||
|
}}</router-link>
|
||||||
|
/
|
||||||
|
<router-link
|
||||||
|
class="route"
|
||||||
|
active-class="route-active"
|
||||||
|
:data-active="$route.path.startsWith('/journal')"
|
||||||
|
to="/journal"
|
||||||
|
>
|
||||||
|
{{ $t('app.journal') }}
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import StatusIndicator from './StatusIndicator.vue';
|
||||||
|
import Clock from './Clock.vue';
|
||||||
|
import RegionDropdown from '../Global/RegionDropdown.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['changeLang'],
|
||||||
|
props: {
|
||||||
|
currentLang: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
store: useStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
changeLang(lang: string) {
|
||||||
|
this.$emit('changeLang', lang);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
onlineTrainsCount() {
|
||||||
|
return this.store.trainList.filter((train) => train.online).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
onlineDispatchersCount() {
|
||||||
|
return this.store.onlineSceneryList.length;
|
||||||
|
},
|
||||||
|
|
||||||
|
factorU() {
|
||||||
|
return this.onlineDispatchersCount == 0
|
||||||
|
? '-'
|
||||||
|
: (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: { StatusIndicator, Clock, RegionDropdown }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/variables.scss';
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
|
// HEADER
|
||||||
|
.app_header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
background-color: $primaryCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
&_body {
|
||||||
|
position: relative;
|
||||||
|
max-width: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_brand {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_info {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
font-size: 1.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
border-radius: 0.7em;
|
||||||
|
|
||||||
|
font-size: 1.25em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
transform: translateX(85%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICONS
|
||||||
|
.icons-top {
|
||||||
|
img {
|
||||||
|
width: 2.5em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// COUNTER
|
||||||
|
.info_counter {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: 0 0.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1.35em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info_region {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,36 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="clock">{{ computedDate }}</div>
|
<div class="clock">{{ computedDate }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
<script lang="ts">
|
import { computed, defineComponent, ref } from 'vue';
|
||||||
import { computed, defineComponent, ref } from "vue";
|
export default defineComponent({
|
||||||
export default defineComponent({
|
name: 'VueClock',
|
||||||
name: "clock",
|
data: () => ({
|
||||||
data: () => ({
|
timestamp: Date.now()
|
||||||
timestamp: Date.now(),
|
}),
|
||||||
}),
|
setup() {
|
||||||
setup() {
|
let timestamp = ref(Date.now());
|
||||||
let timestamp = ref(Date.now());
|
|
||||||
|
const computedDate = computed(() =>
|
||||||
const computedDate = computed(() => new Date(timestamp.value).toLocaleString("pl-PL", {
|
new Date(timestamp.value).toLocaleString('pl-PL', {
|
||||||
hour: "2-digit",
|
hour: '2-digit',
|
||||||
minute: "2-digit",
|
minute: '2-digit',
|
||||||
second: "2-digit",
|
second: '2-digit'
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
setInterval(() => (timestamp.value = Date.now()), 1000);
|
|
||||||
|
setInterval(() => (timestamp.value = Date.now()), 1000);
|
||||||
return { computedDate }
|
|
||||||
}
|
return { computedDate };
|
||||||
});
|
}
|
||||||
</script>
|
});
|
||||||
|
</script>
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import "../../styles/responsive.scss";
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
.clock {
|
|
||||||
display: flex;
|
.clock {
|
||||||
align-items: center;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
</style>
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="loading">{{message}}</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "@vue/runtime-core";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
props: ["message"],
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.loading {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
min-height: 100%;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
|
|
||||||
font-size: calc(0.75rem + 1vw);
|
|
||||||
|
|
||||||
color: #fdc62f;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -43,7 +43,13 @@
|
|||||||
<g v-if="greenBlinkLight" filter="url(#filter0_d_843_28)">
|
<g v-if="greenBlinkLight" filter="url(#filter0_d_843_28)">
|
||||||
<circle cx="15" cy="17" r="7" fill="#00FF0A" />
|
<circle cx="15" cy="17" r="7" fill="#00FF0A" />
|
||||||
|
|
||||||
<animate attributeType="XML" attributeName="opacity" values="1;0;1" dur="1s" repeatCount="indefinite" />
|
<animate
|
||||||
|
attributeType="XML"
|
||||||
|
attributeName="opacity"
|
||||||
|
values="1;0;1"
|
||||||
|
dur="1s"
|
||||||
|
repeatCount="indefinite"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g v-if="redTopLight" filter="url(#filter1_d_843_28)">
|
<g v-if="redTopLight" filter="url(#filter1_d_843_28)">
|
||||||
@@ -56,7 +62,13 @@
|
|||||||
<g v-if="redBottomLight" filter="url(#filter3_d_843_28)">
|
<g v-if="redBottomLight" filter="url(#filter3_d_843_28)">
|
||||||
<circle cx="15" cy="74" r="7" fill="#F40000" />
|
<circle cx="15" cy="74" r="7" fill="#F40000" />
|
||||||
|
|
||||||
<animate attributeType="XML" attributeName="opacity" values="1;0;1" dur="1s" repeatCount="indefinite" />
|
<animate
|
||||||
|
attributeType="XML"
|
||||||
|
attributeName="opacity"
|
||||||
|
values="1;0;1"
|
||||||
|
dur="1s"
|
||||||
|
repeatCount="indefinite"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
@@ -82,7 +94,12 @@
|
|||||||
<feComposite in2="hardAlpha" operator="out" />
|
<feComposite in2="hardAlpha" operator="out" />
|
||||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 1 0 0 0 0 0.04 0 0 0 1 0" />
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 1 0 0 0 0 0.04 0 0 0 1 0" />
|
||||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_843_28" result="shape" />
|
<feBlend
|
||||||
|
mode="normal"
|
||||||
|
in="SourceGraphic"
|
||||||
|
in2="effect1_dropShadow_843_28"
|
||||||
|
result="shape"
|
||||||
|
/>
|
||||||
</filter>
|
</filter>
|
||||||
<filter
|
<filter
|
||||||
id="filter1_d_843_28"
|
id="filter1_d_843_28"
|
||||||
@@ -104,7 +121,12 @@
|
|||||||
<feGaussianBlur stdDeviation="2.5" />
|
<feGaussianBlur stdDeviation="2.5" />
|
||||||
<feColorMatrix type="matrix" values="0 0 0 0 0.770833 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" />
|
<feColorMatrix type="matrix" values="0 0 0 0 0.770833 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" />
|
||||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_843_28" result="shape" />
|
<feBlend
|
||||||
|
mode="normal"
|
||||||
|
in="SourceGraphic"
|
||||||
|
in2="effect1_dropShadow_843_28"
|
||||||
|
result="shape"
|
||||||
|
/>
|
||||||
</filter>
|
</filter>
|
||||||
<filter
|
<filter
|
||||||
id="filter2_d_843_28"
|
id="filter2_d_843_28"
|
||||||
@@ -126,7 +148,12 @@
|
|||||||
<feGaussianBlur stdDeviation="2.5" />
|
<feGaussianBlur stdDeviation="2.5" />
|
||||||
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.72 0 0 0 0 0 0 0 0 1 0" />
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.72 0 0 0 0 0 0 0 0 1 0" />
|
||||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_843_28" result="shape" />
|
<feBlend
|
||||||
|
mode="normal"
|
||||||
|
in="SourceGraphic"
|
||||||
|
in2="effect1_dropShadow_843_28"
|
||||||
|
result="shape"
|
||||||
|
/>
|
||||||
</filter>
|
</filter>
|
||||||
<filter
|
<filter
|
||||||
id="filter3_d_843_28"
|
id="filter3_d_843_28"
|
||||||
@@ -148,7 +175,12 @@
|
|||||||
<feGaussianBlur stdDeviation="2.5" />
|
<feGaussianBlur stdDeviation="2.5" />
|
||||||
<feColorMatrix type="matrix" values="0 0 0 0 0.770833 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" />
|
<feColorMatrix type="matrix" values="0 0 0 0 0.770833 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" />
|
||||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_843_28" />
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_843_28" result="shape" />
|
<feBlend
|
||||||
|
mode="normal"
|
||||||
|
in="SourceGraphic"
|
||||||
|
in2="effect1_dropShadow_843_28"
|
||||||
|
result="shape"
|
||||||
|
/>
|
||||||
</filter>
|
</filter>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -161,29 +193,26 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
import { defineComponent } from 'vue';
|
||||||
import { StoreData } from '@/scripts/interfaces/StoreData';
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
import { useStore } from '@/store/store';
|
import { useStore } from '../../store/store';
|
||||||
import { StoreState } from '@/store/storeTypes';
|
import { StoreState } from '../../scripts/interfaces/store/storeTypes';
|
||||||
import { computed, defineComponent, watch } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
icons: {
|
|
||||||
statusIndicator: require('@/assets/signal-status-indicator.svg'),
|
|
||||||
},
|
|
||||||
tooltipActive: false,
|
tooltipActive: false,
|
||||||
indicator: {
|
indicator: {
|
||||||
|
offline: false,
|
||||||
status: DataStatus.Loading,
|
status: DataStatus.Loading,
|
||||||
message: 'data-status.S3',
|
message: 'data-status.S3'
|
||||||
},
|
},
|
||||||
|
|
||||||
greenLight: false,
|
greenLight: false,
|
||||||
greenBlinkLight: false,
|
greenBlinkLight: false,
|
||||||
redTopLight: false,
|
redTopLight: false,
|
||||||
orangeLight: false,
|
orangeLight: false,
|
||||||
redBottomLight: false,
|
redBottomLight: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -196,6 +225,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
dataStatus: store.dataStatuses,
|
dataStatus: store.dataStatuses,
|
||||||
|
store
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -209,6 +239,13 @@ export default defineComponent({
|
|||||||
const trainsDataStatus = statuses.trains;
|
const trainsDataStatus = statuses.trains;
|
||||||
const dispatcherDataStatus = statuses.dispatchers;
|
const dispatcherDataStatus = statuses.dispatchers;
|
||||||
|
|
||||||
|
if (this.store.isOffline) {
|
||||||
|
this.setSignalStatus(DataStatus.Initialized);
|
||||||
|
this.indicator.status = DataStatus.Initialized;
|
||||||
|
this.indicator.message = 'data-status.S1-offline';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (connectionStatus == DataStatus.Error) {
|
if (connectionStatus == DataStatus.Error) {
|
||||||
this.setSignalStatus(connectionStatus);
|
this.setSignalStatus(connectionStatus);
|
||||||
this.indicator.status = connectionStatus;
|
this.indicator.status = connectionStatus;
|
||||||
@@ -243,8 +280,8 @@ export default defineComponent({
|
|||||||
this.indicator.status = DataStatus.Loaded;
|
this.indicator.status = DataStatus.Loaded;
|
||||||
this.indicator.message = 'data-status.S2';
|
this.indicator.message = 'data-status.S2';
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -255,6 +292,10 @@ export default defineComponent({
|
|||||||
this.orangeLight = false;
|
this.orangeLight = false;
|
||||||
this.redBottomLight = false;
|
this.redBottomLight = false;
|
||||||
|
|
||||||
|
if (status == DataStatus.Initialized) {
|
||||||
|
this.redTopLight = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loaded) {
|
if (status == DataStatus.Loaded) {
|
||||||
this.greenLight = true;
|
this.greenLight = true;
|
||||||
}
|
}
|
||||||
@@ -271,8 +312,8 @@ export default defineComponent({
|
|||||||
if (status == DataStatus.Loading) {
|
if (status == DataStatus.Loading) {
|
||||||
this.greenBlinkLight = true;
|
this.greenBlinkLight = true;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -294,10 +335,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
.status-indicator {
|
.status-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
transform: translateX(12em);
|
right: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
|
transform: translateX(1.5em);
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator {
|
.indicator {
|
||||||
@@ -322,7 +364,7 @@ export default defineComponent({
|
|||||||
background-color: #171717;
|
background-color: #171717;
|
||||||
border-radius: 0.75em;
|
border-radius: 0.75em;
|
||||||
|
|
||||||
min-width: 13em;
|
width: 13em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: none;
|
overflow: none;
|
||||||
|
|
||||||
@@ -346,22 +388,16 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include midScreen() {
|
@include midScreen() {
|
||||||
left: 50%;
|
left: auto;
|
||||||
top: 100%;
|
right: 200%;
|
||||||
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
margin-left: 0;
|
|
||||||
margin-top: 0.75em;
|
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
border-left: 10px solid transparent;
|
|
||||||
border-right: 10px solid transparent;
|
border-right: 10px solid transparent;
|
||||||
border-bottom: 10px solid #171717;
|
border-left: 12px solid #171717;
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
|
||||||
top: 0;
|
transform: translate(100%, -50%);
|
||||||
left: 50%;
|
|
||||||
|
|
||||||
transform: translate(-50%, -100%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section
|
|
||||||
class="updates card"
|
|
||||||
v-if="cardOpen"
|
|
||||||
>
|
|
||||||
<h2>Ostatnie aktualizacje w Stacjowniku</h2>
|
|
||||||
<p>Tutaj będą pojawiać się informacje o kolejnych nowościach na stronie :)</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
v-for="(update, i) in updates"
|
|
||||||
:key="i"
|
|
||||||
>
|
|
||||||
<div>{{update.date}}</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
v-for="(line, l) in content"
|
|
||||||
:key="l"
|
|
||||||
>{{line}}</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { defineComponent } from "@vue/runtime-core";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
updates: {
|
|
||||||
date: "08/08/20",
|
|
||||||
content: [
|
|
||||||
"Lekko odświeżono wygląd strony, dodano nowy widok z pociągami online",
|
|
||||||
"Dodano animacje zmieniania widoków (zakładek)",
|
|
||||||
"Dodano przycisk zamykający kartę z filtrami",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
</style>
|
|
||||||
@@ -1,65 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<button class="action-btn">
|
<button class="action-btn btn--filled">
|
||||||
<div class="button_content">
|
<div class="button_content">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({});
|
export default defineComponent({});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../styles/variables";
|
@import '../../styles/variables';
|
||||||
@import "../../styles/responsive";
|
@import '../../styles/responsive';
|
||||||
|
|
||||||
.action-btn {
|
.button_content {
|
||||||
background: #333;
|
display: flex;
|
||||||
border: none;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
color: #bdbdbd;
|
}
|
||||||
|
</style>
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
padding: 0.35em 0.65em;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
transition: all 0.3s;
|
|
||||||
|
|
||||||
&.outlined {
|
|
||||||
border: 1px solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 1.25em;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: 0.35em;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 1em;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.open {
|
|
||||||
color: $accentCol;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
color: $accentCol;
|
|
||||||
background: #5c5c5c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button_content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="btn btn--option btn--load-data"
|
||||||
|
v-if="!scrollNoMoreData && scrollDataLoaded && list.length >= 15"
|
||||||
|
@click="addHistoryData"
|
||||||
|
>
|
||||||
|
{{ $t('journal.load-data') }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { PropType, defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
scrollNoMoreData: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollDataLoaded: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
|
||||||
|
list: {
|
||||||
|
type: Array as PropType<any[]>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['addHistoryData'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
addHistoryData() {
|
||||||
|
this.$emit('addHistoryData');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -12,7 +12,7 @@ import { defineComponent } from 'vue';
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
return {};
|
return {};
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ export default defineComponent({
|
|||||||
.loading {
|
.loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<span class="bar-bg"></span>
|
||||||
|
<span
|
||||||
|
class="bar-fg"
|
||||||
|
:style="{ width: `${~~progressPercent}%`, backgroundColor: bgColor }"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
progressPercent: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
progressType: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
bgColor() {
|
||||||
|
switch (this.progressType) {
|
||||||
|
case 'abandoned':
|
||||||
|
return 'salmon';
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 'springgreen';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.progress-bar {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
width: 6em;
|
||||||
|
height: 1em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
|
||||||
|
.bar-fg,
|
||||||
|
.bar-bg {
|
||||||
|
position: absolute;
|
||||||
|
height: 1em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-fg {
|
||||||
|
background-color: springgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-bg {
|
||||||
|
background-color: #5b5b5b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
<template>
|
||||||
|
<div class="region-dropdown" v-click-outside="clickedOutside">
|
||||||
|
<div class="content">
|
||||||
|
<button class="selected-region" @click="toggleBox">
|
||||||
|
<span>{{ selectedItem.name }}</span>
|
||||||
|
|
||||||
|
<img :src="`/images/icon-arrow-${listOpen ? 'asc' : 'desc'}.svg`" alt="Arrow icon" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ul class="options">
|
||||||
|
<li class="option" v-for="(item, i) in regionList" :key="item.id">
|
||||||
|
<transition
|
||||||
|
name="unfold"
|
||||||
|
:style="`
|
||||||
|
--delay-in: ${i * 55}ms;
|
||||||
|
--delay-out: ${(regionList.length - 1 - i) * 55}ms`"
|
||||||
|
>
|
||||||
|
<label :for="item.id" v-if="listOpen">
|
||||||
|
<input type="button" :id="item.id" name="select-box" @click="selectOption(item)" />
|
||||||
|
<span :style="selectedItem.id == item.id ? 'color: gold;' : ''" v-html="item.value">
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</transition>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, Ref, ref } from 'vue';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import { regions as regionsJSON } from '../../data/options.json';
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useStore(),
|
||||||
|
selectedItemIndex: 0,
|
||||||
|
listOpen: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
let buttonRef: Ref<HTMLButtonElement | null> = ref(null);
|
||||||
|
|
||||||
|
return {
|
||||||
|
buttonRef
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'store.region.id': {
|
||||||
|
handler(regionId) {
|
||||||
|
this.selectedItemIndex = this.regionList.findIndex((reg) => reg.id == regionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
selectedItem() {
|
||||||
|
return this.regionList[this.selectedItemIndex] || null;
|
||||||
|
},
|
||||||
|
regionList() {
|
||||||
|
return regionsJSON.map((region) => {
|
||||||
|
const regionStationCount =
|
||||||
|
this.store.apiData.stations?.filter(
|
||||||
|
(station) => station.region == region.id && station.isOnline
|
||||||
|
).length || 0;
|
||||||
|
|
||||||
|
const regionTrainCount =
|
||||||
|
this.store.apiData.trains?.filter((train) => train.region == region.id && train.online)
|
||||||
|
.length || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: region.id,
|
||||||
|
value: `${region.value} <div class='text--grayed'>${regionStationCount} / ${regionTrainCount}</div>`,
|
||||||
|
name: region.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
selectOption(selectedRegion: Item) {
|
||||||
|
this.store.region = selectedRegion;
|
||||||
|
this.listOpen = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleBox(e: Event) {
|
||||||
|
this.listOpen = !this.listOpen;
|
||||||
|
|
||||||
|
if (!this.listOpen) (e.target as HTMLButtonElement).blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
clickedOutside() {
|
||||||
|
this.listOpen = false;
|
||||||
|
this.buttonRef?.blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/variables.scss';
|
||||||
|
|
||||||
|
.region-dropdown {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
button img {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 1.35em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.selected-region {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: paleturquoise;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: #262626;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.options {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
z-index: 100;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.option {
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
&:focus + span {
|
||||||
|
color: $accentCol;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child label {
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #262626f2;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: #333333f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
padding: 0.5em 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unfold {
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px) scale(0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 110ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active {
|
||||||
|
transition-delay: var(--delay-in);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-active {
|
||||||
|
transition-delay: var(--delay-out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,39 +7,31 @@
|
|||||||
@keypress="updateValue"
|
@keypress="updateValue"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
<img class="search-exit" src="/images/icon-exit.svg" alt="exit-icon" @click="clearSearchValue" />
|
||||||
class="search-exit"
|
|
||||||
:src="exitIcon"
|
|
||||||
alt="exit-icon"
|
|
||||||
@click="clearValue"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch } from "vue";
|
import { defineComponent, ref, watch } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data: () => ({
|
emits: ['update:searchedValue', 'clearValue'],
|
||||||
exitIcon: require("@/assets/icon-exit.svg"),
|
|
||||||
}),
|
|
||||||
emits: ["update:searchedValue", "clearValue"],
|
|
||||||
props: {
|
props: {
|
||||||
searchedValue: {
|
searchedValue: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
updateOnInput: {
|
updateOnInput: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true
|
||||||
},
|
},
|
||||||
titleToTranslate: {
|
titleToTranslate: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
clearValue: {
|
clearValue: {
|
||||||
type: Function,
|
type: Function
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
@@ -49,32 +41,32 @@ export default defineComponent({
|
|||||||
watch(
|
watch(
|
||||||
() => compSearchedValue.value,
|
() => compSearchedValue.value,
|
||||||
(value) => {
|
(value) => {
|
||||||
emit("update:searchedValue", value);
|
emit('update:searchedValue', value);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearValue = () => {
|
const clearSearchValue = () => {
|
||||||
compSearchedValue.value = "";
|
compSearchedValue.value = '';
|
||||||
emit("clearValue");
|
emit('clearValue');
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateValue = (e) => {
|
const updateValue = (e: any) => {
|
||||||
if (!props.updateOnInput && e.keyCode == 13)
|
if (!props.updateOnInput && e.keyCode == 13)
|
||||||
emit("update:searchedValue", compSearchedValue.value);
|
emit('update:searchedValue', compSearchedValue.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
compSearchedValue,
|
compSearchedValue,
|
||||||
updateValue,
|
updateValue,
|
||||||
clearValue,
|
clearSearchValue
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "../../styles/responsive";
|
@import '../../styles/responsive';
|
||||||
|
|
||||||
.search {
|
.search {
|
||||||
&-box {
|
&-box {
|
||||||
@@ -109,4 +101,4 @@ export default defineComponent({
|
|||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,238 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="select-box" >
|
|
||||||
<div class="select-box_content">
|
|
||||||
<button class="selected" @click="toggleBox">
|
|
||||||
<span class="text--primary">{{ prefix }}</span>
|
|
||||||
<span>{{ computedSelectedItem.selectedValue || computedSelectedItem.value }}</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul class="options" :ref="(el) => (listRef = el as Element)">
|
|
||||||
<li class="option" v-for="(item, i) in itemList" :key="item.id">
|
|
||||||
<transition
|
|
||||||
name="unfold"
|
|
||||||
:style="`
|
|
||||||
--delay-in: ${i * 55}ms;
|
|
||||||
--delay-out: ${(itemList.length - 1 - i) * 55}ms`"
|
|
||||||
>
|
|
||||||
<label :for="item.id" v-if="listOpen">
|
|
||||||
<input type="button" :id="item.id" name="select-box" @click="selectOption(item)" />
|
|
||||||
<span :style="computedSelectedItem.id == item.id ? 'color: gold;' : ''" v-html="item.value"> </span>
|
|
||||||
</label>
|
|
||||||
</transition>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="arrow">
|
|
||||||
<img :src="listOpen ? ascIcon : descIcon" alt="arrow-icon" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, Ref, ref } from '@vue/runtime-core';
|
|
||||||
|
|
||||||
interface Item {
|
|
||||||
id: string;
|
|
||||||
value: string;
|
|
||||||
selectedValue?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
emits: ['selected'],
|
|
||||||
|
|
||||||
props: {
|
|
||||||
itemList: {
|
|
||||||
type: Array as () => Item[],
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
defaultItemIndex: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
prefix: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
data: () => ({
|
|
||||||
ascIcon: require('@/assets/icon-arrow-asc.svg'),
|
|
||||||
descIcon: require('@/assets/icon-arrow-desc.svg'),
|
|
||||||
}),
|
|
||||||
|
|
||||||
setup(props) {
|
|
||||||
let listRef: Ref<Element | null> = ref(null);
|
|
||||||
let buttonRef: Ref<HTMLButtonElement | null> = ref(null);
|
|
||||||
|
|
||||||
let activeEl: Ref<Element | null> = ref(document.activeElement);
|
|
||||||
|
|
||||||
let listOpen = ref(false);
|
|
||||||
let selectedItem: Ref<Item> = ref(props.itemList[props.defaultItemIndex]);
|
|
||||||
|
|
||||||
const computedSelectedItem = computed(() => {
|
|
||||||
return props.itemList.find((item) => item.id === selectedItem.value.id) || props.itemList[props.defaultItemIndex];
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
computedSelectedItem,
|
|
||||||
listOpen,
|
|
||||||
selectedItem,
|
|
||||||
listRef,
|
|
||||||
buttonRef,
|
|
||||||
activeEl,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
selectOption(item: Item) {
|
|
||||||
this.selectedItem = item;
|
|
||||||
this.listOpen = false;
|
|
||||||
|
|
||||||
this.$emit('selected', item);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleBox(e: Event) {
|
|
||||||
this.listOpen = !this.listOpen;
|
|
||||||
|
|
||||||
if (!this.listOpen) (e.target as HTMLButtonElement).blur();
|
|
||||||
},
|
|
||||||
|
|
||||||
clickedOutside() {
|
|
||||||
this.listOpen = false;
|
|
||||||
this.buttonRef?.blur();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
|
|
||||||
.unfold {
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px) scale(0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 110ms ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active {
|
|
||||||
transition-delay: var(--delay-in);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-leave-active {
|
|
||||||
transition-delay: var(--delay-out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-box {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0;
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 1.35em;
|
|
||||||
}
|
|
||||||
|
|
||||||
transform: translateY(-50%);
|
|
||||||
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.selected {
|
|
||||||
background: #333;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
font-size: 1em;
|
|
||||||
|
|
||||||
padding: 0.35em 0.5em;
|
|
||||||
margin-right: 1.4em;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background: #555;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-box_content {
|
|
||||||
position: relative;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.options {
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
height: auto;
|
|
||||||
|
|
||||||
z-index: 100;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.option {
|
|
||||||
input {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&:focus + span {
|
|
||||||
color: $accentCol;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child label {
|
|
||||||
border-radius: 0 0 1em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
background-color: hsla(0, 0%, 15%, 0.95);
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
background-color: hsla(0, 0%, 20%, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
padding: 0.5em 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,56 +1,90 @@
|
|||||||
$free: #8a8a8a;
|
<template>
|
||||||
$ending: #e6c300;
|
<span class="status-badge" :class="statusID" v-if="isOnline">
|
||||||
$no-limit: #117fc9;
|
{{ $t(`status.${statusID}`) }}
|
||||||
$unav: #ff3d5d;
|
{{ statusID == 'online' ? timestampToString(statusTimestamp!) : '' }}
|
||||||
$brb: #e6a100;
|
</span>
|
||||||
$no-space: #222;
|
|
||||||
$taken: #09a116;
|
<span class="status-badge free" v-else>
|
||||||
$unknown: rgb(185, 60, 60);
|
{{ $t('status.free') }}
|
||||||
|
</span>
|
||||||
.status-badge {
|
</template>
|
||||||
border-radius: 1rem;
|
|
||||||
font-weight: 500;
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
padding: 0.2em .55em;
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
|
||||||
background-color: $taken;
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
&.free {
|
statusID: {
|
||||||
background-color: $free;
|
type: String
|
||||||
font-size: 0.95em;
|
},
|
||||||
}
|
statusTimestamp: {
|
||||||
|
type: Number
|
||||||
&.ending {
|
},
|
||||||
background-color: $ending;
|
isOnline: {
|
||||||
color: black;
|
type: Boolean
|
||||||
font-size: 0.9em;
|
}
|
||||||
}
|
},
|
||||||
|
mixins: [dateMixin]
|
||||||
&.no-limit {
|
});
|
||||||
background-color: $no-limit;
|
</script>
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
<style lang="scss" scoped>
|
||||||
|
$free: #8a8a8a;
|
||||||
&.not-signed,
|
$ending: #e6c300;
|
||||||
&.unavailable {
|
$no-limit: #117fc9;
|
||||||
background-color: $unav;
|
$unav: #ff3d5d;
|
||||||
font-size: 0.85em;
|
$brb: #e6a100;
|
||||||
}
|
$no-space: #222;
|
||||||
|
$online: #09a116;
|
||||||
&.brb {
|
$unknown: rgb(185, 60, 60);
|
||||||
background-color: $brb;
|
|
||||||
color: black;
|
.status-badge {
|
||||||
font-size: 0.95em;
|
border-radius: 1rem;
|
||||||
}
|
font-weight: 500;
|
||||||
|
|
||||||
&.no-space {
|
padding: 0.2em 0.55em;
|
||||||
background-color: $no-space;
|
|
||||||
color: white;
|
background-color: $online;
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
&.free {
|
||||||
|
background-color: $free;
|
||||||
&.unknown {
|
font-size: 0.95em;
|
||||||
background-color: $unknown;
|
}
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
&.ending {
|
||||||
}
|
background-color: $ending;
|
||||||
|
color: black;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-limit {
|
||||||
|
background-color: $no-limit;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.not-signed,
|
||||||
|
&.unavailable {
|
||||||
|
background-color: $unav;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.brb {
|
||||||
|
background-color: $brb;
|
||||||
|
color: black;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-space {
|
||||||
|
background-color: $no-space;
|
||||||
|
border: 1px solid white;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unknown {
|
||||||
|
background-color: $unknown;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div class="stock-list">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(stockName, i) in trainStockList" :key="i">
|
||||||
|
<p>
|
||||||
|
{{ stockName.split(':')[0].split('_').splice(0, 2).join(' ') }}
|
||||||
|
{{ stockName.split(':')[1] }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<img
|
||||||
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stockName.split(':')[0]}${
|
||||||
|
/^EN/.test(stockName) ? 'rb' : ''
|
||||||
|
}.png`"
|
||||||
|
@error="onImageError($event, stockName)"
|
||||||
|
width="400"
|
||||||
|
height="60"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="/^(EN|2EN)/.test(stockName)"
|
||||||
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stockName.split(':')[0]}s.png`"
|
||||||
|
@error="
|
||||||
|
(event) => ((event.target as HTMLImageElement).src = '/images/icon-loco-ezt-s.png')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
class="train-thumbnail"
|
||||||
|
v-if="/^EN71/.test(stockName)"
|
||||||
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stockName.split(':')[0]}s.png`"
|
||||||
|
@error="
|
||||||
|
(event) => ((event.target as HTMLImageElement).src = '/images/icon-loco-ezt-s.png')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
class="train-thumbnail"
|
||||||
|
v-if="/^(EN|2EN)/.test(stockName)"
|
||||||
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stockName.split(':')[0]}ra.png`"
|
||||||
|
@error="
|
||||||
|
(event) => ((event.target as HTMLImageElement).src = '/images/icon-loco-ezt-ra.png')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { PropType, defineComponent } from 'vue';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import { RollingStockInfo } from '../../scripts/interfaces/github_api/StockInfoGithubData';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
trainStockList: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onImageError(event: Event, stockName: string) {
|
||||||
|
const fallbackName =
|
||||||
|
Object.keys(this.store.rollingStockData!.info).find((type) => {
|
||||||
|
return this.store.rollingStockData!.info[type as keyof RollingStockInfo].find(
|
||||||
|
(v) => v[0] === stockName.split(':')[0]
|
||||||
|
);
|
||||||
|
}) || 'vehicle-unknown';
|
||||||
|
|
||||||
|
(event.target as HTMLImageElement).src = `/images/icon-${fallbackName}.png`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.stock-list {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-list ul {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
overflow: auto;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul > li > span {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 60px;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: center;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,12 +4,12 @@
|
|||||||
class="date arrival"
|
class="date arrival"
|
||||||
v-if="!stop.beginsHere"
|
v-if="!stop.beginsHere"
|
||||||
:class="{
|
:class="{
|
||||||
delayed: stop.arrivalDelay > 0 && stop.confirmed,
|
delayed: stop.arrivalDelay > 0 && (stop.confirmed || stop.stopped),
|
||||||
preponed: stop.arrivalDelay < 0 && stop.confirmed,
|
preponed: stop.arrivalDelay < 0 && (stop.confirmed || stop.stopped),
|
||||||
'on-time': stop.arrivalDelay == 0 && stop.confirmed,
|
'on-time': stop.arrivalDelay == 0 && stop.confirmed
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<span v-if="stop.arrivalDelay != 0 && stop.confirmed">
|
<span v-if="stop.arrivalDelay != 0 && (stop.confirmed || stop.stopped)">
|
||||||
<s>{{ timestampToString(stop.arrivalTimestamp) }}</s>
|
<s>{{ timestampToString(stop.arrivalTimestamp) }}</s>
|
||||||
{{ timestampToString(stop.arrivalRealTimestamp) }}
|
{{ timestampToString(stop.arrivalRealTimestamp) }}
|
||||||
({{ stop.arrivalDelay > 0 ? '+' : '' }}{{ stop.arrivalDelay }})
|
({{ stop.arrivalDelay > 0 ? '+' : '' }}{{ stop.arrivalDelay }})
|
||||||
@@ -20,16 +20,20 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="date stop" v-if="stop.stopTime" :class="stop.stopType.replace(', ', '-')">
|
<span
|
||||||
|
class="date stop"
|
||||||
|
v-if="stop.stopTime || stop.stopped"
|
||||||
|
:class="stop.stopType.replace(', ', '-')"
|
||||||
|
>
|
||||||
{{ stop.stopTime }} {{ stop.stopType == '' ? 'pt' : stop.stopType }}
|
{{ stop.stopTime }} {{ stop.stopType == '' ? 'pt' : stop.stopType }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="date departure"
|
class="date departure"
|
||||||
v-if="!stop.terminatesHere && stop.stopTime != 0"
|
v-if="!stop.terminatesHere && (stop.stopTime != 0 || stop.stopped)"
|
||||||
:class="{
|
:class="{
|
||||||
delayed: stop.departureDelay > 0 && stop.confirmed,
|
delayed: stop.departureDelay > 0 && stop.confirmed,
|
||||||
preponed: stop.departureDelay < 0 && stop.confirmed,
|
preponed: stop.departureDelay < 0 && stop.confirmed
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<span v-if="stop.departureDelay != 0 && stop.confirmed">
|
<span v-if="stop.departureDelay != 0 && stop.confirmed">
|
||||||
@@ -47,9 +51,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import dateMixin from '@/mixins/dateMixin';
|
|
||||||
import TrainStop from '@/scripts/interfaces/TrainStop';
|
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
import TrainStop from '../../scripts/interfaces/TrainStop';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin],
|
||||||
@@ -57,13 +61,13 @@ export default defineComponent({
|
|||||||
props: {
|
props: {
|
||||||
stop: {
|
stop: {
|
||||||
type: Object as () => TrainStop,
|
type: Object as () => TrainStop,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
return {};
|
return {};
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<div class="train-modal" v-if="chosenTrain" @keydown.esc="closeModal">
|
||||||
|
<div class="modal_background" @click="closeModal"></div>
|
||||||
|
<div class="modal_content" ref="content" tabindex="0">
|
||||||
|
<button class="btn exit" @click="closeModal">
|
||||||
|
<img src="/images/icon-exit.svg" alt="close card" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<TrainInfo :train="chosenTrain" :extended="false" ref="trainInfo" />
|
||||||
|
<TrainSchedule :train="chosenTrain" tabindex="0" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||||
|
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
||||||
|
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: { TrainInfo, TrainSchedule },
|
||||||
|
mixins: [trainInfoMixin, modalTrainMixin],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isTopBarVisible: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
return {
|
||||||
|
store
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
const contentEl = this.$refs['content'] as HTMLElement;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
contentEl.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleContentScroll(e: Event) {
|
||||||
|
const trainInfoCompHeight: number = (
|
||||||
|
this.$refs['trainInfo'] as any
|
||||||
|
).$el.getBoundingClientRect().height;
|
||||||
|
|
||||||
|
const posTop = (e.target as HTMLElement).scrollTop;
|
||||||
|
this.isTopBarVisible = posTop > trainInfoCompHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
@import '../../styles/card.scss';
|
||||||
|
|
||||||
|
.top-info-bar-anim {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 150ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
transform: translate(-50%, -50%) scale(0.8);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.exit {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
margin: 0.5em 1em;
|
||||||
|
|
||||||
|
padding: 0.25em;
|
||||||
|
|
||||||
|
z-index: 201;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1.5rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.train-modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
z-index: 200;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_background {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background-color: rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_content {
|
||||||
|
position: relative;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
|
width: 95vw;
|
||||||
|
max-height: 96vh;
|
||||||
|
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
box-shadow: 0 0 15px 10px #0e0e0e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include midScreen {
|
||||||
|
.exit {
|
||||||
|
margin: 0.5em;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
.modal_content {
|
||||||
|
max-height: 85vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<img class="train-thumbnail" :src="placeholderUrl" v-if="isNotFound" />
|
||||||
|
|
||||||
|
<img
|
||||||
|
class="train-thumbnail"
|
||||||
|
v-else
|
||||||
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${name.split(':')[0]}${
|
||||||
|
stockType == 'loco-ezt' ? 'rb' : ''
|
||||||
|
}.png`"
|
||||||
|
@error="onImageError"
|
||||||
|
@load="onImageLoad"
|
||||||
|
width="220"
|
||||||
|
height="60"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import { RollingStockInfo } from '../../scripts/interfaces/github_api/StockInfoGithubData';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
|
||||||
|
onlyFirstSegment: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useStore(),
|
||||||
|
isNotFound: false,
|
||||||
|
isLoaded: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
url() {
|
||||||
|
return `https://rj.td2.info.pl/dist/img/thumbnails/${this.name.split(':')[0]}.png`;
|
||||||
|
},
|
||||||
|
|
||||||
|
placeholderUrl() {
|
||||||
|
return `/images/icon-${this.stockType}.png`;
|
||||||
|
},
|
||||||
|
|
||||||
|
stockType() {
|
||||||
|
if (!this.store.rollingStockData) return 'vehicle-unknown';
|
||||||
|
|
||||||
|
return (
|
||||||
|
Object.keys(this.store.rollingStockData.info).find((type) => {
|
||||||
|
return this.store.rollingStockData?.info[type as keyof RollingStockInfo].find(
|
||||||
|
(v) => v[0] === this.name.split(':')[0]
|
||||||
|
);
|
||||||
|
}) || 'vehicle-unknown'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onImageError() {
|
||||||
|
this.isNotFound = true;
|
||||||
|
this.isLoaded = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
onImageLoad() {
|
||||||
|
this.isNotFound = false;
|
||||||
|
this.isLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.train-thumbnail {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
<template>
|
||||||
|
<section class="daily-stats">
|
||||||
|
<span :data-active="statsStatus">
|
||||||
|
<b v-if="statsStatus == DataStatus.Loading">
|
||||||
|
{{ $t('app.loading') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<b v-else-if="stats.distanceSum == null">
|
||||||
|
{{ $t('journal.daily-stats-info') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<span class="stats-list" v-else>
|
||||||
|
<h3>
|
||||||
|
{{ $t('journal.daily-stats-title') }}
|
||||||
|
<b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b>
|
||||||
|
</h3>
|
||||||
|
<hr style="margin-bottom: 0.5em" />
|
||||||
|
|
||||||
|
<div v-if="stats.totalTimetables">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-total">
|
||||||
|
<template #count>
|
||||||
|
<b class="text--primary">
|
||||||
|
{{ stats.totalTimetables }}
|
||||||
|
{{ $t('journal.timetable-count', stats.totalTimetables) }}
|
||||||
|
</b>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.timetableId">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-longest">
|
||||||
|
<template #id>
|
||||||
|
<router-link :to="`/journal/timetables?timetableId=${stats.timetableId}`">
|
||||||
|
<b>{{ stats.timetableId }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #author>
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.timetableAuthor}`">
|
||||||
|
<b>{{ stats.timetableAuthor }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #driver>
|
||||||
|
<b class="text--primary">{{ stats.timetableDriver }}</b>
|
||||||
|
</template>
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary">{{ stats.timetableRouteDistance }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="topDispatchers.length == 1">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-most-active-dr">
|
||||||
|
<template #dispatcher>
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${topDispatchers[0].name}`">
|
||||||
|
<b>{{ topDispatchers[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #count>
|
||||||
|
<b class="text--primary">
|
||||||
|
{{ topDispatchers[0].count }}
|
||||||
|
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
|
||||||
|
</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="topDispatchers.length > 1">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-most-active-dr-many">
|
||||||
|
<template #dispatchers>
|
||||||
|
<span v-for="(disp, i) in topDispatchers" :key="i">
|
||||||
|
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
||||||
|
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${disp.name}`">
|
||||||
|
<b>{{ disp.name }}</b>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<span v-if="i < topDispatchers.length - 2">, </span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #count>
|
||||||
|
<b class="text--primary">
|
||||||
|
{{ topDispatchers[0].count }}
|
||||||
|
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
|
||||||
|
</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.longestDuties.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-longest-duties">
|
||||||
|
<template #dispatcher>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`"
|
||||||
|
>
|
||||||
|
<b>{{ stats.longestDuties[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #station>{{ stats.longestDuties[0].station }}</template>
|
||||||
|
|
||||||
|
<template #duration>
|
||||||
|
{{ calculateDuration(stats.longestDuties[0].duration) }}
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.mostActiveDrivers.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-most-active-driver">
|
||||||
|
<template #driver>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b>
|
||||||
|
</template>
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import axios from 'axios';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
|
import {
|
||||||
|
ITimetablesDailyStats,
|
||||||
|
ITimetablesDailyStatsResponse
|
||||||
|
} from '../../scripts/interfaces/api/StatsAPIData';
|
||||||
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
mixins: [dateMixin],
|
||||||
|
emits: ['toggleStatsOpen'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
DataStatus,
|
||||||
|
statsStatus: DataStatus.Loading,
|
||||||
|
intervalId: -1,
|
||||||
|
|
||||||
|
stats: {
|
||||||
|
totalTimetables: 0,
|
||||||
|
distanceSum: 0,
|
||||||
|
distanceAvg: 0,
|
||||||
|
timetableAuthor: '',
|
||||||
|
timetableDriver: '',
|
||||||
|
timetableId: 0,
|
||||||
|
timetableRouteDistance: 0,
|
||||||
|
longestDuties: [],
|
||||||
|
mostActiveDrivers: [],
|
||||||
|
mostActiveDispatchers: []
|
||||||
|
} as ITimetablesDailyStats
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
this.startFetchingDailyStats();
|
||||||
|
this.$emit('toggleStatsOpen', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivated() {
|
||||||
|
this.stopFetchingDailyStats();
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
topDispatchers() {
|
||||||
|
if (this.stats.mostActiveDispatchers.length == 0) return [];
|
||||||
|
const maxCount = this.stats.mostActiveDispatchers[0].count;
|
||||||
|
|
||||||
|
return this.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async fetchDailyTimetableStats() {
|
||||||
|
try {
|
||||||
|
const res: ITimetablesDailyStatsResponse = await (
|
||||||
|
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
||||||
|
).data;
|
||||||
|
|
||||||
|
this.stats = {
|
||||||
|
totalTimetables: res.totalTimetables,
|
||||||
|
distanceSum: res.distanceSum,
|
||||||
|
distanceAvg: res.distanceAvg,
|
||||||
|
timetableAuthor: res.maxTimetable?.authorName || '',
|
||||||
|
timetableDriver: res.maxTimetable?.driverName || '',
|
||||||
|
timetableId: res.maxTimetable?.id || 0,
|
||||||
|
timetableRouteDistance: res.maxTimetable?.routeDistance || 0,
|
||||||
|
|
||||||
|
mostActiveDispatchers: res.mostActiveDispatchers,
|
||||||
|
mostActiveDrivers: res.mostActiveDrivers,
|
||||||
|
longestDuties: res.longestDuties
|
||||||
|
};
|
||||||
|
|
||||||
|
this.statsStatus = DataStatus.Loaded;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
||||||
|
this.statsStatus = DataStatus.Error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startFetchingDailyStats() {
|
||||||
|
this.fetchDailyTimetableStats();
|
||||||
|
|
||||||
|
if (this.intervalId != -1) return;
|
||||||
|
|
||||||
|
this.intervalId = setInterval(this.fetchDailyTimetableStats, 60000);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopFetchingDailyStats() {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
this.intervalId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
|
.daily-stats {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.daily-stats > span[data-active='0'] {
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-list a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="stats_container" v-click-outside="() => (cardVisible = false)">
|
<div class="stats_container" v-click-outside="() => (cardVisible = false)">
|
||||||
<button class="stats_button btn btn--option" @click="toggleCard">
|
<button class="stats_button" @click="toggleCard">
|
||||||
Statystyki dyżurnego {{ store.dispatcherStatsName }}
|
Statystyki dyżurnego {{ store.dispatcherStatsName }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h3>STATYSTYKI WYSTAWIONYCH ROZKŁADÓW</h3>
|
<h3>STATYSTYKI WYSTAWIONYCH ROZKŁADÓW</h3>
|
||||||
|
|
||||||
<div class="info-stats" v-if="store.dispatcherStatsData._count._all">
|
<div class="info-stats" v-if="store.dispatcherStatsData._count._all">
|
||||||
<span class="stat-badge">
|
<span class="stat-badge">
|
||||||
<span>LICZBA</span>
|
<span>LICZBA</span>
|
||||||
@@ -35,8 +36,9 @@
|
|||||||
|
|
||||||
<h3>OSTATNIE WYSTAWIONE ROZKŁADY</h3>
|
<h3>OSTATNIE WYSTAWIONE ROZKŁADY</h3>
|
||||||
<div class="last-timetables">
|
<div class="last-timetables">
|
||||||
<div class="timetable-row" v-for="timetable in timetables">
|
<div class="timetable-row" v-for="timetable in timetables" :key="timetable.id">
|
||||||
#{{ timetable.timetableId }} | <b>{{ timetable.trainCategoryCode }} {{ timetable.trainNo }}</b> |
|
#{{ timetable.timetableId }} |
|
||||||
|
<b>{{ timetable.trainCategoryCode }} {{ timetable.trainNo }}</b> |
|
||||||
{{ timetable.driverName }} ({{ timetable.routeDistance }}km)
|
{{ timetable.driverName }} ({{ timetable.routeDistance }}km)
|
||||||
<div>{{ timetable.route.replace('|', ' > ') }}</div>
|
<div>{{ timetable.route.replace('|', ' > ') }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,12 +50,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DispatcherStatsAPIData } from '@/scripts/interfaces/api/DispatcherStatsAPIData';
|
|
||||||
import { TimetableHistory } from '@/scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
import { URLs } from '@/scripts/utils/apiURLs';
|
|
||||||
import { useStore } from '@/store/store';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { computed, defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import { DispatcherStatsAPIData } from '../../scripts/interfaces/api/DispatcherStatsAPIData';
|
||||||
|
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||||
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -62,15 +64,8 @@ export default defineComponent({
|
|||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
const statsData2 = computed(async () => {
|
|
||||||
return await (
|
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getDispatcherInfo?name=${store.dispatcherStatsName}`)
|
|
||||||
).data;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
store,
|
store
|
||||||
statsData2,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -78,7 +73,7 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
cardVisible: false,
|
cardVisible: false,
|
||||||
lastDispatcherName: '',
|
lastDispatcherName: '',
|
||||||
timetables: [] as TimetableHistory[],
|
timetables: [] as TimetableHistory[]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -96,18 +91,22 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const statsData: DispatcherStatsAPIData = await (
|
const statsData: DispatcherStatsAPIData = await (
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getDispatcherInfo?name=${this.store.dispatcherStatsName}`)
|
await axios.get(
|
||||||
|
`${URLs.stacjownikAPI}/api/getDispatcherInfo?name=${this.store.dispatcherStatsName}`
|
||||||
|
)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
const timetables: TimetableHistory[] = await (
|
const timetables: TimetableHistory[] = await (
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getTimetables?authorName=${this.store.dispatcherStatsName}`)
|
await axios.get(
|
||||||
|
`${URLs.stacjownikAPI}/api/getTimetables?authorName=${this.store.dispatcherStatsName}`
|
||||||
|
)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
this.timetables = timetables;
|
this.timetables = timetables;
|
||||||
this.store.dispatcherStatsData = statsData;
|
this.store.dispatcherStatsData = statsData;
|
||||||
this.lastDispatcherName = this.store.dispatcherStatsName;
|
this.lastDispatcherName = this.store.dispatcherStatsName;
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -161,42 +160,7 @@ h3 {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-stats {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.last-timetables {
|
.last-timetables {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-badge {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding-bottom: 1em;
|
|
||||||
|
|
||||||
span {
|
|
||||||
padding: 0.25em 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
span:first-child {
|
|
||||||
background-color: #4d4d4d;
|
|
||||||
}
|
|
||||||
|
|
||||||
span:last-child {
|
|
||||||
background-color: $accentCol;
|
|
||||||
color: black;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
.stats_card {
|
|
||||||
text-align: center;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
border-radius: 0 0 1em 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||